Commit a664bdef authored by Vitja Makarov's avatar Vitja Makarov

Merge remote branch 'upstream/master'

parents d5c80a3d 7cdfd770
......@@ -2021,6 +2021,13 @@ class IndexNode(ExprNode):
def is_ephemeral(self):
return self.base.is_ephemeral()
def is_simple(self):
if self.is_buffer_access:
return False
base = self.base
return (base.is_simple() and self.index.is_simple()
and base.type and (base.type.is_ptr or base.type.is_array))
def analyse_target_declaration(self, env):
pass
......@@ -2966,25 +2973,50 @@ class SimpleCallNode(CallNode):
self.is_temp = 1
# Coerce arguments
some_args_in_temps = False
for i in range(min(max_nargs, actual_nargs)):
for i in xrange(min(max_nargs, actual_nargs)):
formal_type = func_type.args[i].type
arg = self.args[i].coerce_to(formal_type, env).coerce_to_simple(env)
arg = self.args[i].coerce_to(formal_type, env)
if arg.is_temp:
if i > 0:
# first argument in temp doesn't impact subsequent arguments
some_args_in_temps = True
elif arg.type.is_pyobject and not env.nogil:
if not arg.is_name or arg.entry and (not arg.entry.is_local or arg.entry.in_closure):
if i == 0 and self.self is not None:
# a method's cloned "self" argument is ok
pass
elif arg.is_name and arg.entry and arg.entry.is_local and not arg.entry.in_closure:
# plain local variables are ok
pass
else:
# we do not safely own the argument's reference,
# but we must make sure it cannot be collected
# before we return from the function, so we create
# an owned temp reference to it
if i > 0: # first argument doesn't matter
some_args_in_temps = True
arg = arg.coerce_to_temp(env)
self.args[i] = arg
# handle additional varargs parameters
for i in xrange(max_nargs, actual_nargs):
arg = self.args[i]
if arg.type.is_pyobject:
arg_ctype = arg.type.default_coerced_ctype()
if arg_ctype is None:
error(self.args[i].pos,
"Python object cannot be passed as a varargs parameter")
else:
self.args[i] = arg = arg.coerce_to(arg_ctype, env)
if arg.is_temp and i > 0:
some_args_in_temps = True
if some_args_in_temps:
# if some args are temps and others are not, they may get
# constructed in the wrong order (temps first) => make
# sure they are either all temps or all not temps
for i in range(min(max_nargs, actual_nargs)-1):
# sure they are either all temps or all not temps (except
# for the last argument, which is evaluated last in any
# case)
for i in xrange(actual_nargs-1):
if i == 0 and self.self is not None:
continue # self is ok
arg = self.args[i]
if arg.is_name and arg.entry and (
(arg.entry.is_local and not arg.entry.in_closure)
......@@ -2998,15 +3030,6 @@ class SimpleCallNode(CallNode):
pass
else:
self.args[i] = arg.coerce_to_temp(env)
for i in range(max_nargs, actual_nargs):
arg = self.args[i]
if arg.type.is_pyobject:
arg_ctype = arg.type.default_coerced_ctype()
if arg_ctype is None:
error(self.args[i].pos,
"Python object cannot be passed as a varargs parameter")
else:
self.args[i] = arg.coerce_to(arg_ctype, env)
# Calc result type and code fragment
if isinstance(self.function, NewExprNode):
self.type = PyrexTypes.CPtrType(self.function.class_type)
......@@ -5447,6 +5470,10 @@ class TypecastNode(ExprNode):
elif self.type.is_complex and self.operand.type.is_complex:
self.operand = self.operand.coerce_to_simple(env)
def is_simple(self):
# either temp or a C cast => no side effects
return True
def nogil_check(self, env):
if self.type and self.type.is_pyobject and self.is_temp:
self.gil_error()
......@@ -7103,6 +7130,9 @@ class PyTypeTestNode(CoercionNode):
return False
return self.arg.may_be_none()
def is_simple(self):
return self.arg.is_simple()
def result_in_temp(self):
return self.arg.result_in_temp()
......@@ -7153,6 +7183,9 @@ class NoneCheckNode(CoercionNode):
def may_be_none(self):
return False
def is_simple(self):
return self.arg.is_simple()
def result_in_temp(self):
return self.arg.result_in_temp()
......@@ -7453,6 +7486,9 @@ class CloneNode(CoercionNode):
if hasattr(self.arg, 'entry'):
self.entry = self.arg.entry
def is_simple(self):
return True # result is always in a temp (or a name)
def generate_evaluation_code(self, code):
pass
......
......@@ -607,9 +607,6 @@ class CFuncDeclaratorNode(CDeclaratorNode):
error(self.exception_value.pos,
"Exception value incompatible with function return type")
exc_check = self.exception_check
if return_type.is_array:
error(self.pos,
"Function cannot return an array")
if return_type.is_cfunction:
error(self.pos,
"Function cannot return a function")
......@@ -1658,6 +1655,9 @@ class CFuncDefNode(FuncDefNode):
api = self.api, modifiers = self.modifiers)
self.entry.inline_func_in_pxd = self.inline_in_pxd
self.return_type = type.return_type
if self.return_type.is_array and visibility != 'extern':
error(self.pos,
"Function cannot return an array")
if self.overridable and not env.is_module_scope:
if len(self.args) < 1 or not self.args[0].type.is_pyobject:
......
......@@ -1995,14 +1995,15 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
builtin_type = entry.type
if builtin_type and builtin_type is not Builtin.type_type:
type_check_function = entry.type.type_check_function(exact=False)
if type_check_function in tests:
continue
tests.append(type_check_function)
type_check_args = [arg]
elif test_type_node.type is Builtin.type_type:
type_check_function = '__Pyx_TypeCheck'
type_check_args = [arg, test_type_node]
else:
return node
if type_check_function not in tests:
tests.append(type_check_function)
test_nodes.append(
ExprNodes.PythonCapiCallNode(
test_type_node.pos, type_check_function, self.Py_type_check_func_type,
......
......@@ -29,6 +29,49 @@ with open(codefile) as f:
# can't access the module anymore. Get it from sys.modules instead.
build_ext = sys.modules['Cython.Distutils.build_ext']
have_gdb = None
def test_gdb():
global have_gdb
if have_gdb is None:
try:
p = subprocess.Popen(['gdb', '-v'], stdout=subprocess.PIPE)
have_gdb = True
except OSError:
# gdb was not installed
have_gdb = False
else:
gdb_version = p.stdout.read().decode('ascii')
p.wait()
p.stdout.close()
if have_gdb:
# Based on Lib/test/test_gdb.py
regex = "^GNU gdb [^\d]*(\d+)\.(\d+)"
gdb_version_number = list(map(int, re.search(regex, gdb_version).groups()))
if gdb_version_number >= [7, 2]:
python_version_script = tempfile.NamedTemporaryFile(mode='w+')
python_version_script.write(
'python import sys; print("%s %s" % sys.version_info[:2])')
python_version_script.flush()
p = subprocess.Popen(['gdb', '-batch', '-x', python_version_script.name],
stdout=subprocess.PIPE)
python_version = p.stdout.read().decode('ascii')
p.wait()
python_version_number = list(map(int, python_version.split()))
# Be Python 3 compatible
if (not have_gdb
or gdb_version_number < [7, 2]
or python_version_number < [2, 6]):
warnings.warn(
'Skipping gdb tests, need gdb >= 7.2 with Python >= 2.6')
have_gdb = False
return have_gdb
class DebuggerTestCase(unittest.TestCase):
def setUp(self):
......@@ -36,6 +79,9 @@ class DebuggerTestCase(unittest.TestCase):
Run gdb and have cygdb import the debug information from the code
defined in TestParseTreeTransforms's setUp method
"""
if not test_gdb():
return
self.tempdir = tempfile.mkdtemp()
self.destfile = os.path.join(self.tempdir, 'codefile.pyx')
self.debug_dest = os.path.join(self.tempdir,
......@@ -44,6 +90,7 @@ class DebuggerTestCase(unittest.TestCase):
self.cfuncs_destfile = os.path.join(self.tempdir, 'cfuncs')
self.cwd = os.getcwd()
try:
os.chdir(self.tempdir)
shutil.copy(codefile, self.destfile)
......@@ -58,7 +105,6 @@ class DebuggerTestCase(unittest.TestCase):
)
optimization_disabler = build_ext.Optimization()
optimization_disabler.disable_optimization()
cython_compile_testcase = runtests.CythonCompileTestCase(
workdir=self.tempdir,
......@@ -67,6 +113,14 @@ class DebuggerTestCase(unittest.TestCase):
**opts
)
new_stderr = open(os.devnull, 'w')
stderr = sys.stderr
sys.stderr = new_stderr
optimization_disabler.disable_optimization()
try:
cython_compile_testcase.run_cython(
targetdir=self.tempdir,
incdir=None,
......@@ -84,8 +138,9 @@ class DebuggerTestCase(unittest.TestCase):
extra_extension_args={'extra_objects':['cfuncs.o']},
**opts
)
finally:
optimization_disabler.restore_state()
sys.stderr = stderr
# ext = Cython.Distutils.extension.Extension(
# 'codefile',
......@@ -99,7 +154,13 @@ class DebuggerTestCase(unittest.TestCase):
# cmdclass=dict(build_ext=Cython.Distutils.build_ext)
# )
except:
os.chdir(self.cwd)
raise
def tearDown(self):
if not test_gdb():
return
os.chdir(self.cwd)
shutil.rmtree(self.tempdir)
......@@ -107,6 +168,9 @@ class DebuggerTestCase(unittest.TestCase):
class GdbDebuggerTestCase(DebuggerTestCase):
def setUp(self):
if not test_gdb():
return
super(GdbDebuggerTestCase, self).setUp()
prefix_code = textwrap.dedent('''\
......@@ -167,6 +231,11 @@ class GdbDebuggerTestCase(DebuggerTestCase):
p.stdout.close()
if have_gdb:
# Based on Lib/test/test_gdb.py
regex = "^GNU gdb [^\d]*(\d+)\.(\d+)"
gdb_version_number = list(map(int, re.search(regex, gdb_version).groups()))
if gdb_version_number >= [7, 2]:
python_version_script = tempfile.NamedTemporaryFile(mode='w+')
python_version_script.write(
'python import sys; print("%s %s" % sys.version_info[:2])')
......@@ -175,16 +244,12 @@ class GdbDebuggerTestCase(DebuggerTestCase):
stdout=subprocess.PIPE)
python_version = p.stdout.read().decode('ascii')
p.wait()
python_version_number = [int(a) for a in python_version.split()]
python_version_number = list(map(int, python_version.split()))
if have_gdb:
# Based on Lib/test/test_gdb.py
regex = "^GNU gdb [^\d]*(\d+)\.(\d+)"
gdb_version_number = re.search(regex, gdb_version).groups()
# Be Python 3 compatible
if (not have_gdb
or list(map(int, gdb_version_number)) < [7, 2]
or gdb_version_number < [7, 2]
or python_version_number < [2, 6]):
self.p = None
warnings.warn(
......@@ -197,6 +262,9 @@ class GdbDebuggerTestCase(DebuggerTestCase):
env=env)
def tearDown(self):
if not test_gdb():
return
super(GdbDebuggerTestCase, self).tearDown()
if self.p:
self.p.stderr.close()
......@@ -207,17 +275,24 @@ class GdbDebuggerTestCase(DebuggerTestCase):
class TestAll(GdbDebuggerTestCase):
def test_all(self):
if self.p is None:
if not test_gdb():
return
out, err = self.p.communicate()
err = err.decode('UTF-8')
exit_status = self.p.wait()
if exit_status == 1:
sys.stderr.write(err)
elif exit_status >= 2:
border = '*' * 30
start = '%s v INSIDE GDB v %s' % (border, border)
end = '%s ^ INSIDE GDB ^ %s' % (border, border)
errmsg = '\n%s\n%s%s' % (start, err, end)
self.assertEquals(0, self.p.wait(), errmsg)
sys.stderr.write(err)
sys.stderr.write(errmsg)
if __name__ == '__main__':
unittest.main()
......@@ -428,7 +428,7 @@ def run_unittest_in_module(modulename):
"debugging information. Either compile python with "
"-g or get a debug build (configure with --with-pydebug).")
warnings.warn(msg)
os._exit(0)
os._exit(1)
else:
m = __import__(modulename, fromlist=[''])
tests = inspect.getmembers(m, inspect.isclass)
......@@ -453,7 +453,7 @@ def runtests():
success_libpython = run_unittest_in_module(test_libpython_in_gdb.__name__)
if not success_libcython or not success_libpython:
sys.exit(1)
sys.exit(2)
def main(version, trace_code=False):
global inferior_python_version
......
......@@ -194,7 +194,7 @@ class _XMLTestResult(_TextTestResult):
module = ''
testcase_name = module + testcase.__name__
if not tests_by_testcase.has_key(testcase_name):
if testcase_name not in tests_by_testcase:
tests_by_testcase[testcase_name] = []
tests_by_testcase[testcase_name].append(test_info)
......
__version__ = "0.14.1rc2"
__version__ = "0.14.1rc3"
# Void cython.* directives (for case insensitive operating systems).
from Cython.Shadow import *
......@@ -26,6 +26,18 @@ try:
except ImportError: # No threads, no problems
threading = None
if sys.platform == 'win32':
# TODO: Figure out why this hackery (see http://thread.gmane.org/gmane.comp.python.cython.devel/8280/).
config_files = distutils_distro.find_config_files()
try: config_files.remove('setup.cfg')
except ValueError: pass
distutils_distro.parse_config_files(config_files)
cfgfiles = distutils_distro.find_config_files()
try: cfgfiles.remove('setup.cfg')
except ValueError: pass
distutils_distro.parse_config_files(cfgfiles)
WITH_CYTHON = True
......@@ -981,6 +993,9 @@ def check_thread_termination(ignore_seen=True):
raise PendingThreadsError("left-over threads found after running test")
def main():
DISTDIR = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]))
from optparse import OptionParser
parser = OptionParser()
parser.add_option("--no-cleanup", dest="cleanup_workdir",
......@@ -1051,12 +1066,15 @@ def main():
parser.add_option("--exit-ok", dest="exit_ok", default=False,
action="store_true",
help="exit without error code even on test failures")
parser.add_option("--root-dir", dest="root_dir", default=os.path.join(DISTDIR, 'tests'),
help="working directory")
parser.add_option("--work-dir", dest="work_dir", default=os.path.join(os.getcwd(), 'BUILD'),
help="working directory")
options, cmd_args = parser.parse_args()
DISTDIR = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]))
ROOTDIR = os.path.join(DISTDIR, 'tests')
WORKDIR = os.path.join(os.getcwd(), 'BUILD')
ROOTDIR = os.path.abspath(options.root_dir)
WORKDIR = os.path.abspath(options.work_dir)
if sys.version_info[0] >= 3:
options.doctests = False
......@@ -1167,7 +1185,7 @@ def main():
exclude_selectors += [ re.compile(r, re.I|re.U).search for r in options.exclude ]
if not test_bugs:
exclude_selectors += [ FileListExcluder("tests/bugs.txt") ]
exclude_selectors += [ FileListExcluder(os.path.join(ROOTDIR, "bugs.txt")) ]
if sys.platform in ['win32', 'cygwin'] and sys.version_info < (2,6):
exclude_selectors += [ lambda x: x == "run.specialfloat" ]
......
......@@ -77,6 +77,23 @@ def test_custom():
assert isinstance(A(), A)
return True
cdef class B:
pass
cdef class C:
pass
def test_custom_tuple(obj):
"""
>>> test_custom_tuple(A())
True
>>> test_custom_tuple(B())
True
>>> test_custom_tuple(C())
False
"""
return isinstance(obj, (A,B))
def test_nested(x):
"""
>>> test_nested(1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment