Imported Upstream version 0.29.19 upstream/0.29.19
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:06:20 +0000 (12:06 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:06:20 +0000 (12:06 +0900)
29 files changed:
.travis.yml
CHANGES.rst
Cython/Compiler/Code.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/MemoryView.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Optimize.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Parsing.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Scanning.py
Cython/Distutils/old_build_ext.py
Cython/Includes/cpython/datetime.pxd
Cython/Includes/numpy/__init__.pxd
Cython/Shadow.py
Cython/Utility/Buffer.c
Cython/Utility/ExtensionTypes.c
Cython/Utility/MemoryView_C.c
Cython/Utility/ModuleSetupCode.c
runtests.py
tests/buffers/buffmt.pyx
tests/buffers/mockbuffers.pxi
tests/memoryview/numpy_memoryview.pyx
tests/run/async_def.pyx
tests/run/fstring.pyx
tests/run/numpy_common.pxi
tests/run/numpy_test.pyx
tests/run/parallel.pyx
tests/windows_bugs.txt

index efffa1c861d729c77d2a6eefc529ea7125f6a181..0bb801354eb03f349261ed45ec1ac35815f1f6cd 100644 (file)
@@ -75,6 +75,14 @@ matrix:
       dist: xenial    # Required for Python 3.7
       sudo: required  # travis-ci/travis-ci#9069
       env: BACKEND=cpp
+    - python: 3.9-dev
+      dist: xenial    # Required for Python 3.7
+      sudo: required  # travis-ci/travis-ci#9069
+      env: BACKEND=c
+    - python: 3.9-dev
+      dist: xenial    # Required for Python 3.7
+      sudo: required  # travis-ci/travis-ci#9069
+      env: BACKEND=cpp
     - os: osx
       osx_image: xcode6.4
       env: PY=2
@@ -98,6 +106,7 @@ matrix:
     - env: STACKLESS=true BACKEND=c PY=3
       python: 3.6
   allow_failures:
+    - python: 3.9-dev
     - python: pypy
     - python: pypy3
 
index 8e9143fdff82c8965ba9a3fd599f5129cf46a057..64fd0bac952eef408ba439afbe99983e24bdb9c6 100644 (file)
@@ -2,6 +2,74 @@
 Cython Changelog
 ================
 
+0.29.19 (2020-05-20)
+====================
+
+Bugs fixed
+----------
+
+* A typo in Windows specific code in 0.29.18 was fixed that broke "libc.math".
+  (Github issue #3622)
+
+* A platform specific test failure in 0.29.18 was fixed.
+  Patch by smutch.  (Github issue #3620)
+
+
+0.29.18 (2020-05-18)
+====================
+
+Bugs fixed
+----------
+
+* Exception position reporting could run into race conditions on threaded code.
+  It now uses function-local variables again.
+
+* Error handling early in the module init code could lead to a crash.
+
+* Error handling in ``cython.array`` creation was improved to avoid calling
+  C-API functions with an error held.
+
+* A memory corruption was fixed when garbage collection was triggered during calls
+  to ``PyType_Ready()`` of extension type subclasses.
+  (Github issue #3603)
+
+* Memory view slicing generated unused error handling code which could negatively
+  impact the C compiler optimisations for parallel OpenMP code etc.  Also, it is
+  now helped by static branch hints.
+  (Github issue #2987)
+
+* Cython's built-in OpenMP functions were not translated inside of call arguments.
+  Original patch by Celelibi and David Woods.  (Github issue #3594)
+
+* Complex buffer item types of structs of arrays could fail to validate.
+  Patch by Leo and smutch.  (Github issue #1407)
+
+* Decorators were not allowed on nested `async def` functions.
+  (Github issue #1462)
+
+* C-tuples could use invalid C struct casting.
+  Patch by MegaIng.  (Github issue #3038)
+
+* Optimised ``%d`` string formatting into f-strings failed on float values.
+  (Github issue #3092)
+
+* Optimised aligned string formatting (``%05s``, ``%-5s``) failed.
+  (Github issue #3476)
+
+* When importing the old Cython ``build_ext`` integration with distutils, the
+  additional command line arguments leaked into the regular command.
+  Patch by Kamekameha.  (Github issue #2209)
+
+* When using the ``CYTHON_NO_PYINIT_EXPORT`` option in C++, the module init function
+  was not declared as ``extern "C"``.
+  (Github issue #3414)
+
+* Three missing timedelta access macros were added in ``cpython.datetime``.
+
+* The signature of the NumPy C-API function ``PyArray_SearchSorted()`` was fixed.
+  Patch by Brock Mendel.  (Github issue #3606)
+
+
 0.29.17 (2020-04-26)
 ====================
 
index 160a878850ae2f4b133a2dc592ab5ed4c5fdbb54..b9c689ce7641ce1680058df0fd3de6c7f8326144 100644 (file)
@@ -280,7 +280,7 @@ class UtilityCodeBase(object):
         _, ext = os.path.splitext(path)
         if ext in ('.pyx', '.py', '.pxd', '.pxi'):
             comment = '#'
-            strip_comments = partial(re.compile(r'^\s*#.*').sub, '')
+            strip_comments = partial(re.compile(r'^\s*#(?!\s*cython\s*:).*').sub, '')
             rstrip = StringEncoding._unicode.rstrip
         else:
             comment = '/'
@@ -2344,24 +2344,18 @@ class CCodeWriter(object):
         self.funcstate.should_declare_error_indicator = True
         if used:
             self.funcstate.uses_error_indicator = True
-        if self.code_config.c_line_in_traceback:
-            cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
-        else:
-            cinfo = ""
-
-        return "%s = %s[%s]; %s = %s;%s" % (
-            Naming.filename_cname,
-            Naming.filetable_cname,
+        return "__PYX_MARK_ERR_POS(%s, %s)" % (
             self.lookup_filename(pos[0]),
-            Naming.lineno_cname,
-            pos[1],
-            cinfo)
+            pos[1])
 
-    def error_goto(self, pos):
+    def error_goto(self, pos, used=True):
         lbl = self.funcstate.error_label
         self.funcstate.use_label(lbl)
         if pos is None:
             return 'goto %s;' % lbl
+        self.funcstate.should_declare_error_indicator = True
+        if used:
+            self.funcstate.uses_error_indicator = True
         return "__PYX_ERR(%s, %s, %s)" % (
             self.lookup_filename(pos[0]),
             pos[1],
index 41ebfb9e505b4898e18e7fcb6736f7e0296dbcec..7d184e66a3c35f8461e9fcb5fed5b83eb29124ab 100644 (file)
@@ -3222,7 +3222,7 @@ class FormattedValueNode(ExprNode):
     # {}-delimited portions of an f-string
     #
     # value           ExprNode                The expression itself
-    # conversion_char str or None             Type conversion (!s, !r, !a, or none)
+    # conversion_char str or None             Type conversion (!s, !r, !a, or none, or 'd' for integer conversion)
     # format_spec     JoinedStrNode or None   Format string passed to __format__
     # c_format_spec   str or None             If not None, formatting can be done at the C level
 
@@ -3236,6 +3236,7 @@ class FormattedValueNode(ExprNode):
         's': 'PyObject_Unicode',
         'r': 'PyObject_Repr',
         'a': 'PyObject_ASCII',  # NOTE: mapped to PyObject_Repr() in Py2
+        'd': '__Pyx_PyNumber_IntOrLong',  # NOTE: internal mapping for '%d' formatting
     }.get
 
     def may_be_none(self):
@@ -10697,17 +10698,20 @@ class CythonArrayNode(ExprNode):
             code.putln(code.error_goto(self.operand.pos))
             code.putln("}")
 
-        code.putln("%s = __pyx_format_from_typeinfo(&%s);" %
-                                                (format_temp, type_info))
-        buildvalue_fmt = " __PYX_BUILD_PY_SSIZE_T " * len(shapes)
-        code.putln('%s = Py_BuildValue((char*) "(" %s ")", %s);' % (
-            shapes_temp, buildvalue_fmt, ", ".join(shapes)))
-
-        err = "!%s || !%s || !PyBytes_AsString(%s)" % (format_temp,
-                                                       shapes_temp,
-                                                       format_temp)
-        code.putln(code.error_goto_if(err, self.pos))
+        code.putln("%s = __pyx_format_from_typeinfo(&%s); %s" % (
+            format_temp,
+            type_info,
+            code.error_goto_if_null(format_temp, self.pos),
+        ))
         code.put_gotref(format_temp)
+
+        buildvalue_fmt = " __PYX_BUILD_PY_SSIZE_T " * len(shapes)
+        code.putln('%s = Py_BuildValue((char*) "(" %s ")", %s); %s' % (
+            shapes_temp,
+            buildvalue_fmt,
+            ", ".join(shapes),
+            code.error_goto_if_null(shapes_temp, self.pos),
+        ))
         code.put_gotref(shapes_temp)
 
         tup = (self.result(), shapes_temp, itemsize, format_temp,
index 6ac1d88e43d491dd4b9e0d49464282ba6862b3be..0406d6c716a8ae6ed04a19a663884d387913c0b5 100644 (file)
@@ -291,7 +291,6 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
 
             dim += 1
             access, packing = self.type.axes[dim]
-            error_goto = code.error_goto(index.pos)
 
             if isinstance(index, ExprNodes.SliceNode):
                 # slice, unspecified dimension, or part of ellipsis
@@ -308,6 +307,7 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
                     util_name = "SimpleSlice"
                 else:
                     util_name = "ToughSlice"
+                    d['error_goto'] = code.error_goto(index.pos)
 
                 new_ndim += 1
             else:
@@ -325,8 +325,10 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
                 d = dict(
                     locals(),
                     wraparound=int(directives['wraparound']),
-                    boundscheck=int(directives['boundscheck'])
+                    boundscheck=int(directives['boundscheck']),
                 )
+                if d['boundscheck']:
+                    d['error_goto'] = code.error_goto(index.pos)
                 util_name = "SliceIndex"
 
             _, impl = TempitaUtilityCode.load_as_string(util_name, "MemoryView_C.c", context=d)
index 8a1e1e718f0f5c62c1912d9144bb8dd39d12b15a..ede21ff09b8e806b13fd09ee84e1af575bc2e38c 100644 (file)
@@ -658,16 +658,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         self._put_setup_code(code, "PythonCompatibility")
         self._put_setup_code(code, "MathInitCode")
 
+        # Using "(void)cname" to prevent "unused" warnings.
         if options.c_line_in_traceback:
-            cinfo = "%s = %s; " % (Naming.clineno_cname, Naming.line_c_macro)
+            cinfo = "%s = %s; (void)%s; " % (Naming.clineno_cname, Naming.line_c_macro, Naming.clineno_cname)
         else:
             cinfo = ""
-        code.put("""
-#define __PYX_ERR(f_index, lineno, Ln_error) \\
-{ \\
-  %s = %s[f_index]; %s = lineno; %sgoto Ln_error; \\
-}
-""" % (Naming.filename_cname, Naming.filetable_cname, Naming.lineno_cname, cinfo))
+        code.putln("#define __PYX_MARK_ERR_POS(f_index, lineno) \\")
+        code.putln("    { %s = %s[f_index]; (void)%s; %s = lineno; (void)%s; %s}" % (
+            Naming.filename_cname, Naming.filetable_cname, Naming.filename_cname,
+            Naming.lineno_cname, Naming.lineno_cname,
+            cinfo
+        ))
+        code.putln("#define __PYX_ERR(f_index, lineno, Ln_error) \\")
+        code.putln("    { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; }")
 
         code.putln("")
         self.generate_extern_c_macro_definition(code)
@@ -2293,7 +2296,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         code.exit_cfunc_scope()  # done with labels
 
     def generate_module_init_func(self, imported_modules, env, code):
-        subfunction = self.mod_init_subfunction(self.scope, code)
+        subfunction = self.mod_init_subfunction(self.pos, self.scope, code)
 
         code.enter_cfunc_scope(self.scope)
         code.putln("")
@@ -2419,10 +2422,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
 
         if Options.cache_builtins:
             code.putln("/*--- Builtin init code ---*/")
-            code.put_error_if_neg(None, "__Pyx_InitCachedBuiltins()")
+            code.put_error_if_neg(self.pos, "__Pyx_InitCachedBuiltins()")
 
         code.putln("/*--- Constants init code ---*/")
-        code.put_error_if_neg(None, "__Pyx_InitCachedConstants()")
+        code.put_error_if_neg(self.pos, "__Pyx_InitCachedConstants()")
 
         code.putln("/*--- Global type/function init code ---*/")
 
@@ -2513,7 +2516,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
 
         code.exit_cfunc_scope()
 
-    def mod_init_subfunction(self, scope, orig_code):
+    def mod_init_subfunction(self, pos, scope, orig_code):
         """
         Return a context manager that allows deviating the module init code generation
         into a separate function and instead inserts a call to it.
@@ -2569,9 +2572,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 code.putln("")
 
                 if needs_error_handling:
-                    self.call_code.use_label(orig_code.error_label)
-                    self.call_code.putln("if (unlikely(%s() != 0)) goto %s;" % (
-                        self.cfunc_name, orig_code.error_label))
+                    self.call_code.putln(
+                        self.call_code.error_goto_if_neg("%s()" % self.cfunc_name, pos))
                 else:
                     self.call_code.putln("(void)%s();" % self.cfunc_name)
                 self.call_code = None
index 96155b619e6347024dcd3ae29c4a7a11eb5522e2..a43c03a42b946c1765a8a4f28e68eea63048903b 100644 (file)
@@ -4292,10 +4292,10 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
         return self.visit_BinopNode(node)
 
     _parse_string_format_regex = (
-        u'(%(?:'            # %...
-        u'(?:[0-9]+|[ ])?'  # width (optional) or space prefix fill character (optional)
-        u'(?:[.][0-9]+)?'   # precision (optional)
-        u')?.)'             # format type (or something different for unsupported formats)
+        u'(%(?:'              # %...
+        u'(?:[-0-9]+|[ ])?'   # width (optional) or space prefix fill character (optional)
+        u'(?:[.][0-9]+)?'     # precision (optional)
+        u')?.)'               # format type (or something different for unsupported formats)
     )
 
     def _build_fstring(self, pos, ustring, format_args):
@@ -4327,14 +4327,25 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
                 break
             if format_type in u'asrfdoxX':
                 format_spec = s[1:]
+                conversion_char = None
                 if format_type in u'doxX' and u'.' in format_spec:
                     # Precision is not allowed for integers in format(), but ok in %-formatting.
                     can_be_optimised = False
                 elif format_type in u'ars':
                     format_spec = format_spec[:-1]
+                    conversion_char = format_type
+                    if format_spec.startswith('0'):
+                        format_spec = '>' + format_spec[1:]  # right-alignment '%05s' spells '{:>5}'
+                elif format_type == u'd':
+                    # '%d' formatting supports float, but '{obj:d}' does not => convert to int first.
+                    conversion_char = 'd'
+
+                if format_spec.startswith('-'):
+                    format_spec = '<' + format_spec[1:]  # left-alignment '%-5s' spells '{:<5}'
+
                 substrings.append(ExprNodes.FormattedValueNode(
                     arg.pos, value=arg,
-                    conversion_char=format_type if format_type in u'ars' else None,
+                    conversion_char=conversion_char,
                     format_spec=ExprNodes.UnicodeNode(
                         pos, value=EncodedString(format_spec), constant_result=format_spec)
                         if format_spec else None,
index ad6a5cf140614b83c63ed8e98c3cf525dd25b13e..e7a33341b0a60ddb9e29883d5ae36dfc4167b41a 100644 (file)
@@ -1161,6 +1161,7 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations):
     def visit_CallNode(self, node):
         self.visit(node.function)
         if not self.parallel_directive:
+            self.visitchildren(node, exclude=('function',))
             return node
 
         # We are a parallel directive, replace this node with the
index 56884f0a29d4c0a33601b8271bd69edd839393bc..fd19d6c8e0882ddcb85951db225d5e37fc836d68 100644 (file)
@@ -2237,7 +2237,7 @@ def p_statement(s, ctx, first_statement = 0):
             s.error('decorator not allowed here')
         s.level = ctx.level
         decorators = p_decorators(s)
-        if not ctx.allow_struct_enum_decorator and s.sy not in ('def', 'cdef', 'cpdef', 'class'):
+        if not ctx.allow_struct_enum_decorator and s.sy not in ('def', 'cdef', 'cpdef', 'class', 'async'):
             if s.sy == 'IDENT' and s.systring == 'async':
                 pass  # handled below
             else:
index 2b604bd27760ff315e2e6ebbf3f102da94237204..b998d350f4e8ea13bd158253112a2322d557256d 100644 (file)
@@ -4034,6 +4034,9 @@ class CTupleType(CType):
         env.use_utility_code(self._convert_from_py_code)
         return True
 
+    def cast_code(self, expr_code):
+        return expr_code
+
 
 def c_tuple_type(components):
     components = tuple(components)
index 21b456816f0a2e64102fd6f5657a3bdf9c3ae697..f61144033cb74cf577f079ad35417c97970aff19 100644 (file)
@@ -41,8 +41,8 @@ py_reserved_words = [
     "global", "nonlocal", "def", "class", "print", "del", "pass", "break",
     "continue", "return", "raise", "import", "exec", "try",
     "except", "finally", "while", "if", "elif", "else", "for",
-    "in", "assert", "and", "or", "not", "is", "in", "lambda",
-    "from", "yield", "with", "nonlocal",
+    "in", "assert", "and", "or", "not", "is", "lambda",
+    "from", "yield", "with",
 ]
 
 pyx_reserved_words = py_reserved_words + [
index 882f72666b1182d0d671b2f869d75dbd5c20f7b1..aa2a1cf2292869f5023f5007086dd21a613d7507 100644 (file)
@@ -84,9 +84,9 @@ class old_build_ext(_build_ext.build_ext):
     description = "build C/C++ and Cython extensions (compile/link to build directory)"
 
     sep_by = _build_ext.build_ext.sep_by
-    user_options = _build_ext.build_ext.user_options
-    boolean_options = _build_ext.build_ext.boolean_options
-    help_options = _build_ext.build_ext.help_options
+    user_options = _build_ext.build_ext.user_options[:]
+    boolean_options = _build_ext.build_ext.boolean_options[:]
+    help_options = _build_ext.build_ext.help_options[:]
 
     # Add the pyrex specific data.
     user_options.extend([
index 3d561f046eb5d7cb69110d020882f29ead25c138..cd0f90719bd65bef1461ac37ce378d196db6eb4a 100644 (file)
@@ -90,9 +90,9 @@ cdef extern from "datetime.h":
     int PyDateTime_TIME_GET_MICROSECOND(object o)
 
     # Getters for timedelta (C macros).
-    #int PyDateTime_DELTA_GET_DAYS(object o)
-    #int PyDateTime_DELTA_GET_SECONDS(object o)
-    #int PyDateTime_DELTA_GET_MICROSECONDS(object o)
+    int PyDateTime_DELTA_GET_DAYS(object o)
+    int PyDateTime_DELTA_GET_SECONDS(object o)
+    int PyDateTime_DELTA_GET_MICROSECONDS(object o)
 
     # PyDateTime CAPI object.
     PyDateTime_CAPI *PyDateTimeAPI
index 789669dac13f189c74738f66bfa26cde466a8e57..15c070263def1ed025c848ba7d88f1f0f699b232 100644 (file)
@@ -341,7 +341,6 @@ cdef extern from "numpy/arrayobject.h":
                 PyObject_Free(info.strides)
                 # info.shape was stored after info.strides in the same block
 
-
     ctypedef unsigned char      npy_bool
 
     ctypedef signed char      npy_byte
@@ -686,7 +685,7 @@ cdef extern from "numpy/arrayobject.h":
     object PyArray_Choose (ndarray, object, ndarray, NPY_CLIPMODE)
     int PyArray_Sort (ndarray, int, NPY_SORTKIND)
     object PyArray_ArgSort (ndarray, int, NPY_SORTKIND)
-    object PyArray_SearchSorted (ndarray, object, NPY_SEARCHSIDE)
+    object PyArray_SearchSorted (ndarray, object, NPY_SEARCHSIDE, PyObject*)
     object PyArray_ArgMax (ndarray, int, ndarray)
     object PyArray_ArgMin (ndarray, int, ndarray)
     object PyArray_Reshape (ndarray, object)
index 96d9e3984c7c8a7932f5c98df42600296c1f5d64..5d8d628d5691eecb6540211ba6eb0f0be390ebfc 100644 (file)
@@ -1,7 +1,7 @@
 # cython.* namespace for pure mode.
 from __future__ import absolute_import
 
-__version__ = "0.29.17"
+__version__ = "0.29.19"
 
 try:
     from __builtin__ import basestring
index 68a600d0c7bc2e98ef2f5fc623da8b6166c86894..3c7105fa35615d5899f23a6d3bac5b46a0328f39 100644 (file)
@@ -602,9 +602,8 @@ static PyObject *
 __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp)
 {
     const char *ts = *tsp;
-    int i = 0, number;
-    int ndim = ctx->head->field->type->ndim;
-;
+    int i = 0, number, ndim;
+
     ++ts;
     if (ctx->new_count != 1) {
         PyErr_SetString(PyExc_ValueError,
@@ -615,6 +614,9 @@ __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp)
     /* Process the previous element */
     if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
 
+    // store ndim now, as field advanced by __Pyx_BufFmt_ProcessTypeChunk call
+    ndim = ctx->head->field->type->ndim;
+
     /* Parse all numbers in the format string */
     while (*ts && *ts != ')') {
         // ignore space characters (not using isspace() due to C/C++ problem on MacOS-X)
@@ -757,8 +759,8 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha
       case 'l': case 'L': case 'q': case 'Q':
       case 'f': case 'd': case 'g':
       case 'O': case 'p':
-        if (ctx->enc_type == *ts && got_Z == ctx->is_complex &&
-            ctx->enc_packmode == ctx->new_packmode) {
+        if ((ctx->enc_type == *ts) && (got_Z == ctx->is_complex) &&
+            (ctx->enc_packmode == ctx->new_packmode) && (!ctx->is_valid_array)) {
           /* Continue pooling same type */
           ctx->enc_count += ctx->new_count;
           ctx->new_count = 1;
index 5c700cf9314de75e9a8032142e3fa3999f204e31..1b39c9e42d308f5675fd397000c1a04ffa789c8a 100644 (file)
@@ -55,20 +55,65 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) {
     }
 
 #if PY_VERSION_HEX >= 0x03050000
-    // As of https://bugs.python.org/issue22079
-    // PyType_Ready enforces that all bases of a non-heap type are
-    // non-heap. We know that this is the case for the solid base but
-    // other bases are heap allocated and are kept alive through the
-    // tp_bases reference.
-    // Other than this check, the Py_TPFLAGS_HEAPTYPE flag is unused
-    // in PyType_Ready().
-    t->tp_flags |= Py_TPFLAGS_HEAPTYPE;
+    {
+        // Make sure GC does not pick up our non-heap type as heap type with this hack!
+        // For details, see https://github.com/cython/cython/issues/3603
+        PyObject *ret, *py_status;
+        int gc_was_enabled;
+        PyObject *gc = PyImport_Import(PYUNICODE("gc"));
+        if (unlikely(!gc)) return -1;
+        py_status = PyObject_CallMethodObjArgs(gc, PYUNICODE("isenabled"), NULL);
+        if (unlikely(!py_status)) {
+            Py_DECREF(gc);
+            return -1;
+        }
+        gc_was_enabled = __Pyx_PyObject_IsTrue(py_status);
+        Py_DECREF(py_status);
+        if (gc_was_enabled > 0) {
+            ret = PyObject_CallMethodObjArgs(gc, PYUNICODE("disable"), NULL);
+            if (unlikely(!ret)) {
+                Py_DECREF(gc);
+                return -1;
+            }
+            Py_DECREF(ret);
+        } else if (unlikely(gc_was_enabled == -1)) {
+            Py_DECREF(gc);
+            return -1;
+        }
+
+        // As of https://bugs.python.org/issue22079
+        // PyType_Ready enforces that all bases of a non-heap type are
+        // non-heap. We know that this is the case for the solid base but
+        // other bases are heap allocated and are kept alive through the
+        // tp_bases reference.
+        // Other than this check, the Py_TPFLAGS_HEAPTYPE flag is unused
+        // in PyType_Ready().
+        t->tp_flags |= Py_TPFLAGS_HEAPTYPE;
 #endif
 
     r = PyType_Ready(t);
 
 #if PY_VERSION_HEX >= 0x03050000
-    t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE;
+        t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE;
+
+        if (gc_was_enabled) {
+            PyObject *t, *v, *tb;
+            PyErr_Fetch(&t, &v, &tb);
+            ret = PyObject_CallMethodObjArgs(gc, PYUNICODE("enable"), NULL);
+            if (likely(ret || r == -1)) {
+                Py_XDECREF(ret);
+                // do not overwrite exceptions raised by PyType_Ready() above
+                PyErr_Restore(t, v, tb);
+            } else {
+                // PyType_Ready() succeeded, but gc.enable() failed.
+                Py_XDECREF(t);
+                Py_XDECREF(v);
+                Py_XDECREF(tb);
+                r = -1;
+            }
+        }
+        Py_DECREF(gc);
+    }
 #endif
 
     return r;
index 2419bc04beb607926629ea6236bfc45b982f1613..9f4828d1fe05d5b01598c154f1b5fd321cf461ff 100644 (file)
@@ -181,13 +181,13 @@ __pyx_check_strides(Py_buffer *buf, int dim, int ndim, int spec)
     if (buf->strides) {
         if (spec & __Pyx_MEMVIEW_CONTIG) {
             if (spec & (__Pyx_MEMVIEW_PTR|__Pyx_MEMVIEW_FULL)) {
-                if (buf->strides[dim] != sizeof(void *)) {
+                if (unlikely(buf->strides[dim] != sizeof(void *))) {
                     PyErr_Format(PyExc_ValueError,
                                  "Buffer is not indirectly contiguous "
                                  "in dimension %d.", dim);
                     goto fail;
                 }
-            } else if (buf->strides[dim] != buf->itemsize) {
+            } else if (unlikely(buf->strides[dim] != buf->itemsize)) {
                 PyErr_SetString(PyExc_ValueError,
                                 "Buffer and memoryview are not contiguous "
                                 "in the same dimension.");
@@ -199,7 +199,7 @@ __pyx_check_strides(Py_buffer *buf, int dim, int ndim, int spec)
             Py_ssize_t stride = buf->strides[dim];
             if (stride < 0)
                 stride = -stride;
-            if (stride < buf->itemsize) {
+            if (unlikely(stride < buf->itemsize)) {
                 PyErr_SetString(PyExc_ValueError,
                                 "Buffer and memoryview are not contiguous "
                                 "in the same dimension.");
@@ -207,17 +207,17 @@ __pyx_check_strides(Py_buffer *buf, int dim, int ndim, int spec)
             }
         }
     } else {
-        if (spec & __Pyx_MEMVIEW_CONTIG && dim != ndim - 1) {
+        if (unlikely(spec & __Pyx_MEMVIEW_CONTIG && dim != ndim - 1)) {
             PyErr_Format(PyExc_ValueError,
                          "C-contiguous buffer is not contiguous in "
                          "dimension %d", dim);
             goto fail;
-        } else if (spec & (__Pyx_MEMVIEW_PTR)) {
+        } else if (unlikely(spec & (__Pyx_MEMVIEW_PTR))) {
             PyErr_Format(PyExc_ValueError,
                          "C-contiguous buffer is not indirect in "
                          "dimension %d", dim);
             goto fail;
-        } else if (buf->suboffsets) {
+        } else if (unlikely(buf->suboffsets)) {
             PyErr_SetString(PyExc_ValueError,
                             "Buffer exposes suboffsets but no strides");
             goto fail;
@@ -235,7 +235,7 @@ __pyx_check_suboffsets(Py_buffer *buf, int dim, CYTHON_UNUSED int ndim, int spec
     // Todo: without PyBUF_INDIRECT we may not have suboffset information, i.e., the
     //       ptr may not be set to NULL but may be uninitialized?
     if (spec & __Pyx_MEMVIEW_DIRECT) {
-        if (buf->suboffsets && buf->suboffsets[dim] >= 0) {
+        if (unlikely(buf->suboffsets && buf->suboffsets[dim] >= 0)) {
             PyErr_Format(PyExc_ValueError,
                          "Buffer not compatible with direct access "
                          "in dimension %d.", dim);
@@ -244,7 +244,7 @@ __pyx_check_suboffsets(Py_buffer *buf, int dim, CYTHON_UNUSED int ndim, int spec
     }
 
     if (spec & __Pyx_MEMVIEW_PTR) {
-        if (!buf->suboffsets || (buf->suboffsets[dim] < 0)) {
+        if (unlikely(!buf->suboffsets || (buf->suboffsets[dim] < 0))) {
             PyErr_Format(PyExc_ValueError,
                          "Buffer is not indirectly accessible "
                          "in dimension %d.", dim);
@@ -265,9 +265,7 @@ __pyx_verify_contig(Py_buffer *buf, int ndim, int c_or_f_flag)
     if (c_or_f_flag & __Pyx_IS_F_CONTIG) {
         Py_ssize_t stride = 1;
         for (i = 0; i < ndim; i++) {
-            if (stride * buf->itemsize != buf->strides[i] &&
-                    buf->shape[i] > 1)
-            {
+            if (unlikely(stride * buf->itemsize != buf->strides[i]  &&  buf->shape[i] > 1)) {
                 PyErr_SetString(PyExc_ValueError,
                     "Buffer not fortran contiguous.");
                 goto fail;
@@ -277,8 +275,7 @@ __pyx_verify_contig(Py_buffer *buf, int ndim, int c_or_f_flag)
     } else if (c_or_f_flag & __Pyx_IS_C_CONTIG) {
         Py_ssize_t stride = 1;
         for (i = ndim - 1; i >- 1; i--) {
-            if (stride * buf->itemsize != buf->strides[i] &&
-                    buf->shape[i] > 1) {
+            if (unlikely(stride * buf->itemsize != buf->strides[i]  &&  buf->shape[i] > 1)) {
                 PyErr_SetString(PyExc_ValueError,
                     "Buffer not C contiguous.");
                 goto fail;
@@ -325,7 +322,7 @@ static int __Pyx_ValidateAndInit_memviewslice(
     }
 
     buf = &memview->view;
-    if (buf->ndim != ndim) {
+    if (unlikely(buf->ndim != ndim)) {
         PyErr_Format(PyExc_ValueError,
                 "Buffer has wrong number of dimensions (expected %d, got %d)",
                 ndim, buf->ndim);
@@ -334,10 +331,10 @@ static int __Pyx_ValidateAndInit_memviewslice(
 
     if (new_memview) {
         __Pyx_BufFmt_Init(&ctx, stack, dtype);
-        if (!__Pyx_BufFmt_CheckString(&ctx, buf->format)) goto fail;
+        if (unlikely(!__Pyx_BufFmt_CheckString(&ctx, buf->format))) goto fail;
     }
 
-    if ((unsigned) buf->itemsize != dtype->size) {
+    if (unlikely((unsigned) buf->itemsize != dtype->size)) {
         PyErr_Format(PyExc_ValueError,
                      "Item size of buffer (%" CYTHON_FORMAT_SSIZE_T "u byte%s) "
                      "does not match size of '%s' (%" CYTHON_FORMAT_SSIZE_T "u byte%s)",
@@ -352,14 +349,14 @@ static int __Pyx_ValidateAndInit_memviewslice(
     /* Check axes */
     for (i = 0; i < ndim; i++) {
         spec = axes_specs[i];
-        if (!__pyx_check_strides(buf, i, ndim, spec))
+        if (unlikely(!__pyx_check_strides(buf, i, ndim, spec)))
             goto fail;
-        if (!__pyx_check_suboffsets(buf, i, ndim, spec))
+        if (unlikely(!__pyx_check_suboffsets(buf, i, ndim, spec)))
             goto fail;
     }
 
     /* Check contiguity */
-    if (buf->strides && !__pyx_verify_contig(buf, ndim, c_or_f_flag))
+    if (unlikely(buf->strides && !__pyx_verify_contig(buf, ndim, c_or_f_flag)))
         goto fail;
 
     /* Initialize */
@@ -394,7 +391,7 @@ __Pyx_init_memviewslice(struct __pyx_memoryview_obj *memview,
     Py_buffer *buf = &memview->view;
     __Pyx_RefNannySetupContext("init_memviewslice", 0);
 
-    if (memviewslice->memview || memviewslice->data) {
+    if (unlikely(memviewslice->memview || memviewslice->data)) {
         PyErr_SetString(PyExc_ValueError,
             "memviewslice is already initialized!");
         goto fail;
@@ -488,16 +485,16 @@ __Pyx_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil, int lineno)
 {
     int first_time;
     struct {{memview_struct_name}} *memview = memslice->memview;
-    if (!memview || (PyObject *) memview == Py_None)
+    if (unlikely(!memview || (PyObject *) memview == Py_None))
         return; /* allow uninitialized memoryview assignment */
 
-    if (__pyx_get_slice_count(memview) < 0)
+    if (unlikely(__pyx_get_slice_count(memview) < 0))
         __pyx_fatalerror("Acquisition count is %d (line %d)",
                          __pyx_get_slice_count(memview), lineno);
 
     first_time = __pyx_add_acquisition_count(memview) == 0;
 
-    if (first_time) {
+    if (unlikely(first_time)) {
         if (have_gil) {
             Py_INCREF((PyObject *) memview);
         } else {
@@ -513,20 +510,20 @@ static CYTHON_INLINE void __Pyx_XDEC_MEMVIEW({{memviewslice_name}} *memslice,
     int last_time;
     struct {{memview_struct_name}} *memview = memslice->memview;
 
-    if (!memview ) {
-        return;
-    } else if ((PyObject *) memview == Py_None) {
+    if (unlikely(!memview || (PyObject *) memview == Py_None)) {
+        // we do not ref-count None
         memslice->memview = NULL;
         return;
     }
 
-    if (__pyx_get_slice_count(memview) <= 0)
+    if (unlikely(__pyx_get_slice_count(memview) <= 0))
         __pyx_fatalerror("Acquisition count is %d (line %d)",
                          __pyx_get_slice_count(memview), lineno);
 
     last_time = __pyx_sub_acquisition_count(memview) == 1;
     memslice->data = NULL;
-    if (last_time) {
+
+    if (unlikely(last_time)) {
         if (have_gil) {
             Py_CLEAR(memslice->memview);
         } else {
@@ -570,7 +567,7 @@ __pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs,
     __Pyx_RefNannySetupContext("__pyx_memoryview_copy_new_contig", 0);
 
     for (i = 0; i < ndim; i++) {
-        if (from_mvs->suboffsets[i] >= 0) {
+        if (unlikely(from_mvs->suboffsets[i] >= 0)) {
             PyErr_Format(PyExc_ValueError, "Cannot copy memoryview slice with "
                                            "indirect dimensions (axis %d)", i);
             goto fail;
@@ -860,7 +857,7 @@ if (unlikely(__pyx_memoryview_slice_memviewslice(
     {{endif}}
 
     {{if boundscheck}}
-        if (!__Pyx_is_valid_index(__pyx_tmp_idx, __pyx_tmp_shape)) {
+        if (unlikely(!__Pyx_is_valid_index(__pyx_tmp_idx, __pyx_tmp_shape))) {
             {{if not have_gil}}
                 #ifdef WITH_THREAD
                 PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();
@@ -878,9 +875,6 @@ if (unlikely(__pyx_memoryview_slice_memviewslice(
 
             {{error_goto}}
         }
-    {{else}}
-        // make sure label is not un-used
-        if ((0)) {{error_goto}}
     {{endif}}
 
     {{if all_dimensions_direct}}
index 56ba118a20a8d1d442f6be881fe84e57b5d52ea6..40901859b86603acca63075ee7e32216ac1019c7 100644 (file)
@@ -695,24 +695,24 @@ static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) {
 
 /////////////// PyModInitFuncType.proto ///////////////
 
-#if PY_MAJOR_VERSION < 3
+#ifndef CYTHON_NO_PYINIT_EXPORT
+#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC
 
-#ifdef CYTHON_NO_PYINIT_EXPORT
-// define this to void manually because PyMODINIT_FUNC adds __declspec(dllexport) to it's definition.
-#define __Pyx_PyMODINIT_FUNC void
+#elif PY_MAJOR_VERSION < 3
+// Py2: define this to void manually because PyMODINIT_FUNC adds __declspec(dllexport) to it's definition.
+#ifdef __cplusplus
+#define __Pyx_PyMODINIT_FUNC extern "C" void
 #else
-#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC
+#define __Pyx_PyMODINIT_FUNC void
 #endif
 
 #else
-
-#ifdef CYTHON_NO_PYINIT_EXPORT
-// define this to PyObject * manually because PyMODINIT_FUNC adds __declspec(dllexport) to it's definition.
-#define __Pyx_PyMODINIT_FUNC PyObject *
+// Py3+: define this to PyObject * manually because PyMODINIT_FUNC adds __declspec(dllexport) to it's definition.
+#ifdef __cplusplus
+#define __Pyx_PyMODINIT_FUNC extern "C" PyObject *
 #else
-#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC
+#define __Pyx_PyMODINIT_FUNC PyObject *
 #endif
-
 #endif
 
 
index 3b4d8adfb63d16e2d2e8e353bba0b8a3f9a70a7b..c9ffdec35c25bd9a92b0602a331010519b43a12d 100755 (executable)
@@ -21,6 +21,7 @@ import warnings
 import zlib
 import glob
 from contextlib import contextmanager
+from collections import defaultdict
 
 try:
     import platform
@@ -46,26 +47,6 @@ try:
 except ImportError: # No threads, no problems
     threading = None
 
-try:
-    from collections import defaultdict
-except ImportError:
-    class defaultdict(object):
-        def __init__(self, default_factory=lambda : None):
-            self._dict = {}
-            self.default_factory = default_factory
-        def __getitem__(self, key):
-            if key not in self._dict:
-                self._dict[key] = self.default_factory()
-            return self._dict[key]
-        def __setitem__(self, key, value):
-            self._dict[key] = value
-        def __contains__(self, key):
-            return key in self._dict
-        def __repr__(self):
-            return repr(self._dict)
-        def __nonzero__(self):
-            return bool(self._dict)
-
 try:
     from unittest import SkipTest
 except ImportError:
@@ -2434,8 +2415,9 @@ def runtests(options, cmd_args, coverage=None):
                                 options.pythran_dir, add_embedded_test=True, stats=stats)
         test_suite.addTest(filetests.build_suite())
     if options.examples and languages:
+        examples_workdir = os.path.join(WORKDIR, 'examples')
         for subdirectory in glob.glob(os.path.join(options.examples_dir, "*/")):
-            filetests = TestBuilder(subdirectory, WORKDIR, selectors, exclude_selectors,
+            filetests = TestBuilder(subdirectory, examples_workdir, selectors, exclude_selectors,
                                     options, options.pyregr, languages, test_bugs,
                                     options.language_level, common_utility_dir,
                                     options.pythran_dir,
index 851193f3f844d0fcf6e6ed762c804a7aa0ff9115..eba10020d720445b156ee47da526375a4217ef4e 100644 (file)
@@ -1,4 +1,5 @@
 from __future__ import unicode_literals
+import struct
 
 # Tests buffer format string parsing.
 
@@ -406,6 +407,62 @@ def packed_struct_with_strings(fmt):
         fmt, sizeof(PackedStructWithCharArrays))
 
 
+ctypedef struct PackedStructWithArrays:
+    double a[16]
+    double b[16]
+    double c
+
+ctypedef struct UnpackedStructWithArrays:
+    int a
+    float b[8]
+    float c
+    unsigned long long d
+    int e[5]
+    int f
+    int g
+    double h[4]
+    int i
+
+ctypedef struct PackedStructWithNDArrays:
+    double a
+    double b[2][2]
+    float c
+    float d
+
+
+@testcase
+def packed_struct_with_arrays(fmt):
+    """
+    >>> packed_struct_with_arrays("T{(16)d:a:(16)d:b:d:c:}")
+    """
+
+    cdef object[PackedStructWithArrays] buf = MockBuffer(
+        fmt, sizeof(PackedStructWithArrays))
+
+
+@testcase
+def unpacked_struct_with_arrays(fmt):
+    """
+    >>> if struct.calcsize('P') == 8:  # 64 bit
+    ...     unpacked_struct_with_arrays("T{i:a:(8)f:b:f:c:Q:d:(5)i:e:i:f:i:g:xxxx(4)d:h:i:i:}")
+    ... elif struct.calcsize('P') == 4:  # 32 bit
+    ...     unpacked_struct_with_arrays("T{i:a:(8)f:b:f:c:Q:d:(5)i:e:i:f:i:g:(4)d:h:i:i:}")
+    """
+
+    cdef object[UnpackedStructWithArrays] buf = MockBuffer(
+        fmt, sizeof(UnpackedStructWithArrays))
+
+
+@testcase
+def packed_struct_with_ndarrays(fmt):
+    """
+    >>> packed_struct_with_ndarrays("T{d:a:(2,2)d:b:f:c:f:d:}")
+    """
+
+    cdef object[PackedStructWithNDArrays] buf = MockBuffer(
+        fmt, sizeof(PackedStructWithNDArrays))
+
+
 # TODO: empty struct
 # TODO: Incomplete structs
 # TODO: mixed structs
index f0c4f54783b2a44ec1addf2c7829e1520f573c8f..09395cc5199c3051572b59b86f8654457d168dc6 100644 (file)
@@ -43,9 +43,7 @@ cdef class MockBuffer:
         if strides is None:
             strides = []
             cumprod = 1
-            rshape = list(shape)
-            rshape.reverse()
-            for s in rshape:
+            for s in shape[::-1]:
                 strides.append(cumprod)
                 cumprod *= s
             strides.reverse()
index cf9e92971c9f0a2fd4c20189354742684d50bf9e..9b18be6153765aaae917c8e601ab88791668896b 100644 (file)
@@ -718,3 +718,42 @@ def test_boundscheck_and_wraparound(double[:, :] x):
         x[i]
         x[i, ...]
         x[i, :]
+
+
+ctypedef struct SameTypeAfterArraysStructSimple:
+    double a[16]
+    double b[16]
+    double c
+
+@testcase
+def same_type_after_arrays_simple():
+    """
+    >>> same_type_after_arrays_simple()
+    """
+
+    cdef SameTypeAfterArraysStructSimple element
+    arr = np.ones(2, np.asarray(<SameTypeAfterArraysStructSimple[:1]>&element).dtype)
+    cdef SameTypeAfterArraysStructSimple[:] memview = arr
+
+
+ctypedef struct SameTypeAfterArraysStructComposite:
+    int a
+    float b[8]
+    float c
+    unsigned long d
+    int e[5]
+    int f
+    int g
+    double h[4]
+    int i
+
+@testcase
+def same_type_after_arrays_composite():
+    """
+    >>> same_type_after_arrays_composite() if sys.version_info[:2] >= (3, 5) else None
+    >>> same_type_after_arrays_composite() if sys.version_info[:2] == (2, 7) else None
+    """
+
+    cdef SameTypeAfterArraysStructComposite element
+    arr = np.ones(2, np.asarray(<SameTypeAfterArraysStructComposite[:1]>&element).dtype)
+    cdef SameTypeAfterArraysStructComposite[:] memview = arr
index ac0b8a516b13edf00256ab141e42d60d0e7ec01e..64b5af48647d6dfc61a5d6a2d34185d6563e1166 100644 (file)
@@ -1,4 +1,4 @@
-# cython: language_level=3, binding=True
+# cython: language_level=3str, binding=True
 # mode: run
 # tag: pep492, await, gh3337
 
@@ -33,3 +33,30 @@ async def test_async_temp_gh3337(x, y):
     ([], 0)
     """
     return min(x - y, 0)
+
+
+async def outer_with_nested(called):
+    """
+    >>> called = []
+    >>> _, inner = run_async(outer_with_nested(called))
+    >>> called  # after outer_with_nested()
+    ['outer', 'make inner', 'deco', 'return inner']
+    >>> _ = run_async(inner())
+    >>> called  # after inner()
+    ['outer', 'make inner', 'deco', 'return inner', 'inner']
+    """
+    called.append('outer')
+
+    def deco(f):
+        called.append('deco')
+        return f
+
+    called.append('make inner')
+
+    @deco
+    async def inner():
+        called.append('inner')
+        return 1
+
+    called.append('return inner')
+    return inner
index 12410f38306cf38b636ea66570117750476d135b..45bfaf5e37495a5e234c94f91c4553327e0ae8d0 100644 (file)
@@ -474,31 +474,35 @@ def format_decoded_bytes(bytes value):
     "//FormattedValueNode",
     "//JoinedStrNode",
 )
-def generated_fstring(int i, unicode u not None, o):
+def generated_fstring(int i, float f, unicode u not None, o):
     """
-    >>> i, u, o = 11, u'xyz', [1]
+    >>> i, f, u, o = 11, 1.3125, u'xyz', [1]
     >>> print(((
-    ...     u"(i) %s-%.3s-%r-%.3r-%d-%3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
-    ...     u"(u) %s-%.2s-%r-%.7r %% "
-    ...     u"(o) %s-%.2s-%r-%.2r"
+    ...     u"(i) %s-%.3s-%r-%.3r-%d-%3d-%-3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
+    ...     u"(u) %s-%.2s-%r-%.7r-%05s-%-5s %% "
+    ...     u"(o) %s-%.2s-%r-%.2r %% "
+    ...     u"(f) %.2f-%d"
     ... ) % (
-    ...     i, i, i, i, i, i, i, i, i, i, i, i, i, i,
-    ...     u, u, u, u,
+    ...     i, i, i, i, i, i, i, i, i, i, i, i, i, i, i,
+    ...     u, u, u, u, u, u,
     ...     o, o, o, o,
+    ...     f, f,
     ... )).replace("-u'xyz'", "-'xyz'"))
-    (i) 11-11-11-11-11- 11-13-0013-b-   b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz' % (o) [1]-[1-[1]-[1
+    (i) 11-11-11-11-11- 11-11 -13-0013-b-   b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz'-  xyz-xyz   % (o) [1]-[1-[1]-[1 % (f) 1.31-1
 
-    >>> print(generated_fstring(i, u, o).replace("-u'xyz'", "-'xyz'"))
-    (i) 11-11-11-11-11- 11-13-0013-b-   b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz' % (o) [1]-[1-[1]-[1
+    >>> print(generated_fstring(i, f, u, o).replace("-u'xyz'", "-'xyz'"))
+    (i) 11-11-11-11-11- 11-11 -13-0013-b-   b-B-00B-11.0-11.00 % (u) xyz-xy-'xyz'-'xyz'-  xyz-xyz   % (o) [1]-[1-[1]-[1 % (f) 1.31-1
     """
     return (
-        u"(i) %s-%.3s-%r-%.3r-%d-%3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
-        u"(u) %s-%.2s-%r-%.7r %% "
-        u"(o) %s-%.2s-%r-%.2r"
+        u"(i) %s-%.3s-%r-%.3r-%d-%3d-%-3d-%o-%04o-%x-%4x-%X-%03X-%.1f-%04.2f %% "
+        u"(u) %s-%.2s-%r-%.7r-%05s-%-5s %% "
+        u"(o) %s-%.2s-%r-%.2r %% "
+        u"(f) %.2f-%d"
     ) % (
-        i, i, i, i, i, i, i, i, i, i, i, i, i, i,
-        u, u, u, u,
+        i, i, i, i, i, i, i, i, i, i, i, i, i, i, i,
+        u, u, u, u, u, u,
         o, o, o, o,
+        f, f,
     )
 
 
index 59f020115736afe7e4eeffa8b40c31e859cf08c3..615bf701a702a7840c1b786c5359121b76b79f4d 100644 (file)
@@ -1,9 +1,9 @@
 # hack to avoid C compiler warnings about unused functions in the NumPy header files
 
+from numpy cimport import_array  # , import_umath
+
 cdef extern from *:
    bint FALSE "0"
-   void import_array()
-#   void import_umath()
 
 if FALSE:
     import_array()
index 40e3476b5827a0f8c13d7aac564c1e548d7f1c22..662dd4ad0d4336c19d689d1fd042d5dda284b411 100644 (file)
@@ -7,6 +7,9 @@ cimport cython
 import re
 import sys
 
+# initialise NumPy C-API
+np.import_array()
+
 
 def little_endian():
     cdef int endian_detector = 1
@@ -182,7 +185,7 @@ try:
             ('a', np.dtype('i,i')),\
             ('b', np.dtype('i,i'))\
         ]))))                              # doctest: +NORMALIZE_WHITESPACE
-    array([((0, 0), (0, 0)), ((1, 2), (1, 4)), ((1, 2), (1, 4))], 
+    array([((0, 0), (0, 0)), ((1, 2), (1, 4)), ((1, 2), (1, 4))],
           dtype=[('a', [('f0', '!i4'), ('f1', '!i4')]), ('b', [('f0', '!i4'), ('f1', '!i4')])])
 
     >>> print(test_nested_dtypes(np.zeros((3,), dtype=np.dtype([\
@@ -235,7 +238,7 @@ try:
     8,16
 
     >>> test_point_record()         # doctest: +NORMALIZE_WHITESPACE
-    array([(0., 0.), (1., -1.), (2., -2.)], 
+    array([(0., 0.), (1., -1.), (2., -2.)],
           dtype=[('x', '!f8'), ('y', '!f8')])
 
 """
@@ -947,4 +950,16 @@ def test_broadcast_comparison(np.ndarray[double, ndim=1] a):
     return a == 0, obj == 0, a == 1, obj == 1
 
 
-include "numpy_common.pxi"
+@testcase
+def test_c_api_searchsorted(np.ndarray arr, other):
+    """
+    >>> arr = np.random.randn(10)
+    >>> other = np.random.randn(5)
+    >>> result, expected = test_c_api_searchsorted(arr, other)
+    >>> (result == expected).all()
+    True
+    """
+    result = np.PyArray_SearchSorted(arr, other, np.NPY_SEARCHRIGHT, NULL)
+
+    expected = arr.searchsorted(other, side="right")
+    return result, expected
index c3526556f0f2d1905f4ed49e5d61c892333d699a..c3739b10bcebdbf831df4f0b616f21af47e6625c 100644 (file)
@@ -8,6 +8,9 @@ from libc.stdlib cimport malloc, free
 
 openmp.omp_set_nested(1)
 
+cdef int forward(int x) nogil:
+    return x
+
 def test_parallel():
     """
     >>> test_parallel()
@@ -20,6 +23,9 @@ def test_parallel():
 
     with nogil, cython.parallel.parallel():
         buf[threadid()] = threadid()
+        # Recognise threadid() also when it's used in a function argument.
+        # See https://github.com/cython/cython/issues/3594
+        buf[forward(cython.parallel.threadid())] = forward(threadid())
 
     for i in range(maxthreads):
         assert buf[i] == i
index d4a99735c3d1b5a166753dc4d0bbbb46a58c9fcb..ea5b239029b841ac2ba91dd02861ca69e6ade9c5 100644 (file)
@@ -6,7 +6,6 @@ initial_file_path
 package_compilation
 
 carray_coercion
-ctuple
 int_float_builtins_as_casts_T400
 int_float_builtins_as_casts_T400_long_double
 list_pop