Imported Upstream version 0.29.17 upstream/0.29.17
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:06:12 +0000 (12:06 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:06:12 +0000 (12:06 +0900)
27 files changed:
.travis.yml
CHANGES.rst
Cython/Build/Inline.py
Cython/Build/Tests/TestInline.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/ModuleNode.py
Cython/Includes/libcpp/utility.pxd
Cython/Shadow.py
Cython/Utility/CythonFunction.c
Cython/Utility/ExtensionTypes.c
Cython/Utility/FunctionArguments.c
Cython/Utility/ImportExport.c
Cython/Utility/ObjectHandling.c
Cython/Utility/StringTools.c
appveyor.yml
docs/src/userguide/external_C_code.rst
runtests.py
setup.py
tests/compile/ctuple_unused_T3543.pyx [new file with mode: 0644]
tests/pypy_bugs.txt
tests/run/always_allow_keywords_T295.pyx
tests/run/bytesmethods.pyx
tests/run/charptr_decode.pyx
tests/run/cpp_move.pyx [new file with mode: 0644]
tests/run/reimport_failure.srctree [new file with mode: 0644]
tests/run/tracebacks.pyx
tests/run/unicode_slicing.pyx

index 1e80e2f4e3c94adc29267427abcc17df4bc5e4f5..efffa1c861d729c77d2a6eefc529ea7125f6a181 100644 (file)
@@ -108,7 +108,7 @@ branches:
 
 before_install:
   - |
-    if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
+    if [ "$TRAVIS_OS_NAME" == "linux" ]; then
       # adding apt repos in travis is really fragile => retry a couple of times.
       for i in {1..10}; do travis_retry sudo apt-add-repository --yes 'ppa:ubuntu-toolchain-r/test' && break; sleep 2; done
       for i in {1..10}; do travis_retry sudo apt-get update && travis_retry sudo apt-get install --yes gcc-8  $(if [ -z "${BACKEND##*cpp*}" ]; then echo -n "g++-8"; fi ) && break; sleep 2; done
@@ -119,12 +119,14 @@ before_install:
     fi
 
   - |
-    if [[ "$TRAVIS_OS_NAME" == "osx" ]] || [[ "$STACKLESS" == "true" ]]; then # Install Miniconda
-      if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then CONDA_PLATFORM=MacOSX; else CONDA_PLATFORM=Linux; fi
-      travis_retry curl -s -o miniconda.sh https://repo.continuum.io/miniconda/Miniconda$PY-latest-${CONDA_PLATFORM}-x86_64.sh
-      bash miniconda.sh -b -p $HOME/miniconda && rm miniconda.sh
+    if [ "$TRAVIS_OS_NAME" == "osx" -o "$STACKLESS" == "true" ]; then
+      echo "Installing Miniconda"
+      if [ "$TRAVIS_OS_NAME" == "osx" ]; then CONDA_PLATFORM=MacOSX; else CONDA_PLATFORM=Linux; fi
+      travis_retry wget -O miniconda.sh https://repo.continuum.io/miniconda/Miniconda$PY-latest-${CONDA_PLATFORM}-x86_64.sh || exit 1
+      bash miniconda.sh -b -p $HOME/miniconda && rm miniconda.sh || exit 1
+      conda --version || exit 1
       #conda install --quiet --yes nomkl --file=test-requirements.txt --file=test-requirements-cpython.txt
-      if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+      if [ "$TRAVIS_OS_NAME" == "osx" ]; then
         which clang && clang --version && export CC=clang || true
         which clang++ && clang++ --version && export CXX=clang++ || true
       fi
@@ -133,7 +135,7 @@ before_install:
   - if [ -n "$CC" ]; then which $CC; $CC --version; fi
   - if [ -n "$CXX" ]; then which $CXX; $CXX --version; fi
 
-  - if [[ "$STACKLESS" == "true" ]]; then
+  - if [ "$STACKLESS" == "true" ]; then
       conda config --add channels stackless;
       travis_retry conda install --quiet --yes stackless;
     fi
index 8b44fb6c8d258dc670e058bf8536032685996294..8e9143fdff82c8965ba9a3fd599f5129cf46a057 100644 (file)
@@ -2,6 +2,49 @@
 Cython Changelog
 ================
 
+0.29.17 (2020-04-26)
+====================
+
+Features added
+--------------
+
+* ``std::move()`` is now available from ``libcpp.utility``.
+  Patch by Omer Ozarslan.  (Github issue #2169)
+
+* The ``@cython.binding`` decorator is available in Python code.
+  (Github issue #3505)
+
+Bugs fixed
+----------
+
+* Creating an empty unicode slice with large bounds could crash.
+  Patch by Sam Sneddon.  (Github issue #3531)
+
+* Decoding an empty bytes/char* slice with large bounds could crash.
+  Patch by Sam Sneddon.  (Github issue #3534)
+
+* Re-importing a Cython extension no longer raises the error
+  "``__reduce_cython__ not found``".
+  (Github issue #3545)
+
+* Unused C-tuples could generate incorrect code in 0.29.16.
+  Patch by Kirk Meyer.  (Github issue #3543)
+
+* Creating a fused function attached it to the garbage collector before it
+  was fully initialised, thus risking crashes in rare failure cases.
+  Original patch by achernomorov.  (Github issue #3215)
+
+* Temporary buffer indexing variables were not released and could show up in
+  C compiler warnings, e.g. in generators.
+  Patch by David Woods.  (Github issues #3430, #3522)
+
+* The compilation cache in ``cython.inline("…")`` failed to take the language
+  level into account.
+  Patch by will-ca.  (Github issue #3419)
+
+* The deprecated ``PyUnicode_GET_SIZE()`` function is no longer used in Py3.
+
+
 0.29.16 (2020-03-24)
 ====================
 
index 47be53427688f89cfb6e7211c5f4f61f5a4debbe..fdd38e21d527022d86592b1c025cbdd6408dbe0b 100644 (file)
@@ -144,6 +144,10 @@ def _populate_unbound(kwds, unbound_symbols, locals=None, globals=None):
             else:
                 print("Couldn't find %r" % symbol)
 
+def _inline_key(orig_code, arg_sigs, language_level):
+    key = orig_code, arg_sigs, sys.version_info, sys.executable, language_level, Cython.__version__
+    return hashlib.sha1(_unicode(key).encode('utf-8')).hexdigest()
+
 def cython_inline(code, get_type=unsafe_type,
                   lib_dir=os.path.join(get_cython_cache_dir(), 'inline'),
                   cython_include_dirs=None, cython_compiler_directives=None,
@@ -153,13 +157,20 @@ def cython_inline(code, get_type=unsafe_type,
         get_type = lambda x: 'object'
     ctx = _create_context(tuple(cython_include_dirs)) if cython_include_dirs else _cython_inline_default_context
 
+    cython_compiler_directives = dict(cython_compiler_directives or {})
+    if language_level is None and 'language_level' not in cython_compiler_directives:
+        language_level = '3str'
+    if language_level is not None:
+        cython_compiler_directives['language_level'] = language_level
+
     # Fast path if this has been called in this session.
     _unbound_symbols = _cython_inline_cache.get(code)
     if _unbound_symbols is not None:
         _populate_unbound(kwds, _unbound_symbols, locals, globals)
         args = sorted(kwds.items())
         arg_sigs = tuple([(get_type(value, ctx), arg) for arg, value in args])
-        invoke = _cython_inline_cache.get((code, arg_sigs))
+        key_hash = _inline_key(code, arg_sigs, language_level)
+        invoke = _cython_inline_cache.get((code, arg_sigs, key_hash))
         if invoke is not None:
             arg_list = [arg[1] for arg in args]
             return invoke(*arg_list)
@@ -180,10 +191,6 @@ def cython_inline(code, get_type=unsafe_type,
             # Parsing from strings not fully supported (e.g. cimports).
             print("Could not parse code as a string (to extract unbound symbols).")
 
-    cython_compiler_directives = dict(cython_compiler_directives or {})
-    if language_level is not None:
-        cython_compiler_directives['language_level'] = language_level
-
     cimports = []
     for name, arg in list(kwds.items()):
         if arg is cython_module:
@@ -191,8 +198,8 @@ def cython_inline(code, get_type=unsafe_type,
             del kwds[name]
     arg_names = sorted(kwds)
     arg_sigs = tuple([(get_type(kwds[arg], ctx), arg) for arg in arg_names])
-    key = orig_code, arg_sigs, sys.version_info, sys.executable, language_level, Cython.__version__
-    module_name = "_cython_inline_" + hashlib.md5(_unicode(key).encode('utf-8')).hexdigest()
+    key_hash = _inline_key(orig_code, arg_sigs, language_level)
+    module_name = "_cython_inline_" + key_hash
 
     if module_name in sys.modules:
         module = sys.modules[module_name]
@@ -259,7 +266,7 @@ def __invoke(%(params)s):
 
         module = load_dynamic(module_name, module_path)
 
-    _cython_inline_cache[orig_code, arg_sigs] = module.__invoke
+    _cython_inline_cache[orig_code, arg_sigs, key_hash] = module.__invoke
     arg_list = [kwds[arg] for arg in arg_names]
     return module.__invoke(*arg_list)
 
index 0a40e0de50e6a6c4d6ae4d18545c52da51686d0b..5ef9fec4efb433385665fc7f351763239185897b 100644 (file)
@@ -74,6 +74,18 @@ class TestInline(CythonTest):
             6
         )
 
+    def test_lang_version(self):
+        # GH-3419. Caching for inline code didn't always respect compiler directives.
+        inline_divcode = "def f(int a, int b): return a/b"
+        self.assertEqual(
+            inline(inline_divcode, language_level=2)['f'](5,2),
+            2
+        )
+        self.assertEqual(
+            inline(inline_divcode, language_level=3)['f'](5,2),
+            2.5
+        )
+
     if has_numpy:
 
         def test_numpy(self):
index 19e7d733af2d4d6f1bd7b7cd9a60e92a606ff1c6..41ebfb9e505b4898e18e7fcb6736f7e0296dbcec 100644 (file)
@@ -4200,6 +4200,9 @@ class BufferIndexNode(_IndexingBaseNode):
     # Whether we're assigning to a buffer (in that case it needs to be writable)
     writable_needed = False
 
+    # Any indexing temp variables that we need to clean up.
+    index_temps = ()
+
     def analyse_target_types(self, env):
         self.analyse_types(env, getting=False)
 
@@ -4284,7 +4287,7 @@ class BufferIndexNode(_IndexingBaseNode):
                     warning(self.pos, "Use boundscheck(False) for faster access", level=1)
 
         # Assign indices to temps of at least (s)size_t to allow further index calculations.
-        index_temps = [self.get_index_in_temp(code,ivar) for ivar in self.indices]
+        self.index_temps = index_temps = [self.get_index_in_temp(code,ivar) for ivar in self.indices]
 
         # Generate buffer access code using these temps
         from . import Buffer
@@ -4370,6 +4373,12 @@ class BufferIndexNode(_IndexingBaseNode):
             code.putln("%s = (PyObject *) *%s;" % (self.result(), self.buffer_ptr_code))
             code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result())
 
+    def free_temps(self, code):
+        for temp in self.index_temps:
+            code.funcstate.release_temp(temp)
+        self.index_temps = ()
+        super(BufferIndexNode, self).free_temps(code)
+
 
 class MemoryViewIndexNode(BufferIndexNode):
 
@@ -9387,11 +9396,11 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
         if self.specialized_cpdefs or self.is_specialization:
             code.globalstate.use_utility_code(
                 UtilityCode.load_cached("FusedFunction", "CythonFunction.c"))
-            constructor = "__pyx_FusedFunction_NewEx"
+            constructor = "__pyx_FusedFunction_New"
         else:
             code.globalstate.use_utility_code(
                 UtilityCode.load_cached("CythonFunction", "CythonFunction.c"))
-            constructor = "__Pyx_CyFunction_NewEx"
+            constructor = "__Pyx_CyFunction_New"
 
         if self.code_object:
             code_object_result = self.code_object.py_result()
index fe59836aca39f326da8b88f8ce72b52037d57fca..8a1e1e718f0f5c62c1912d9144bb8dd39d12b15a 100644 (file)
@@ -580,7 +580,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             definition = module is env
             type_entries = []
             for entry in module.type_entries:
-                if entry.type.is_ctuple:
+                if entry.type.is_ctuple and entry.used:
                     if entry.name not in ctuple_names:
                         ctuple_names.add(entry.name)
                         type_entries.append(entry)
index ab649fe7a1aba83131a16b2688ee184a49ce857d..ec8ba401836936595290f8e766e33c15a79ddcf1 100644 (file)
@@ -13,3 +13,17 @@ cdef extern from "<utility>" namespace "std" nogil:
         bint operator>(pair&, pair&)
         bint operator<=(pair&, pair&)
         bint operator>=(pair&, pair&)
+
+cdef extern from * namespace "cython_std" nogil:
+    """
+    #if __cplusplus > 199711L
+    #include <type_traits>
+
+    namespace cython_std {
+    template <typename T> typename std::remove_reference<T>::type&& move(T& t) noexcept { return std::move(t); }
+    template <typename T> typename std::remove_reference<T>::type&& move(T&& t) noexcept { return std::move(t); }
+    }
+
+    #endif
+    """
+    cdef T move[T](T)
index 0ad294f669a587e6f7bb17ce9ee831a9fa541630..96d9e3984c7c8a7932f5c98df42600296c1f5d64 100644 (file)
@@ -1,7 +1,7 @@
 # cython.* namespace for pure mode.
 from __future__ import absolute_import
 
-__version__ = "0.29.16"
+__version__ = "0.29.17"
 
 try:
     from __builtin__ import basestring
@@ -123,6 +123,8 @@ overflowcheck.fold = optimization.use_switch = \
 
 final = internal = type_version_tag = no_gc_clear = no_gc = _empty_decorator
 
+binding = lambda _: _empty_decorator
+
 
 _cython_inline = None
 def inline(f, *args, **kwds):
index 9e9da163dd99e7f220f09398661d8eb6318d4ab9..8f2349722c4b4f40ac0a92276209ba59be34188f 100644 (file)
@@ -1,6 +1,6 @@
 
+//////////////////// CythonFunctionShared.proto ////////////////////
 
-//////////////////// CythonFunction.proto ////////////////////
 #define __Pyx_CyFunction_USED 1
 
 #define __Pyx_CYFUNCTION_STATICMETHOD  0x01
@@ -50,10 +50,7 @@ static PyTypeObject *__pyx_CyFunctionType = 0;
 
 #define __Pyx_CyFunction_Check(obj)  (__Pyx_TypeCheck(obj, __pyx_CyFunctionType))
 
-#define __Pyx_CyFunction_NewEx(ml, flags, qualname, self, module, globals, code) \
-    __Pyx_CyFunction_New(__pyx_CyFunctionType, ml, flags, qualname, self, module, globals, code)
-
-static PyObject *__Pyx_CyFunction_New(PyTypeObject *, PyMethodDef *ml,
+static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml,
                                       int flags, PyObject* qualname,
                                       PyObject *self,
                                       PyObject *module, PyObject *globals,
@@ -72,7 +69,8 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m,
 
 static int __pyx_CyFunction_init(void);
 
-//////////////////// CythonFunction ////////////////////
+
+//////////////////// CythonFunctionShared ////////////////////
 //@substitute: naming
 //@requires: CommonStructures.c::FetchCommonType
 ////@requires: ObjectHandling.c::PyObjectGetAttrStr
@@ -446,11 +444,9 @@ static PyMethodDef __pyx_CyFunction_methods[] = {
 #define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func.m_weakreflist)
 #endif
 
-
-static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, PyObject* qualname,
-                                      PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) {
-    __pyx_CyFunctionObject *op = PyObject_GC_New(__pyx_CyFunctionObject, type);
-    if (op == NULL)
+static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname,
+                                       PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) {
+    if (unlikely(op == NULL))
         return NULL;
     op->flags = flags;
     __Pyx_CyFunction_weakreflist(op) = NULL;
@@ -478,7 +474,6 @@ static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int f
     op->defaults_kwdict = NULL;
     op->defaults_getter = NULL;
     op->func_annotations = NULL;
-    PyObject_GC_Track(op);
     return (PyObject *) op;
 }
 
@@ -779,11 +774,36 @@ static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, Py
     Py_INCREF(dict);
 }
 
+
+//////////////////// CythonFunction.proto ////////////////////
+
+static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml,
+                                      int flags, PyObject* qualname,
+                                      PyObject *closure,
+                                      PyObject *module, PyObject *globals,
+                                      PyObject* code);
+
+//////////////////// CythonFunction ////////////////////
+//@requires: CythonFunctionShared
+
+static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname,
+                                      PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) {
+    PyObject *op = __Pyx_CyFunction_Init(
+        PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType),
+        ml, flags, qualname, closure, module, globals, code
+    );
+    if (likely(op)) {
+        PyObject_GC_Track(op);
+    }
+    return op;
+}
+
+
 //////////////////// CyFunctionClassCell.proto ////////////////////
 static int __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *classobj);/*proto*/
 
 //////////////////// CyFunctionClassCell ////////////////////
-//@requires: CythonFunction
+//@requires: CythonFunctionShared
 
 static int __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *classobj) {
     Py_ssize_t i, count = PyList_GET_SIZE(cyfunctions);
@@ -806,7 +826,9 @@ static int __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *class
     return 0;
 }
 
+
 //////////////////// FusedFunction.proto ////////////////////
+
 typedef struct {
     __pyx_CyFunctionObject func;
     PyObject *__signatures__;
@@ -814,11 +836,8 @@ typedef struct {
     PyObject *self;
 } __pyx_FusedFunctionObject;
 
-#define __pyx_FusedFunction_NewEx(ml, flags, qualname, self, module, globals, code)         \
-        __pyx_FusedFunction_New(__pyx_FusedFunctionType, ml, flags, qualname, self, module, globals, code)
-static PyObject *__pyx_FusedFunction_New(PyTypeObject *type,
-                                         PyMethodDef *ml, int flags,
-                                         PyObject *qualname, PyObject *self,
+static PyObject *__pyx_FusedFunction_New(PyMethodDef *ml, int flags,
+                                         PyObject *qualname, PyObject *closure,
                                          PyObject *module, PyObject *globals,
                                          PyObject *code);
 
@@ -829,24 +848,27 @@ static int __pyx_FusedFunction_init(void);
 #define __Pyx_FusedFunction_USED
 
 //////////////////// FusedFunction ////////////////////
-//@requires: CythonFunction
+//@requires: CythonFunctionShared
 
 static PyObject *
-__pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags,
-                        PyObject *qualname, PyObject *self,
+__pyx_FusedFunction_New(PyMethodDef *ml, int flags,
+                        PyObject *qualname, PyObject *closure,
                         PyObject *module, PyObject *globals,
                         PyObject *code)
 {
-    __pyx_FusedFunctionObject *fusedfunc =
-        (__pyx_FusedFunctionObject *) __Pyx_CyFunction_New(type, ml, flags, qualname,
-                                                           self, module, globals, code);
-    if (!fusedfunc)
-        return NULL;
-
-    fusedfunc->__signatures__ = NULL;
-    fusedfunc->type = NULL;
-    fusedfunc->self = NULL;
-    return (PyObject *) fusedfunc;
+    PyObject *op = __Pyx_CyFunction_Init(
+        // __pyx_CyFunctionObject is correct below since that's the cast that we want.
+        PyObject_GC_New(__pyx_CyFunctionObject, __pyx_FusedFunctionType),
+        ml, flags, qualname, closure, module, globals, code
+    );
+    if (likely(op)) {
+        __pyx_FusedFunctionObject *fusedfunc = (__pyx_FusedFunctionObject *) op;
+        fusedfunc->__signatures__ = NULL;
+        fusedfunc->type = NULL;
+        fusedfunc->self = NULL;
+        PyObject_GC_Track(op);
+    }
+    return op;
 }
 
 static void
@@ -896,7 +918,7 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type)
     if (obj == Py_None)
         obj = NULL;
 
-    meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_NewEx(
+    meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_New(
                     ((PyCFunctionObject *) func)->m_ml,
                     ((__pyx_CyFunctionObject *) func)->flags,
                     ((__pyx_CyFunctionObject *) func)->func_qualname,
@@ -972,31 +994,32 @@ __pyx_FusedFunction_getitem(__pyx_FusedFunctionObject *self, PyObject *idx)
     if (PyTuple_Check(idx)) {
         PyObject *list = PyList_New(0);
         Py_ssize_t n = PyTuple_GET_SIZE(idx);
-        PyObject *string = NULL;
         PyObject *sep = NULL;
         int i;
 
-        if (!list)
+        if (unlikely(!list))
             return NULL;
 
         for (i = 0; i < n; i++) {
+            int ret;
+            PyObject *string;
 #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
             PyObject *item = PyTuple_GET_ITEM(idx, i);
 #else
-            PyObject *item = PySequence_ITEM(idx, i);
+            PyObject *item = PySequence_ITEM(idx, i);  if (unlikely(!item)) goto __pyx_err;
 #endif
             string = _obj_to_str(item);
 #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS)
             Py_DECREF(item);
 #endif
-            if (!string || PyList_Append(list, string) < 0)
-                goto __pyx_err;
-
+            if (unlikely(!string)) goto __pyx_err;
+            ret = PyList_Append(list, string);
             Py_DECREF(string);
+            if (unlikely(ret < 0)) goto __pyx_err;
         }
 
         sep = PyUnicode_FromString("|");
-        if (sep)
+        if (likely(sep))
             signature = PyUnicode_Join(sep, list);
 __pyx_err:
 ;
index 4107b9143dfb5fce584c90bf895453f814e3b42c..5c700cf9314de75e9a8032142e3fa3999f204e31 100644 (file)
@@ -132,6 +132,7 @@ static void __Pyx_call_next_tp_clear(PyObject* obj, inquiry current_tp_clear) {
 static int __Pyx_setup_reduce(PyObject* type_obj);
 
 /////////////// SetupReduce ///////////////
+//@requires: ObjectHandling.c::PyObjectGetAttrStrNoError
 //@requires: ObjectHandling.c::PyObjectGetAttrStr
 //@substitute: naming
 
@@ -188,16 +189,28 @@ static int __Pyx_setup_reduce(PyObject* type_obj) {
         reduce = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__reduce__")); if (unlikely(!reduce)) goto __PYX_BAD;
 
         if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, PYIDENT("__reduce_cython__"))) {
-            reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__reduce_cython__")); if (unlikely(!reduce_cython)) goto __PYX_BAD;
-            ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce__"), reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
-            ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+            reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, PYIDENT("__reduce_cython__"));
+            if (likely(reduce_cython)) {
+                ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce__"), reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
+                ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+            } else if (reduce == object_reduce || PyErr_Occurred()) {
+                // Ignore if we're done, i.e. if 'reduce' already has the right name and the original is gone.
+                // Otherwise: error.
+                goto __PYX_BAD;
+            }
 
             setstate = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__setstate__"));
             if (!setstate) PyErr_Clear();
             if (!setstate || __Pyx_setup_reduce_is_named(setstate, PYIDENT("__setstate_cython__"))) {
-                setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__setstate_cython__")); if (unlikely(!setstate_cython)) goto __PYX_BAD;
-                ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate__"), setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
-                ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+                setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, PYIDENT("__setstate_cython__"));
+                if (likely(setstate_cython)) {
+                    ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate__"), setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
+                    ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+                } else if (!setstate || PyErr_Occurred()) {
+                    // Ignore if we're done, i.e. if 'setstate' already has the right name and the original is gone.
+                    // Otherwise: error.
+                    goto __PYX_BAD;
+                }
             }
             PyType_Modified((PyTypeObject*)type_obj);
         }
index 1815974b6a94b90c5e21752d2a2663d4ffc8b56a..8333d9366640fcfc5040a859b53535cdd55409c1 100644 (file)
@@ -211,7 +211,7 @@ static int __Pyx_ParseOptionalKeywords(
 
         name = first_kw_arg;
         #if PY_MAJOR_VERSION < 3
-        if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) {
+        if (likely(PyString_Check(key))) {
             while (*name) {
                 if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key))
                         && _PyString_Eq(**name, key)) {
@@ -239,9 +239,9 @@ static int __Pyx_ParseOptionalKeywords(
             while (*name) {
                 int cmp = (**name == key) ? 0 :
                 #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3
-                    (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 :
+                    (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 :
                 #endif
-                    // need to convert argument name from bytes to unicode for comparison
+                    // In Py2, we may need to convert the argument name from str to unicode for comparison.
                     PyUnicode_Compare(**name, key);
                 if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad;
                 if (cmp == 0) {
@@ -257,7 +257,7 @@ static int __Pyx_ParseOptionalKeywords(
                 while (argname != first_kw_arg) {
                     int cmp = (**argname == key) ? 0 :
                     #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3
-                        (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 :
+                        (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 :
                     #endif
                         // need to convert argument name from bytes to unicode for comparison
                         PyUnicode_Compare(**argname, key);
index 67034672354c9d756650ddd5b9c7d360fee928ad..676bc4c71752cac5e1e62ef2595a9c18179918a5 100644 (file)
@@ -46,7 +46,8 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
     {
         #if PY_MAJOR_VERSION >= 3
         if (level == -1) {
-            if (strchr(__Pyx_MODULE_NAME, '.')) {
+            // Avoid C compiler warning if strchr() evaluates to false at compile time.
+            if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) {
                 /* try package relative import first */
                 module = PyImport_ImportModuleLevelObject(
                     name, global_dict, empty_dict, list, 1);
index bf6f9532274be5b5033c6f8a632d24a5c5a322f3..fbb22bea49b64d2aa630cadd6aa0f7ac8a3370bc 100644 (file)
@@ -1361,6 +1361,41 @@ static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_nam
 #endif
 
 
+/////////////// PyObjectGetAttrStrNoError.proto ///////////////
+
+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name);/*proto*/
+
+/////////////// PyObjectGetAttrStrNoError ///////////////
+//@requires: PyObjectGetAttrStr
+//@requires: Exceptions.c::PyThreadStateGet
+//@requires: Exceptions.c::PyErrFetchRestore
+//@requires: Exceptions.c::PyErrExceptionMatches
+
+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) {
+    __Pyx_PyThreadState_declare
+    __Pyx_PyThreadState_assign
+    if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError)))
+        __Pyx_PyErr_Clear();
+}
+
+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) {
+    PyObject *result;
+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1
+    // _PyObject_GenericGetAttrWithDict() in CPython 3.7+ can avoid raising the AttributeError.
+    // See https://bugs.python.org/issue32544
+    PyTypeObject* tp = Py_TYPE(obj);
+    if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) {
+        return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1);
+    }
+#endif
+    result = __Pyx_PyObject_GetAttrStr(obj, attr_name);
+    if (unlikely(!result)) {
+        __Pyx_PyObject_GetAttrStr_ClearAttributeError();
+    }
+    return result;
+}
+
+
 /////////////// PyObjectGetAttrStr.proto ///////////////
 
 #if CYTHON_USE_TYPE_SLOTS
index 8147778e52b54c08d32005a9f73f573502f8d466..68315d9495977178e05e55bd283d7f4978c65d8c 100644 (file)
@@ -466,9 +466,9 @@ static CYTHON_INLINE PyObject* __Pyx_decode_c_string(
         if (stop < 0)
             stop += length;
     }
-    length = stop - start;
-    if (unlikely(length <= 0))
+    if (unlikely(stop <= start))
         return PyUnicode_FromUnicode(NULL, 0);
+    length = stop - start;
     cstring += start;
     if (decode_func) {
         return decode_func(cstring, length, errors);
@@ -502,9 +502,9 @@ static CYTHON_INLINE PyObject* __Pyx_decode_c_bytes(
     }
     if (stop > length)
         stop = length;
-    length = stop - start;
-    if (unlikely(length <= 0))
+    if (unlikely(stop <= start))
         return PyUnicode_FromUnicode(NULL, 0);
+    length = stop - start;
     cstring += start;
     if (decode_func) {
         return decode_func(cstring, length, errors);
@@ -558,8 +558,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring(
         stop += length;
     else if (stop > length)
         stop = length;
-    length = stop - start;
-    if (length <= 0)
+    if (stop <= start)
         return PyUnicode_FromUnicode(NULL, 0);
 #if CYTHON_PEP393_ENABLED
     return PyUnicode_FromKindAndData(PyUnicode_KIND(text),
index 860fcbb50f4f702e5459499ab7aa6eedc4e9f1d5..56e47e1256b622c7eb5e3e046031afa1ae794a82 100644 (file)
@@ -17,6 +17,14 @@ environment:
       PYTHON_VERSION: "2.7"
       PYTHON_ARCH: "64"
 
+    - PYTHON: "C:\\Python38"
+      PYTHON_VERSION: "3.8"
+      PYTHON_ARCH: "32"
+
+    - PYTHON: "C:\\Python38-x64"
+      PYTHON_VERSION: "3.8"
+      PYTHON_ARCH: "64"
+
     - PYTHON: "C:\\Python37"
       PYTHON_VERSION: "3.7"
       PYTHON_ARCH: "32"
index 80764b2536d6268f1319a7bf96fe8df9c2a4a671..e6605223d8b5e3ffc1f893c680feb11bbac40825 100644 (file)
@@ -17,7 +17,7 @@ to be less frequent, but you might want to do it, for example, if you are
 Cython module can be used as a bridge to allow Python code to call C code, it
 can also be used to allow C code to call Python code.
 
-.. _embedding Python: http://www.freenet.org.nz/python/embeddingpyrex/
+.. _embedding Python: https://web.archive.org/web/20120225082358/http://www.freenet.org.nz:80/python/embeddingpyrex/
 
 External declarations
 =======================
index 5d3e30eba0a1be34d89df409936b8c554da0d8c5..3b4d8adfb63d16e2d2e8e353bba0b8a3f9a70a7b 100755 (executable)
@@ -424,6 +424,7 @@ VER_DEP_MODULES = {
     # to be unsafe...
     (2,999): (operator.lt, lambda x: x in ['run.special_methods_T561_py3',
                                            'run.test_raisefrom',
+                                           'run.reimport_failure',  # reimports don't do anything in Py2
                                            ]),
     (3,): (operator.ge, lambda x: x in ['run.non_future_division',
                                         'compile.extsetslice',
@@ -1095,6 +1096,11 @@ class CythonCompileTestCase(unittest.TestCase):
                 from Cython.Build.Dependencies import update_pythran_extension
                 update_pythran_extension(extension)
 
+            # Compile with -DCYTHON_CLINE_IN_TRACEBACK=1 unless we have
+            # the "traceback" tag
+            if 'traceback' not in self.tags['tag']:
+                extension.define_macros.append(("CYTHON_CLINE_IN_TRACEBACK", 1))
+
             for matcher, fixer in list(EXT_EXTRAS.items()):
                 if isinstance(matcher, str):
                     # lazy init
index df7047f7afb02b2915057a6cc02f403ff95d7b71..cdc3d926493fbf0fe444660dd3a1ba87e92e7728 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -248,8 +248,9 @@ setup(
     Python code.
 
     Note that for one-time builds, e.g. for CI/testing, on platforms that are not
-    covered by one of the wheel packages provided on PyPI, it is substantially faster
-    than a full source build to install an uncompiled (slower) version of Cython with::
+    covered by one of the wheel packages provided on PyPI *and* the pure Python wheel
+    that we provide is not used, it is substantially faster than a full source build
+    to install an uncompiled (slower) version of Cython with::
 
         pip install Cython --install-option="--no-cython-compile"
 
diff --git a/tests/compile/ctuple_unused_T3543.pyx b/tests/compile/ctuple_unused_T3543.pyx
new file mode 100644 (file)
index 0000000..88446dd
--- /dev/null
@@ -0,0 +1,9 @@
+# ticket: 3543
+# mode: compile
+
+# Views define unused ctuples, including (long,)
+from cython cimport view
+
+# Implicitly generate a ctuple (long,)
+obj = None
+obj or (1,)
index 4152fd63ab83b5b72967570b845d3e0d198246c9..77b814cf1e898d78aa411c732e069f77c53db546 100644 (file)
@@ -11,6 +11,8 @@ sequential_parallel
 yield_from_pep380
 memoryview_inplace_division
 
+run.reimport_failure
+
 # gc issue?
 memoryview_in_subclasses
 external_ref_reassignment
index 132489b6afc40ca13a94ed95ab0545f410b65fb8..694839fcf5a096dd97a3ffe7b41e910772612168 100644 (file)
@@ -2,15 +2,23 @@
 
 cimport cython
 
+def assert_typeerror_no_keywords(func, *args, **kwds):
+    # Python 3.9 produces an slightly different error message
+    # to previous versions, so doctest isn't matching the
+    # traceback
+    try:
+        func(*args, **kwds)
+    except TypeError as e:
+        assert e.args[0].endswith(" takes no keyword arguments"), e.args[0]
+    else:
+        assert False, "call did not raise TypeError"
+
 
 def func1(arg):
     """
     >>> func1(None)
     >>> func1(*[None])
-    >>> func1(arg=None)
-    Traceback (most recent call last):
-    ...
-    TypeError: func1() takes no keyword arguments
+    >>> assert_typeerror_no_keywords(func1, arg=None)
     """
     pass
 
@@ -19,10 +27,7 @@ def func2(arg):
     """
     >>> func2(None)
     >>> func2(*[None])
-    >>> func2(arg=None)
-    Traceback (most recent call last):
-    ...
-    TypeError: func2() takes no keyword arguments
+    >>> assert_typeerror_no_keywords(func2, arg=None)
     """
     pass
 
@@ -39,16 +44,10 @@ cdef class A:
     """
     >>> A().meth1(None)
     >>> A().meth1(*[None])
-    >>> A().meth1(arg=None)
-    Traceback (most recent call last):
-    ...
-    TypeError: meth1() takes no keyword arguments
+    >>> assert_typeerror_no_keywords(A().meth1, arg=None)
     >>> A().meth2(None)
     >>> A().meth2(*[None])
-    >>> A().meth2(arg=None)
-    Traceback (most recent call last):
-    ...
-    TypeError: meth2() takes no keyword arguments
+    >>> assert_typeerror_no_keywords(A().meth2, arg=None)
     >>> A().meth3(None)
     >>> A().meth3(*[None])
     >>> A().meth3(arg=None)
index 14a06c42d5c6860433cf5ecaaa2a91c60cb06a41..f2a10e1d24df3119c4ebac9441ed171506c542e6 100644 (file)
@@ -1,5 +1,13 @@
 cimport cython
 
+cdef extern from *:
+    cdef Py_ssize_t PY_SSIZE_T_MIN
+    cdef Py_ssize_t PY_SSIZE_T_MAX
+
+SSIZE_T_MAX = PY_SSIZE_T_MAX
+SSIZE_T_MIN = PY_SSIZE_T_MIN
+
+
 b_a = b'a'
 b_b = b'b'
 
@@ -114,6 +122,14 @@ def bytes_decode(bytes s, start=None, stop=None):
     <BLANKLINE>
     >>> print(bytes_decode(s, -300, -500))
     <BLANKLINE>
+    >>> print(bytes_decode(s, SSIZE_T_MIN, SSIZE_T_MIN))
+    <BLANKLINE>
+    >>> print(bytes_decode(s, SSIZE_T_MIN, SSIZE_T_MAX))
+    abaab
+    >>> print(bytes_decode(s, SSIZE_T_MAX, SSIZE_T_MIN))
+    <BLANKLINE>
+    >>> print(bytes_decode(s, SSIZE_T_MAX, SSIZE_T_MAX))
+    <BLANKLINE>
 
     >>> s[:'test']                       # doctest: +ELLIPSIS
     Traceback (most recent call last):
index e7f9b541f223812256dda1b7fa31dcdf6ea82521..e7c26db1b7a4a3507604d6f00743eb3dfa6bf358 100644 (file)
@@ -1,6 +1,11 @@
 
 cimport cython
 
+cdef extern from *:
+    cdef Py_ssize_t PY_SSIZE_T_MIN
+    cdef Py_ssize_t PY_SSIZE_T_MAX
+
+
 ############################################################
 # tests for char* slicing
 
@@ -118,6 +123,19 @@ def slice_charptr_dynamic_bounds_non_name():
             (cstring+1)[:].decode('UTF-8'),
             (cstring+1)[return1():return5()].decode('UTF-8'))
 
+@cython.test_assert_path_exists("//PythonCapiCallNode")
+@cython.test_fail_if_path_exists("//AttributeNode")
+def slice_charptr_decode_large_bounds():
+    """
+    >>> print(str(slice_charptr_decode_large_bounds()).replace("u'", "'"))
+    ('abcABCqtp', '', '', '')
+    """
+    return (cstring[PY_SSIZE_T_MIN:9].decode('UTF-8'),
+            cstring[PY_SSIZE_T_MAX:PY_SSIZE_T_MIN].decode('UTF-8'),
+            cstring[PY_SSIZE_T_MIN:PY_SSIZE_T_MIN].decode('UTF-8'),
+            cstring[PY_SSIZE_T_MAX:PY_SSIZE_T_MAX].decode('UTF-8'))
+
+
 cdef return1(): return 1
 cdef return3(): return 3
 cdef return4(): return 4
diff --git a/tests/run/cpp_move.pyx b/tests/run/cpp_move.pyx
new file mode 100644 (file)
index 0000000..d93afe2
--- /dev/null
@@ -0,0 +1,34 @@
+# mode: run
+# tag: cpp, werror, cpp11
+
+from libcpp cimport nullptr
+from libcpp.memory cimport shared_ptr, make_shared
+from libcpp.utility cimport move
+from cython.operator cimport dereference
+
+cdef extern from *:
+    """
+    #include <string>
+
+    template<typename T> const char* move_helper(T&) { return "lvalue-ref"; }
+    template<typename T> const char* move_helper(T&&) { return "rvalue-ref"; }
+    """
+    const char* move_helper[T](T)
+
+def test_move_assignment():
+    """
+    >>> test_move_assignment()
+    """
+    cdef shared_ptr[int] p1, p2
+    p1 = make_shared[int](1337)
+    p2 = move(p1)
+    assert p1 == nullptr
+    assert dereference(p2) == 1337
+
+def test_move_func_call():
+    """
+    >>> test_move_func_call()
+    """
+    cdef shared_ptr[int] p
+    assert move_helper(p) == b'lvalue-ref'
+    assert move_helper(move(p)) == b'rvalue-ref'
diff --git a/tests/run/reimport_failure.srctree b/tests/run/reimport_failure.srctree
new file mode 100644 (file)
index 0000000..498c9bd
--- /dev/null
@@ -0,0 +1,38 @@
+# mode: run
+# tag: pep489
+
+"""
+PYTHON setup.py build_ext -i
+PYTHON tester.py
+"""
+
+######## setup.py ########
+
+from Cython.Build.Dependencies import cythonize
+from distutils.core import setup
+
+setup(
+  ext_modules = cythonize("*.pyx"),
+)
+
+
+######## failure.pyx ########
+
+if globals():  # runtime True to confuse dead code removal
+    raise ImportError
+
+cdef class C:
+    cdef int a
+
+
+######## tester.py ########
+
+try:
+    try:
+        import failure  # 1
+    except ImportError:
+        import failure  # 2
+except ImportError:
+    pass
+else:
+    raise RuntimeError("ImportError was not raised on second import!")
index b33e852dceb607e6c1a23dbd791a7ccb73b34459..17b93b448c94b0cf061d5ead18271cbe348cbd7d 100644 (file)
@@ -1,4 +1,4 @@
-import traceback
+# tag: traceback
 
 def foo1():
   foo2()
@@ -21,6 +21,7 @@ def test_traceback(cline_in_traceback=None):
   try:
     foo1()
   except:
+    import traceback
     tb_string = traceback.format_exc()
     expected = (
       'tracebacks.pyx',
index fa48dde591da136510a1edd8fe06e13e440ab3a5..c84d7052e5e4575ac1c9bbc2ff8cd65e24273078 100644 (file)
@@ -151,30 +151,52 @@ __doc__ = u"""
     >>> slice_none_none(None, 2, 4)
     Traceback (most recent call last):    
     TypeError: 'NoneType' object is not subscriptable
+
+    >>> slice_start_end(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+    <BLANKLINE>
+    >>> slice_start(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+    <BLANKLINE>
+    >>> slice_end(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+    abcdef
+    >>> slice_all(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+    abcdef
+    >>> slice_start_none(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+    <BLANKLINE>
+    >>> slice_none_end(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+    abcdef
+    >>> slice_none_none(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+    abcdef
 """
 
+cdef extern from *:
+    cdef Py_ssize_t PY_SSIZE_T_MIN
+    cdef Py_ssize_t PY_SSIZE_T_MAX
+
+SSIZE_T_MAX = PY_SSIZE_T_MAX
+SSIZE_T_MIN = PY_SSIZE_T_MIN
+
 import sys
 
 if sys.version_info[0] >= 3:
     __doc__ = __doc__.replace(u"(u'", u"('").replace(u" u'", u" '")
 
-def slice_start_end(unicode s, int i, int j):
+def slice_start_end(unicode s, Py_ssize_t i, Py_ssize_t j):
     print(s[i:j])
 
-def slice_start(unicode s, int i, int j):
+def slice_start(unicode s, Py_ssize_t i, Py_ssize_t j):
     print(s[i:])
 
-def slice_end(unicode s, int i, int j):
+def slice_end(unicode s, Py_ssize_t i, Py_ssize_t j):
     print(s[:i])
 
-def slice_all(unicode s, int i, int j):
+def slice_all(unicode s, Py_ssize_t i, Py_ssize_t j):
     print(s[:])
 
-def slice_start_none(unicode s, int i, int j):
+def slice_start_none(unicode s, Py_ssize_t i, Py_ssize_t j):
     print(s[i:None])
 
-def slice_none_end(unicode s, int i, int j):
+def slice_none_end(unicode s, Py_ssize_t i, Py_ssize_t j):
     print(s[None:i])
 
-def slice_none_none(unicode s, int i, int j):
+def slice_none_none(unicode s, Py_ssize_t i, Py_ssize_t j):
     print(s[None:None])