STYLE_ARGS=--no-code-style;
if $PYTHON_DBG -V >&2; then CFLAGS="-O0 -ggdb" $PYTHON_DBG runtests.py -vv --no-code-style Debugger --backends=$BACKEND; fi;
if [ -z "${BACKEND##*cpp*}" -a -n "${TRAVIS_PYTHON_VERSION##*-dev}" ]; then pip install pythran; fi;
- if [ "$BACKEND" != "cpp" -a -n "${TRAVIS_PYTHON_VERSION##2*}" -a -n "${TRAVIS_PYTHON_VERSION##*-dev}" ]; then pip install mypy; fi;
+ if [ "$BACKEND" != "cpp" -a -n "${TRAVIS_PYTHON_VERSION##2*}" -a -n "${TRAVIS_PYTHON_VERSION##*-dev}" -a -n "${TRAVIS_PYTHON_VERSION##*3.4}" ]; then pip install mypy; fi;
fi
- if [ "$COVERAGE" != "1" ]; then CFLAGS="-O2 -ggdb -Wall -Wextra $(python -c 'import sys; print("-fno-strict-aliasing" if sys.version_info[0] == 2 else "")')" python setup.py build_ext -i; fi
- CFLAGS="-O0 -ggdb -Wall -Wextra" python runtests.py -vv $STYLE_ARGS -x Debugger --backends=$BACKEND $(if [ "$COVERAGE" == "1" ]; then echo " --coverage"; fi) $(if [ -z "$TEST_CODE_STYLE" ]; then echo " -j7 "; fi)
Cython Changelog
================
+0.29.8 (2019-05-28)
+===================
+
+Bugs fixed
+----------
+
+* C compile errors with CPython 3.8 were resolved.
+ Patch by Marcel Plch. (Github issue #2938)
+
+* Python tuple constants that compare equal but have different item
+ types could incorrectly be merged into a single constant.
+ (Github issue #2919)
+
+* Non-ASCII characters in unprefixed strings could crash the compiler when
+ used with language level ``3str``.
+
+* Starred expressions in %-formatting tuples could fail to compile for
+ unicode strings. (Github issue #2939)
+
+* Passing Python class references through ``cython.inline()`` was broken.
+ (Github issue #2936)
+
+
0.29.7 (2019-04-14)
===================
elif 'numpy' in sys.modules and isinstance(arg, sys.modules['numpy'].ndarray):
return 'numpy.ndarray[numpy.%s_t, ndim=%s]' % (arg.dtype.name, arg.ndim)
else:
- for base_type in py_type.mro():
+ for base_type in py_type.__mro__:
if base_type.__module__ in ('__builtin__', 'builtins'):
return 'object'
module = context.find_module(base_type.__module__, need_pxd=False)
foo = inline("def foo(x): return x * x", **self.test_kwds)['foo']
self.assertEquals(foo(7), 49)
+ def test_class_ref(self):
+ class Type(object):
+ pass
+ tp = inline("Type")['Type']
+ self.assertEqual(tp, Type)
+
def test_pure(self):
import cython as cy
b = inline("""
@return: A tuple that can be used as a dict key for deduplication.
"""
item_keys = [
- (py_object_type, None) if node is None
+ (py_object_type, None, type(None)) if node is None
# For sequences and their "mult_factor", see TupleNode.
else make_dedup_key(node.type, [node.mult_factor if node.is_literal else None] + node.args) if node.is_sequence_constructor
else make_dedup_key(node.type, (node.start, node.stop, node.step)) if node.is_slice
- else (node.type, node.constant_result) if node.has_constant_result()
+ # For constants, look at the Python value type if we don't know the concrete Cython type.
+ else (node.type, node.constant_result,
+ type(node.constant_result) if node.type is py_object_type else None) if node.has_constant_result()
else None # something we cannot handle => short-circuit below
for node in item_nodes
]
return str(int(self.value))
def coerce_to(self, dst_type, env):
+ if dst_type == self.type:
+ return self
+ if dst_type is py_object_type and self.type is Builtin.bool_type:
+ return self
if dst_type.is_pyobject and self.type.is_int:
return BoolNode(
self.pos, value=self.value,
warning(pos, "Too few arguments for format placeholders", level=1)
can_be_optimised = False
break
+ if arg.is_starred:
+ can_be_optimised = False
+ break
if format_type in u'asrfdoxX':
format_spec = s[1:]
if format_type in u'doxX' and u'.' in format_spec:
else:
# keep it simple for now ...
can_be_optimised = False
+ break
if not can_be_optimised:
# Print all warnings we can find before finally giving up here.
error(pos, u"invalid character literal: %r" % bytes_value)
else:
bytes_value, unicode_value = chars.getstrings()
- if is_python3_source and has_non_ascii_literal_characters:
+ if (has_non_ascii_literal_characters
+ and is_python3_source and Future.unicode_literals in s.context.future_directives):
# Python 3 forbids literal non-ASCII characters in byte strings
if kind == 'b':
s.error("bytes can only contain ASCII literal characters.", pos=pos)
# cython.* namespace for pure mode.
from __future__ import absolute_import
-__version__ = "0.29.7"
+__version__ = "0.29.8"
try:
from __builtin__ import basestring
#define __Pyx_DefaultClassType PyClass_Type
#else
#define __Pyx_BUILTIN_MODULE_NAME "builtins"
+#if PY_VERSION_HEX < 0x030800A4
#define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \
PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
+#else
+ #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \
+ PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
+#endif
#define __Pyx_DefaultClassType PyType_Type
#endif
PyObject *py_funcname = 0;
PyCodeObject *py_code = 0;
- #if PY_MAJOR_VERSION < 3
+#if PY_MAJOR_VERSION >= 3
+ py_code = PyCode_NewEmpty(srcfile, funcname, firstlineno);
+ // make CPython use a fresh dict for "f_locals" at need (see GH #1836)
+ py_code->co_flags |= CO_OPTIMIZED | CO_NEWLOCALS;
+#else
+
+
py_funcname = PyString_FromString(funcname);
py_srcfile = PyString_FromString(srcfile);
- #else
- py_funcname = PyUnicode_FromString(funcname);
- py_srcfile = PyUnicode_FromString(srcfile);
- #endif
- if (!py_funcname | !py_srcfile) goto bad;
py_code = PyCode_New(
0, /*int argcount,*/
- #if PY_MAJOR_VERSION >= 3
- 0, /*int kwonlyargcount,*/
- #endif
0, /*int nlocals,*/
0, /*int stacksize,*/
// make CPython use a fresh dict for "f_locals" at need (see GH #1836)
bad:
Py_XDECREF(py_srcfile);
Py_XDECREF(py_funcname);
+#endif
return py_code;
}
pass
else:
with self.stats.time(self.name, 'py', 'mypy'):
- mypy_result = mypy_api.run((
+ mypy_result = mypy_api.run([
self.module_path,
'--ignore-missing-imports',
'--follow-imports', 'skip',
- ))
+ ])
if mypy_result[2]:
self.fail(mypy_result[0])
"""
import sys
-if sys.version_info[0] >= 3:
+IS_PY2 = sys.version_info[0] < 3
+if not IS_PY2:
__doc__ = __doc__.replace(" u'", " '")
def locals_function(a, b=2):
return ustring
+def non_ascii_unprefixed_str():
+ u"""
+ >>> s = non_ascii_unprefixed_str()
+ >>> isinstance(s, bytes)
+ False
+ >>> len(s)
+ 3
+ """
+ s = 'ø\x20\u0020'
+ assert isinstance(s, unicode)
+ return s
+
+
+def non_ascii_raw_str():
+ u"""
+ >>> s = non_ascii_raw_str()
+ >>> isinstance(s, bytes)
+ False
+ >>> len(s)
+ 11
+ """
+ s = r'ø\x20\u0020'
+ assert isinstance(s, unicode)
+ return s
+
+
+def non_ascii_raw_prefixed_unicode():
+ u"""
+ >>> s = non_ascii_raw_prefixed_unicode()
+ >>> isinstance(s, bytes)
+ False
+ >>> len(s)
+ 11
+ """
+ s = ru'ø\x20\u0020'
+ assert isinstance(s, unicode)
+ return s
+
+
def str_type_is_unicode():
"""
>>> str_type, s = str_type_is_unicode()
x = 'abc'
"""
+import sys
+IS_PY2 = sys.version_info[0] < 3
+
+
def locals_function(a, b=2):
x = 'abc'
return locals()
return str_string
+def non_ascii_str():
+ u"""
+ >>> s = 'ø\\x20\\u0020'
+ >>> isinstance(s, str)
+ True
+ >>> print(not IS_PY2 or len(s) == 9 or len(s)) # first is 2-char bytes in Py2, hex escape is resolved
+ True
+ >>> print(IS_PY2 or len(s) == 3 or len(s)) # 3 unicode characters in Py3
+ True
+
+ >>> s = non_ascii_str()
+ >>> isinstance(s, str)
+ True
+ >>> print(not IS_PY2 or len(s) == 9 or len(s)) # first is 2-char bytes in Py2, hex escape is resolved
+ True
+ >>> print(IS_PY2 or len(s) == 3 or len(s)) # 3 unicode characters in Py3
+ True
+ """
+ s = 'ø\x20\u0020'
+ assert isinstance(s, str)
+ assert (IS_PY2 and isinstance(s, bytes)) or (not IS_PY2 and isinstance(s, unicode))
+ return s
+
+
+def non_ascii_raw_str():
+ u"""
+ >>> s = r'ø\\x20\\u0020'
+ >>> print(not IS_PY2 or len(s) == 12 or len(s)) # Py2 (first character is two bytes)
+ True
+ >>> print(IS_PY2 or len(s) == 11 or len(s)) # Py3 (unicode string)
+ True
+
+ >>> s = non_ascii_raw_str()
+ >>> isinstance(s, str)
+ True
+ >>> print(not IS_PY2 or len(s) == 12 or len(s)) # Py2 (first character is two bytes)
+ True
+ >>> print(IS_PY2 or len(s) == 11 or len(s)) # Py3 (unicode string)
+ True
+ """
+ s = r'ø\x20\u0020'
+ assert isinstance(s, str)
+ assert (IS_PY2 and isinstance(s, bytes)) or (not IS_PY2 and isinstance(s, unicode))
+ return s
+
+
+def non_ascii_raw_unicode():
+ u"""
+ >>> s = non_ascii_raw_unicode()
+ >>> isinstance(s, bytes)
+ False
+ >>> len(s)
+ 11
+ """
+ s = ru'ø\x20\u0020'
+ assert isinstance(s, unicode)
+ return s
+
+
def str_type_is_str():
"""
>>> str_type, s = str_type_is_str()
+# mode: run
+# tag: all_language_levels
cimport cython
return (*a, *b, 2, *c)
+def unpack_tuple_in_string_formatting(a, *args):
+ """
+ >>> print(unpack_tuple_in_string_formatting(1, 2))
+ 1 2
+ >>> print(unpack_tuple_in_string_formatting(1, 'x'))
+ 1 'x'
+ >>> unpack_tuple_in_string_formatting(1) # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ TypeError: ...format...
+ >>> unpack_tuple_in_string_formatting(1, 2, 3) # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ TypeError: ...format...
+ """
+ return "%s %r" % (a, *args)
+
+
#### lists
self.assertEqual('h\u0130'.capitalize(), 'H\u0069\u0307')
exp = '\u0399\u0308\u0300\u0069\u0307'
self.assertEqual('\u1fd2\u0130'.capitalize(), exp)
- self.assertEqual('finnish'.capitalize(), 'FInnish')
+ # Note: differs between Py<3.8 and later.
+ #self.assertEqual('finnish'.capitalize(), 'FInnish')
self.assertEqual('A\u0345\u03a3'.capitalize(), 'A\u0345\u03c2')
def test_title(self):
for c in set_o:
self.assertEqual(c.encode('ascii').decode('utf7'), c)
+ if sys.version_info >= (3, 8):
+ with self.assertRaisesRegex(UnicodeDecodeError,
+ 'ill-formed sequence'):
+ b'+@'.decode('utf-7')
+
def test_codecs_utf8(self):
self.assertEqual(''.encode('utf-8'), b'')
self.assertEqual('\u20ac'.encode('utf-8'), b'\xe2\x82\xac')
u = chr(c)
for encoding in ('utf-7', 'utf-8', 'utf-16', 'utf-16-le',
'utf-16-be', 'raw_unicode_escape',
- 'unicode_escape', 'unicode_internal'):
- with warnings.catch_warnings():
- # unicode-internal has been deprecated
- warnings.simplefilter("ignore", DeprecationWarning)
-
- self.assertEqual(str(u.encode(encoding),encoding), u)
+ 'unicode_escape'):
+ self.assertEqual(str(u.encode(encoding),encoding), u)
# Roundtrip safety for BMP (just the first 256 chars)
for c in range(256):
# Roundtrip safety for non-BMP (just a few chars)
with warnings.catch_warnings():
- # unicode-internal has been deprecated
- warnings.simplefilter("ignore", DeprecationWarning)
-
u = '\U00010001\U00020002\U00030003\U00040004\U00050005'
for encoding in ('utf-8', 'utf-16', 'utf-16-le', 'utf-16-be',
- 'raw_unicode_escape',
- 'unicode_escape', 'unicode_internal'):
+ 'raw_unicode_escape', 'unicode_escape'):
self.assertEqual(str(u.encode(encoding),encoding), u)
# UTF-8 must be roundtrip safe for all code points
self.assertEqual(args[0], text)
self.assertEqual(len(args), 1)
+ @unittest.skipIf(sys.version_info < (3, 8), 'resize test requires Py3.8+')
+ @support.cpython_only
def test_resize(self):
+ from _testcapi import getargs_u
for length in range(1, 100, 7):
# generate a fresh string (refcount=1)
text = 'a' * length + 'b'
- with support.check_warnings(('unicode_internal codec has been '
- 'deprecated', DeprecationWarning)):
- # fill wstr internal field
- abc = text.encode('unicode_internal')
- self.assertEqual(abc.decode('unicode_internal'), text)
+ # fill wstr internal field
+ abc = getargs_u(text)
+ self.assertEqual(abc, text)
- # resize text: wstr field must be cleared and then recomputed
- text += 'c'
- abcdef = text.encode('unicode_internal')
- self.assertNotEqual(abc, abcdef)
- self.assertEqual(abcdef.decode('unicode_internal'), text)
+ # resize text: wstr field must be cleared and then recomputed
+ text += 'c'
+ abcdef = getargs_u(text)
+ self.assertNotEqual(abc, abcdef)
+ self.assertEqual(abcdef, text)
def test_compare(self):
# Issue #17615
check_format('%.%s',
b'%.%s', b'abc')
+ # Issue #33817: empty strings
+ check_format('',
+ b'')
+ check_format('',
+ b'%s', b'')
+
# Test PyUnicode_AsWideChar()
@support.cpython_only
def test_aswidechar(self):
def test_capitalize_nonascii(self):
# check that titlecased chars are lowered correctly
# \u1ffc is the titlecased char
- self.checkequal('\u03a9\u0399\u1ff3\u1ff3\u1ff3',
- '\u1ff3\u1ff3\u1ffc\u1ffc', 'capitalize')
+ # Note: differs between Py<3.8 and later.
+ #self.checkequal('\u03a9\u0399\u1ff3\u1ff3\u1ff3',
+ # '\u1ff3\u1ff3\u1ffc\u1ffc', 'capitalize')
# check with cased non-letter chars
self.checkequal('\u24c5\u24e8\u24e3\u24d7\u24de\u24dd',
'\u24c5\u24ce\u24c9\u24bd\u24c4\u24c3', 'capitalize')
"""
a = eval("1")
return ('a', a, 'd')
+
+
+def constant_types_comparing_equal():
+ """
+ >>> constant_types_comparing_equal()
+ ((False, False), (0, 0), (0.0, 0.0), (0, False), (False, 0.0), (0, 0.0))
+ """
+ bool_tuple= (False, False)
+ int_tuple = (0, 0)
+ float_tuple = (0.0, 0.0)
+ int_bool = (0, False)
+ bool_float = (False, 0.0)
+ int_float = (0, 0.0)
+
+ assert bool_tuple is (False, False)
+ assert int_tuple is (0, 0)
+ assert bool_tuple == int_tuple
+ assert bool_tuple is not int_tuple
+ assert float_tuple is (0., 0.)
+ assert float_tuple == int_tuple
+ assert float_tuple is not int_tuple
+ assert int_bool is (0, False)
+ assert int_bool == bool_tuple
+ assert int_bool is not bool_tuple
+ assert int_bool is not int_tuple
+ assert bool_float is (False, 0.)
+ assert bool_float == bool_tuple
+ assert bool_float is not bool_tuple
+ assert bool_float is not float_tuple
+ assert int_float is (0, 0.)
+ assert int_float == int_tuple
+ assert int_float is not int_tuple
+ assert int_float is not float_tuple
+
+ return bool_tuple, int_tuple, float_tuple, int_bool, bool_float, int_float