Commit 719f7569 authored by Vitja Makarov's avatar Vitja Makarov

Merge remote branch 'upstream/master'

parents e7f05c6c 1f735bf4
This diff is collapsed.
...@@ -607,9 +607,6 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -607,9 +607,6 @@ class CFuncDeclaratorNode(CDeclaratorNode):
error(self.exception_value.pos, error(self.exception_value.pos,
"Exception value incompatible with function return type") "Exception value incompatible with function return type")
exc_check = self.exception_check exc_check = self.exception_check
if return_type.is_array:
error(self.pos,
"Function cannot return an array")
if return_type.is_cfunction: if return_type.is_cfunction:
error(self.pos, error(self.pos,
"Function cannot return a function") "Function cannot return a function")
...@@ -1658,6 +1655,9 @@ class CFuncDefNode(FuncDefNode): ...@@ -1658,6 +1655,9 @@ class CFuncDefNode(FuncDefNode):
api = self.api, modifiers = self.modifiers) api = self.api, modifiers = self.modifiers)
self.entry.inline_func_in_pxd = self.inline_in_pxd self.entry.inline_func_in_pxd = self.inline_in_pxd
self.return_type = type.return_type 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 self.overridable and not env.is_module_scope:
if len(self.args) < 1 or not self.args[0].type.is_pyobject: if len(self.args) < 1 or not self.args[0].type.is_pyobject:
......
...@@ -1937,7 +1937,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1937,7 +1937,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
node.pos, cfunc_name, self.PyObject_Size_func_type, node.pos, cfunc_name, self.PyObject_Size_func_type,
args = [arg], args = [arg],
is_temp = node.is_temp) is_temp = node.is_temp)
elif arg.type is PyrexTypes.c_py_unicode_type: elif arg.type.is_unicode_char:
return ExprNodes.IntNode(node.pos, value='1', constant_result=1, return ExprNodes.IntNode(node.pos, value='1', constant_result=1,
type=node.type) type=node.type)
else: else:
...@@ -1995,20 +1995,21 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1995,20 +1995,21 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
builtin_type = entry.type builtin_type = entry.type
if builtin_type and builtin_type is not Builtin.type_type: if builtin_type and builtin_type is not Builtin.type_type:
type_check_function = entry.type.type_check_function(exact=False) 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] type_check_args = [arg]
elif test_type_node.type is Builtin.type_type: elif test_type_node.type is Builtin.type_type:
type_check_function = '__Pyx_TypeCheck' type_check_function = '__Pyx_TypeCheck'
type_check_args = [arg, test_type_node] type_check_args = [arg, test_type_node]
else: else:
return node return node
if type_check_function not in tests: test_nodes.append(
tests.append(type_check_function) ExprNodes.PythonCapiCallNode(
test_nodes.append( test_type_node.pos, type_check_function, self.Py_type_check_func_type,
ExprNodes.PythonCapiCallNode( args = type_check_args,
test_type_node.pos, type_check_function, self.Py_type_check_func_type, is_temp = True,
args = type_check_args, ))
is_temp = True,
))
def join_with_or(a,b, make_binop_node=ExprNodes.binop_node): def join_with_or(a,b, make_binop_node=ExprNodes.binop_node):
or_node = make_binop_node(node.pos, 'or', a, b) or_node = make_binop_node(node.pos, 'or', a, b)
...@@ -2028,7 +2029,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -2028,7 +2029,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return node return node
arg = pos_args[0] arg = pos_args[0]
if isinstance(arg, ExprNodes.CoerceToPyTypeNode): if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
if arg.arg.type is PyrexTypes.c_py_unicode_type: if arg.arg.type.is_unicode_char:
return arg.arg.coerce_to(node.type, self.current_env()) return arg.arg.coerce_to(node.type, self.current_env())
return node return node
...@@ -2191,7 +2192,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -2191,7 +2192,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return node return node
ustring = args[0] ustring = args[0]
if not isinstance(ustring, ExprNodes.CoerceToPyTypeNode) or \ if not isinstance(ustring, ExprNodes.CoerceToPyTypeNode) or \
ustring.arg.type is not PyrexTypes.c_py_unicode_type: not ustring.arg.type.is_unicode_char:
return node return node
uchar = ustring.arg uchar = ustring.arg
method_name = node.function.attribute method_name = node.function.attribute
...@@ -2230,7 +2231,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -2230,7 +2231,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return node return node
ustring = args[0] ustring = args[0]
if not isinstance(ustring, ExprNodes.CoerceToPyTypeNode) or \ if not isinstance(ustring, ExprNodes.CoerceToPyTypeNode) or \
ustring.arg.type is not PyrexTypes.c_py_unicode_type: not ustring.arg.type.is_unicode_char:
return node return node
uchar = ustring.arg uchar = ustring.arg
method_name = node.function.attribute method_name = node.function.attribute
......
...@@ -2049,6 +2049,7 @@ basic_c_type_names = ("void", "char", "int", "float", "double", "bint") ...@@ -2049,6 +2049,7 @@ basic_c_type_names = ("void", "char", "int", "float", "double", "bint")
special_basic_c_types = { special_basic_c_types = {
# name : (signed, longness) # name : (signed, longness)
"Py_UNICODE" : (0, 0), "Py_UNICODE" : (0, 0),
"Py_UCS4" : (0, 0),
"Py_ssize_t" : (2, 0), "Py_ssize_t" : (2, 0),
"ssize_t" : (2, 0), "ssize_t" : (2, 0),
"size_t" : (0, 0), "size_t" : (0, 0),
......
...@@ -49,6 +49,7 @@ class PyrexType(BaseType): ...@@ -49,6 +49,7 @@ class PyrexType(BaseType):
# is_typedef boolean Is a typedef type # is_typedef boolean Is a typedef type
# is_string boolean Is a C char * type # is_string boolean Is a C char * type
# is_unicode boolean Is a UTF-8 encoded C char * type # is_unicode boolean Is a UTF-8 encoded C char * type
# is_unicode_char boolean Is either Py_UCS4 or Py_UNICODE
# is_returncode boolean Is used only to signal exceptions # is_returncode boolean Is used only to signal exceptions
# is_error boolean Is the dummy error type # is_error boolean Is the dummy error type
# is_buffer boolean Is buffer access type # is_buffer boolean Is buffer access type
...@@ -101,6 +102,7 @@ class PyrexType(BaseType): ...@@ -101,6 +102,7 @@ class PyrexType(BaseType):
is_typedef = 0 is_typedef = 0
is_string = 0 is_string = 0
is_unicode = 0 is_unicode = 0
is_unicode_char = 0
is_returncode = 0 is_returncode = 0
is_error = 0 is_error = 0
is_buffer = 0 is_buffer = 0
...@@ -924,9 +926,81 @@ class CBIntType(CIntType): ...@@ -924,9 +926,81 @@ class CBIntType(CIntType):
return "<CNumericType bint>" return "<CNumericType bint>"
class CPyUCS4IntType(CIntType):
# Py_UCS4
is_unicode_char = True
# Py_UCS4 coerces from and to single character unicode strings (or
# at most two characters on 16bit Unicode builds), but we also
# allow Python integers as input. The value range for Py_UCS4
# is 0..1114111, which is checked when converting from an integer
# value.
to_py_function = "PyUnicode_FromOrdinal"
from_py_function = "__Pyx_PyObject_AsPy_UCS4"
def create_from_py_utility_code(self, env):
env.use_utility_code(pyobject_as_py_ucs4_utility_code)
return True
def sign_and_name(self):
return "Py_UCS4"
pyobject_as_py_ucs4_utility_code = UtilityCode(
proto='''
static CYTHON_INLINE Py_UCS4 __Pyx_PyObject_AsPy_UCS4(PyObject*);
''',
impl='''
static CYTHON_INLINE Py_UCS4 __Pyx_PyObject_AsPy_UCS4(PyObject* x) {
long ival;
if (PyUnicode_Check(x)) {
if (likely(PyUnicode_GET_SIZE(x) == 1)) {
return PyUnicode_AS_UNICODE(x)[0];
}
#if Py_UNICODE_SIZE == 2
else if (PyUnicode_GET_SIZE(x) == 2) {
Py_UCS4 high_val = PyUnicode_AS_UNICODE(x)[0];
if (high_val >= 0xD800 && high_val <= 0xDBFF) {
Py_UCS4 low_val = PyUnicode_AS_UNICODE(x)[1];
if (low_val >= 0xDC00 && low_val <= 0xDFFF) {
return 0x10000 | ((high_val & ((1<<10)-1)) << 10) | (low_val & ((1<<10)-1));
}
}
}
#endif
PyErr_Format(PyExc_ValueError,
"only single character unicode strings can be converted to Py_UCS4, got length "
#if PY_VERSION_HEX < 0x02050000
"%d",
#else
"%zd",
#endif
PyUnicode_GET_SIZE(x));
return (Py_UCS4)-1;
}
ival = __Pyx_PyInt_AsLong(x);
if (unlikely(ival < 0)) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_OverflowError,
"cannot convert negative value to Py_UCS4");
return (Py_UCS4)-1;
} else if (unlikely(ival > 1114111)) {
PyErr_SetString(PyExc_OverflowError,
"value too large to convert to Py_UCS4");
return (Py_UCS4)-1;
}
return (Py_UCS4)ival;
}
''')
class CPyUnicodeIntType(CIntType): class CPyUnicodeIntType(CIntType):
# Py_UNICODE # Py_UNICODE
is_unicode_char = True
# Py_UNICODE coerces from and to single character unicode strings, # Py_UNICODE coerces from and to single character unicode strings,
# but we also allow Python integers as input. The value range for # but we also allow Python integers as input. The value range for
# Py_UNICODE is 0..1114111, which is checked when converting from # Py_UNICODE is 0..1114111, which is checked when converting from
...@@ -2306,6 +2380,7 @@ c_anon_enum_type = CAnonEnumType(-1) ...@@ -2306,6 +2380,7 @@ c_anon_enum_type = CAnonEnumType(-1)
c_returncode_type = CReturnCodeType(RANK_INT) c_returncode_type = CReturnCodeType(RANK_INT)
c_bint_type = CBIntType(RANK_INT) c_bint_type = CBIntType(RANK_INT)
c_py_unicode_type = CPyUnicodeIntType(RANK_INT-0.5, UNSIGNED) c_py_unicode_type = CPyUnicodeIntType(RANK_INT-0.5, UNSIGNED)
c_py_ucs4_type = CPyUCS4IntType(RANK_LONG-0.5, UNSIGNED)
c_py_ssize_t_type = CPySSizeTType(RANK_LONG+0.5, SIGNED) c_py_ssize_t_type = CPySSizeTType(RANK_LONG+0.5, SIGNED)
c_ssize_t_type = CSSizeTType(RANK_LONG+0.5, SIGNED) c_ssize_t_type = CSSizeTType(RANK_LONG+0.5, SIGNED)
c_size_t_type = CSizeTType(RANK_LONG+0.5, UNSIGNED) c_size_t_type = CSizeTType(RANK_LONG+0.5, UNSIGNED)
...@@ -2367,6 +2442,7 @@ modifiers_and_name_to_type = { ...@@ -2367,6 +2442,7 @@ modifiers_and_name_to_type = {
(1, 0, "bint"): c_bint_type, (1, 0, "bint"): c_bint_type,
(0, 0, "Py_UNICODE"): c_py_unicode_type, (0, 0, "Py_UNICODE"): c_py_unicode_type,
(0, 0, "Py_UCS4"): c_py_ucs4_type,
(2, 0, "Py_ssize_t"): c_py_ssize_t_type, (2, 0, "Py_ssize_t"): c_py_ssize_t_type,
(2, 0, "ssize_t") : c_ssize_t_type, (2, 0, "ssize_t") : c_ssize_t_type,
(0, 0, "size_t") : c_size_t_type, (0, 0, "size_t") : c_size_t_type,
...@@ -2614,6 +2690,8 @@ def parse_basic_type(name): ...@@ -2614,6 +2690,8 @@ def parse_basic_type(name):
longness = 0 longness = 0
if name == 'Py_UNICODE': if name == 'Py_UNICODE':
signed = 0 signed = 0
elif name == 'Py_UCS4':
signed = 0
elif name == 'Py_ssize_t': elif name == 'Py_ssize_t':
signed = 2 signed = 2
elif name == 'ssize_t': elif name == 'ssize_t':
......
...@@ -29,6 +29,49 @@ with open(codefile) as f: ...@@ -29,6 +29,49 @@ with open(codefile) as f:
# can't access the module anymore. Get it from sys.modules instead. # can't access the module anymore. Get it from sys.modules instead.
build_ext = sys.modules['Cython.Distutils.build_ext'] 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): class DebuggerTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -36,6 +79,9 @@ class DebuggerTestCase(unittest.TestCase): ...@@ -36,6 +79,9 @@ class DebuggerTestCase(unittest.TestCase):
Run gdb and have cygdb import the debug information from the code Run gdb and have cygdb import the debug information from the code
defined in TestParseTreeTransforms's setUp method defined in TestParseTreeTransforms's setUp method
""" """
if not test_gdb():
return
self.tempdir = tempfile.mkdtemp() self.tempdir = tempfile.mkdtemp()
self.destfile = os.path.join(self.tempdir, 'codefile.pyx') self.destfile = os.path.join(self.tempdir, 'codefile.pyx')
self.debug_dest = os.path.join(self.tempdir, self.debug_dest = os.path.join(self.tempdir,
...@@ -44,62 +90,77 @@ class DebuggerTestCase(unittest.TestCase): ...@@ -44,62 +90,77 @@ class DebuggerTestCase(unittest.TestCase):
self.cfuncs_destfile = os.path.join(self.tempdir, 'cfuncs') self.cfuncs_destfile = os.path.join(self.tempdir, 'cfuncs')
self.cwd = os.getcwd() self.cwd = os.getcwd()
os.chdir(self.tempdir) try:
os.chdir(self.tempdir)
shutil.copy(codefile, self.destfile)
shutil.copy(cfuncs_file, self.cfuncs_destfile + '.c') shutil.copy(codefile, self.destfile)
shutil.copy(cfuncs_file, self.cfuncs_destfile + '.c')
compiler = ccompiler.new_compiler()
compiler.compile(['cfuncs.c'], debug=True, extra_postargs=['-fPIC']) compiler = ccompiler.new_compiler()
compiler.compile(['cfuncs.c'], debug=True, extra_postargs=['-fPIC'])
opts = dict(
test_directory=self.tempdir, opts = dict(
module='codefile', test_directory=self.tempdir,
) module='codefile',
)
optimization_disabler = build_ext.Optimization()
optimization_disabler.disable_optimization() optimization_disabler = build_ext.Optimization()
cython_compile_testcase = runtests.CythonCompileTestCase( cython_compile_testcase = runtests.CythonCompileTestCase(
workdir=self.tempdir, workdir=self.tempdir,
# we clean up everything (not only compiled files) # we clean up everything (not only compiled files)
cleanup_workdir=False, cleanup_workdir=False,
**opts **opts
) )
cython_compile_testcase.run_cython(
targetdir=self.tempdir, new_stderr = open(os.devnull, 'w')
incdir=None,
annotate=False, stderr = sys.stderr
extra_compile_options={ sys.stderr = new_stderr
'gdb_debug':True,
'output_dir':self.tempdir, optimization_disabler.disable_optimization()
}, try:
**opts cython_compile_testcase.run_cython(
) targetdir=self.tempdir,
incdir=None,
cython_compile_testcase.run_distutils( annotate=False,
incdir=None, extra_compile_options={
workdir=self.tempdir, 'gdb_debug':True,
extra_extension_args={'extra_objects':['cfuncs.o']}, 'output_dir':self.tempdir,
**opts },
) **opts
)
optimization_disabler.restore_state()
cython_compile_testcase.run_distutils(
# ext = Cython.Distutils.extension.Extension( incdir=None,
# 'codefile', workdir=self.tempdir,
# ['codefile.pyx'], extra_extension_args={'extra_objects':['cfuncs.o']},
# pyrex_gdb=True, **opts
# extra_objects=['cfuncs.o']) )
# finally:
# distutils.core.setup( optimization_disabler.restore_state()
# script_args=['build_ext', '--inplace'], sys.stderr = stderr
# ext_modules=[ext],
# cmdclass=dict(build_ext=Cython.Distutils.build_ext) # ext = Cython.Distutils.extension.Extension(
# ) # 'codefile',
# ['codefile.pyx'],
# pyrex_gdb=True,
# extra_objects=['cfuncs.o'])
#
# distutils.core.setup(
# script_args=['build_ext', '--inplace'],
# ext_modules=[ext],
# cmdclass=dict(build_ext=Cython.Distutils.build_ext)
# )
except:
os.chdir(self.cwd)
raise
def tearDown(self): def tearDown(self):
if not test_gdb():
return
os.chdir(self.cwd) os.chdir(self.cwd)
shutil.rmtree(self.tempdir) shutil.rmtree(self.tempdir)
...@@ -107,6 +168,9 @@ class DebuggerTestCase(unittest.TestCase): ...@@ -107,6 +168,9 @@ class DebuggerTestCase(unittest.TestCase):
class GdbDebuggerTestCase(DebuggerTestCase): class GdbDebuggerTestCase(DebuggerTestCase):
def setUp(self): def setUp(self):
if not test_gdb():
return
super(GdbDebuggerTestCase, self).setUp() super(GdbDebuggerTestCase, self).setUp()
prefix_code = textwrap.dedent('''\ prefix_code = textwrap.dedent('''\
...@@ -166,25 +230,26 @@ class GdbDebuggerTestCase(DebuggerTestCase): ...@@ -166,25 +230,26 @@ class GdbDebuggerTestCase(DebuggerTestCase):
p.wait() p.wait()
p.stdout.close() p.stdout.close()
if have_gdb:
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 = [int(a) for a in python_version.split()]
if have_gdb: if have_gdb:
# Based on Lib/test/test_gdb.py # Based on Lib/test/test_gdb.py
regex = "^GNU gdb [^\d]*(\d+)\.(\d+)" regex = "^GNU gdb [^\d]*(\d+)\.(\d+)"
gdb_version_number = re.search(regex, gdb_version).groups() 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 # Be Python 3 compatible
if (not have_gdb 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]): or python_version_number < [2, 6]):
self.p = None self.p = None
warnings.warn( warnings.warn(
...@@ -197,6 +262,9 @@ class GdbDebuggerTestCase(DebuggerTestCase): ...@@ -197,6 +262,9 @@ class GdbDebuggerTestCase(DebuggerTestCase):
env=env) env=env)
def tearDown(self): def tearDown(self):
if not test_gdb():
return
super(GdbDebuggerTestCase, self).tearDown() super(GdbDebuggerTestCase, self).tearDown()
if self.p: if self.p:
self.p.stderr.close() self.p.stderr.close()
...@@ -207,17 +275,24 @@ class GdbDebuggerTestCase(DebuggerTestCase): ...@@ -207,17 +275,24 @@ class GdbDebuggerTestCase(DebuggerTestCase):
class TestAll(GdbDebuggerTestCase): class TestAll(GdbDebuggerTestCase):
def test_all(self): def test_all(self):
if self.p is None: if not test_gdb():
return return
out, err = self.p.communicate() out, err = self.p.communicate()
err = err.decode('UTF-8') err = err.decode('UTF-8')
border = '*' * 30
start = '%s v INSIDE GDB v %s' % (border, border) exit_status = self.p.wait()
end = '%s ^ INSIDE GDB ^ %s' % (border, border)
errmsg = '\n%s\n%s%s' % (start, err, end) if exit_status == 1:
self.assertEquals(0, self.p.wait(), errmsg) sys.stderr.write(err)
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)
sys.stderr.write(errmsg)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -428,7 +428,7 @@ def run_unittest_in_module(modulename): ...@@ -428,7 +428,7 @@ def run_unittest_in_module(modulename):
"debugging information. Either compile python with " "debugging information. Either compile python with "
"-g or get a debug build (configure with --with-pydebug).") "-g or get a debug build (configure with --with-pydebug).")
warnings.warn(msg) warnings.warn(msg)
os._exit(0) os._exit(1)
else: else:
m = __import__(modulename, fromlist=['']) m = __import__(modulename, fromlist=[''])
tests = inspect.getmembers(m, inspect.isclass) tests = inspect.getmembers(m, inspect.isclass)
...@@ -453,7 +453,7 @@ def runtests(): ...@@ -453,7 +453,7 @@ def runtests():
success_libpython = run_unittest_in_module(test_libpython_in_gdb.__name__) success_libpython = run_unittest_in_module(test_libpython_in_gdb.__name__)
if not success_libcython or not success_libpython: if not success_libcython or not success_libpython:
sys.exit(1) sys.exit(2)
def main(version, trace_code=False): def main(version, trace_code=False):
global inferior_python_version global inferior_python_version
......
...@@ -194,7 +194,7 @@ class _XMLTestResult(_TextTestResult): ...@@ -194,7 +194,7 @@ class _XMLTestResult(_TextTestResult):
module = '' module = ''
testcase_name = module + testcase.__name__ 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] = []
tests_by_testcase[testcase_name].append(test_info) tests_by_testcase[testcase_name].append(test_info)
......
__version__ = "0.14.1rc2" __version__ = "0.14.1rc3"
# Void cython.* directives (for case insensitive operating systems). # Void cython.* directives (for case insensitive operating systems).
from Cython.Shadow import * from Cython.Shadow import *
...@@ -26,7 +26,6 @@ try: ...@@ -26,7 +26,6 @@ try:
except ImportError: # No threads, no problems except ImportError: # No threads, no problems
threading = None threading = None
WITH_CYTHON = True WITH_CYTHON = True
from distutils.dist import Distribution from distutils.dist import Distribution
...@@ -34,6 +33,18 @@ from distutils.core import Extension ...@@ -34,6 +33,18 @@ from distutils.core import Extension
from distutils.command.build_ext import build_ext as _build_ext from distutils.command.build_ext import build_ext as _build_ext
distutils_distro = Distribution() distutils_distro = Distribution()
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)
TEST_DIRS = ['compile', 'errors', 'run', 'wrappers', 'pyregr', 'build'] TEST_DIRS = ['compile', 'errors', 'run', 'wrappers', 'pyregr', 'build']
TEST_RUN_DIRS = ['run', 'wrappers', 'pyregr'] TEST_RUN_DIRS = ['run', 'wrappers', 'pyregr']
...@@ -981,6 +992,9 @@ def check_thread_termination(ignore_seen=True): ...@@ -981,6 +992,9 @@ def check_thread_termination(ignore_seen=True):
raise PendingThreadsError("left-over threads found after running test") raise PendingThreadsError("left-over threads found after running test")
def main(): def main():
DISTDIR = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]))
from optparse import OptionParser from optparse import OptionParser
parser = OptionParser() parser = OptionParser()
parser.add_option("--no-cleanup", dest="cleanup_workdir", parser.add_option("--no-cleanup", dest="cleanup_workdir",
...@@ -1051,12 +1065,15 @@ def main(): ...@@ -1051,12 +1065,15 @@ def main():
parser.add_option("--exit-ok", dest="exit_ok", default=False, parser.add_option("--exit-ok", dest="exit_ok", default=False,
action="store_true", action="store_true",
help="exit without error code even on test failures") 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() options, cmd_args = parser.parse_args()
DISTDIR = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0])) ROOTDIR = os.path.abspath(options.root_dir)
ROOTDIR = os.path.join(DISTDIR, 'tests') WORKDIR = os.path.abspath(options.work_dir)
WORKDIR = os.path.join(os.getcwd(), 'BUILD')
if sys.version_info[0] >= 3: if sys.version_info[0] >= 3:
options.doctests = False options.doctests = False
...@@ -1167,7 +1184,7 @@ def main(): ...@@ -1167,7 +1184,7 @@ def main():
exclude_selectors += [ re.compile(r, re.I|re.U).search for r in options.exclude ] exclude_selectors += [ re.compile(r, re.I|re.U).search for r in options.exclude ]
if not test_bugs: 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): if sys.platform in ['win32', 'cygwin'] and sys.version_info < (2,6):
exclude_selectors += [ lambda x: x == "run.specialfloat" ] exclude_selectors += [ lambda x: x == "run.specialfloat" ]
......
...@@ -13,5 +13,5 @@ _ERRORS = """ ...@@ -13,5 +13,5 @@ _ERRORS = """
2:14: Only single-character string literals can be coerced into ints. 2:14: Only single-character string literals can be coerced into ints.
3:14: Only single-character string literals can be coerced into ints. 3:14: Only single-character string literals can be coerced into ints.
6:15: Only single-character string literals can be coerced into ints. 6:15: Only single-character string literals can be coerced into ints.
9:14: Unicode literals do not support coercion to C types other than Py_UNICODE. 9:14: Unicode literals do not support coercion to C types other than Py_UNICODE or Py_UCS4.
""" """
# -*- coding: iso-8859-1 -*-
cdef Py_UCS4 char_ASCII = u'A'
cdef Py_UCS4 char_KLINGON = u'\uF8D2'
def char_too_long_ASCII():
cdef Py_UCS4 c = u'AB'
def char_too_long_Unicode():
cdef Py_UCS4 c = u'A\uF8D2'
def char_too_long_bytes():
cdef Py_UCS4 c = b'AB'
def char_too_long_latin1():
cdef Py_UCS4 char_bytes_latin1 = b'\xf6'
_ERRORS = """
7:21: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
10:21: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
13:21: Only single-character string literals can be coerced into ints.
16:37: Bytes literals cannot coerce to Py_UNICODE/Py_UCS4, use a unicode literal instead.
"""
...@@ -17,8 +17,8 @@ def char_too_long_latin1(): ...@@ -17,8 +17,8 @@ def char_too_long_latin1():
_ERRORS = """ _ERRORS = """
7:24: Only single-character Unicode string literals can be coerced into Py_UNICODE. 7:24: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
10:24: Only single-character Unicode string literals can be coerced into Py_UNICODE. 10:24: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
13:24: Only single-character string literals can be coerced into ints. 13:24: Only single-character string literals can be coerced into ints.
16:40: Bytes literals cannot coerce to Py_UNICODE, use a unicode literal instead. 16:40: Bytes literals cannot coerce to Py_UNICODE/Py_UCS4, use a unicode literal instead.
""" """
...@@ -50,7 +50,7 @@ cdef list l_f2 = b1 ...@@ -50,7 +50,7 @@ cdef list l_f2 = b1
cdef list l_f3 = u1 cdef list l_f3 = u1
_ERRORS = u""" _ERRORS = u"""
25:20: Unicode literals do not support coercion to C types other than Py_UNICODE. 25:20: Unicode literals do not support coercion to C types other than Py_UNICODE or Py_UCS4.
26:22: Unicode objects do not support coercion to C types. 26:22: Unicode objects do not support coercion to C types.
27:22: 'str' objects do not support coercion to C types (use 'bytes'?). 27:22: 'str' objects do not support coercion to C types (use 'bytes'?).
......
...@@ -77,6 +77,23 @@ def test_custom(): ...@@ -77,6 +77,23 @@ def test_custom():
assert isinstance(A(), A) assert isinstance(A(), A)
return True 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): def test_nested(x):
""" """
>>> test_nested(1) >>> test_nested(1)
......
# -*- coding: iso-8859-1 -*-
cimport cython
cdef Py_UCS4 char_ASCII = u'A'
cdef Py_UCS4 char_KLINGON = u'\uF8D2'
def compare_ASCII():
"""
>>> compare_ASCII()
True
False
False
"""
print(char_ASCII == u'A')
print(char_ASCII == u'B')
print(char_ASCII == u'\uF8D2')
def compare_klingon():
"""
>>> compare_klingon()
True
False
False
"""
print(char_KLINGON == u'\uF8D2')
print(char_KLINGON == u'A')
print(char_KLINGON == u'B')
from cpython.unicode cimport PyUnicode_FromOrdinal
import sys
u0 = u'\x00'
u1 = u'\x01'
umax = PyUnicode_FromOrdinal(sys.maxunicode)
def unicode_ordinal(Py_UCS4 i):
"""
>>> ord(unicode_ordinal(0)) == 0
True
>>> ord(unicode_ordinal(1)) == 1
True
>>> ord(unicode_ordinal(sys.maxunicode)) == sys.maxunicode
True
>>> ord(unicode_ordinal(u0)) == 0
True
>>> ord(unicode_ordinal(u1)) == 1
True
>>> ord(unicode_ordinal(umax)) == sys.maxunicode
True
Value too small:
>>> unicode_ordinal(-1) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
Value too large:
>>> unicode_ordinal(1114111+1) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
Less than one character:
>>> unicode_ordinal(u0[:0])
Traceback (most recent call last):
...
ValueError: only single character unicode strings can be converted to Py_UCS4, got length 0
More than one character:
>>> unicode_ordinal(u0+u1)
Traceback (most recent call last):
...
ValueError: only single character unicode strings can be converted to Py_UCS4, got length 2
"""
return i
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode')
def unicode_type_methods(Py_UCS4 uchar):
"""
>>> unicode_type_methods(ord('A'))
[True, True, False, False, False, False, False, True, True]
>>> unicode_type_methods(ord('a'))
[True, True, False, False, True, False, False, False, False]
>>> unicode_type_methods(ord('8'))
[True, False, True, True, False, True, False, False, False]
>>> unicode_type_methods(ord('\\t'))
[False, False, False, False, False, False, True, False, False]
"""
return [
# character types
uchar.isalnum(),
uchar.isalpha(),
uchar.isdecimal(),
uchar.isdigit(),
uchar.islower(),
uchar.isnumeric(),
uchar.isspace(),
uchar.istitle(),
uchar.isupper(),
]
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode')
def unicode_methods(Py_UCS4 uchar):
"""
>>> unicode_methods(ord('A')) == ['a', 'A', 'A']
True
>>> unicode_methods(ord('a')) == ['a', 'A', 'A']
True
"""
return [
# character conversion
uchar.lower(),
uchar.upper(),
uchar.title(),
]
@cython.test_assert_path_exists('//IntNode')
@cython.test_fail_if_path_exists('//SimpleCallNode',
'//PythonCapiCallNode')
def len_uchar(Py_UCS4 uchar):
"""
>>> len_uchar(ord('A'))
1
"""
return len(uchar)
def index_uchar(Py_UCS4 uchar, Py_ssize_t i):
"""
>>> index_uchar(ord('A'), 0) == ('A', 'A', 'A')
True
>>> index_uchar(ord('A'), -1) == ('A', 'A', 'A')
True
>>> index_uchar(ord('A'), 1)
Traceback (most recent call last):
IndexError: string index out of range
"""
return uchar[0], uchar[-1], uchar[i]
mixed_ustring = u'AbcDefGhIjKlmnoP'
lower_ustring = mixed_ustring.lower()
upper_ustring = mixed_ustring.lower()
@cython.test_assert_path_exists('//PythonCapiCallNode',
'//ForFromStatNode')
@cython.test_fail_if_path_exists('//SimpleCallNode',
'//ForInStatNode')
def count_lower_case_characters(unicode ustring):
"""
>>> count_lower_case_characters(mixed_ustring)
10
>>> count_lower_case_characters(lower_ustring)
16
"""
cdef Py_ssize_t count = 0
for uchar in ustring:
if uchar.islower():
count += 1
return count
@cython.test_assert_path_exists('//SwitchStatNode',
'//ForFromStatNode')
@cython.test_fail_if_path_exists('//ForInStatNode')
def iter_and_in():
"""
>>> iter_and_in()
a
b
e
f
h
"""
for c in u'abcdefgh':
if c in u'abCDefGh':
print c
@cython.test_assert_path_exists('//SwitchStatNode',
'//ForFromStatNode')
@cython.test_fail_if_path_exists('//ForInStatNode')
def index_and_in():
"""
>>> index_and_in()
1
3
4
7
8
"""
cdef int i
for i in range(1,9):
if u'abcdefgh'[-i] in u'abCDefGh':
print i
# function call arguments
arg_order = []
cdef int f():
arg_order.append(1)
return 1
def g():
arg_order.append(2)
return 2
cdef call2(int x, object o):
return x, o
def test_c_call():
"""
>>> arg_order
[]
>>> test_c_call()
(1, 2)
>>> arg_order
[1, 2]
"""
return call2(f(), g())
# module globals
cdef object X = 1
cdef redefine_global():
global X
x,X = X,2
return x
cdef call3(object x1, int o, object x2):
return (x1, o, x2)
def test_global_redefine():
"""
>>> test_global_redefine()
(1, 1, 2)
"""
return call3(X, redefine_global(), X)
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