Imported Upstream version 0.29.8 upstream/0.29.8
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:05:10 +0000 (12:05 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:05:10 +0000 (12:05 +0900)
17 files changed:
.travis.yml
CHANGES.rst
Cython/Build/Inline.py
Cython/Build/Tests/TestInline.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/Optimize.py
Cython/Compiler/Parsing.py
Cython/Shadow.py
Cython/Utility/ModuleSetupCode.c
Cython/Utility/Profile.c
runtests.py
tests/run/cython3.pyx
tests/run/cython3_no_unicode_literals.pyx
tests/run/pep448_extended_unpacking.pyx
tests/run/test_unicode.pyx
tests/run/test_unicode_string_tests.pxi
tests/run/tuple_constants.pyx

index a79db7d..433745c 100644 (file)
@@ -151,7 +151,7 @@ script:
       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)
index 33b41d5..2a1791d 100644 (file)
@@ -2,6 +2,29 @@
 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)
 ===================
 
index a19cebd..8bc6d69 100644 (file)
@@ -90,7 +90,7 @@ def safe_type(arg, context=None):
     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)
index 6a15644..0a40e0d 100644 (file)
@@ -51,6 +51,12 @@ class TestInline(CythonTest):
         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("""
index fa8575a..f873305 100644 (file)
@@ -198,11 +198,13 @@ def make_dedup_key(outer_type, item_nodes):
     @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
     ]
@@ -1207,6 +1209,10 @@ class BoolNode(ConstNode):
             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,
index 5c6dd02..96155b6 100644 (file)
@@ -4322,6 +4322,9 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
                 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:
@@ -4339,6 +4342,7 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
             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.
index 010870f..56884f0 100644 (file)
@@ -958,7 +958,8 @@ def p_string_literal(s, kind_override=None):
             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)
index 3acacb5..3cf20a8 100644 (file)
@@ -1,7 +1,7 @@
 # cython.* namespace for pure mode.
 from __future__ import absolute_import
 
-__version__ = "0.29.7"
+__version__ = "0.29.8"
 
 try:
     from __builtin__ import basestring
index c719786..6360215 100644 (file)
@@ -381,8 +381,13 @@ class __Pyx_FakeReference {
   #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
 
index c4463e8..71d1e0a 100644 (file)
@@ -293,20 +293,18 @@ static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const cha
     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)
@@ -326,6 +324,7 @@ static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const cha
 bad:
     Py_XDECREF(py_srcfile);
     Py_XDECREF(py_funcname);
+#endif
 
     return py_code;
 }
index 1f843c9..646df74 100755 (executable)
@@ -1416,11 +1416,11 @@ class PureDoctestTestCase(unittest.TestCase):
                 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])
 
index 0e8b97f..335a2cf 100644 (file)
@@ -21,7 +21,8 @@ True
 """
 
 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):
@@ -312,6 +313,45 @@ def unicode_literals():
     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()
index ba61439..c9690b3 100644 (file)
@@ -13,6 +13,10 @@ b = 2
 x = 'abc'
 """
 
+import sys
+IS_PY2 = sys.version_info[0] < 3
+
+
 def locals_function(a, b=2):
     x = 'abc'
     return locals()
@@ -64,6 +68,65 @@ def no_unicode_literals():
     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()
index ed038b5..61414f4 100644 (file)
@@ -1,3 +1,5 @@
+# mode: run
+# tag: all_language_levels
 
 cimport cython
 
@@ -144,6 +146,22 @@ def unpack_tuple_keep_originals(a, b, c):
     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
 
 
index 09d9ebd..f69f58c 100644 (file)
@@ -842,7 +842,8 @@ class UnicodeTest(CommonTest,
         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):
@@ -1666,6 +1667,11 @@ class UnicodeTest(CommonTest,
         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')
@@ -2136,12 +2142,8 @@ class UnicodeTest(CommonTest,
             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):
@@ -2157,13 +2159,9 @@ class UnicodeTest(CommonTest,
 
         # 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
@@ -2382,22 +2380,23 @@ class UnicodeTest(CommonTest,
         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
@@ -2714,6 +2713,12 @@ class CAPITest(unittest.TestCase):
         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):
index a0100f2..61cc6f2 100644 (file)
@@ -977,8 +977,9 @@ class CommonTest(BaseTest):
     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')
index ee9be34..55992d9 100644 (file)
@@ -132,3 +132,38 @@ def return_nonconstant_tuple():
     """
     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