Imported Upstream version 0.29.1 upstream/0.29.1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:09:19 +0000 (12:09 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:09:19 +0000 (12:09 +0900)
33 files changed:
CHANGES.rst
Cython/Build/Dependencies.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Pythran.py
Cython/Includes/cpython/array.pxd
Cython/Shadow.py
Cython/Utility/Coroutine.c
Cython/Utility/MemoryView.pyx
Cython/Utility/MemoryView_C.c
Cython/Utility/ModuleSetupCode.c
Cython/Utility/ObjectHandling.c
Cython/Utility/Optimize.c
appveyor.yml
docs/examples/userguide/early_binding_for_speed/rectangle_cpdef.pyx
docs/src/userguide/numpy_tutorial.rst
docs/src/userguide/source_files_and_compilation.rst
runtests.py
tests/compile/buildenv.pyx
tests/errors/w_undeclared.pyx [new file with mode: 0644]
tests/memoryview/memoryview.pyx
tests/memoryview/numpy_memoryview.pyx
tests/run/cimport.srctree
tests/run/cintop.pyx
tests/run/cpp_operators.pyx
tests/run/cpp_operators_helper.h
tests/run/embedsignatures.pyx
tests/run/line_trace.pyx
tests/run/numpy_pythran_unit.pyx [new file with mode: 0644]
tests/run/reimport_from_subinterpreter.srctree

index 35de41c03c1087e0ac0341d0f9a3434bfbdf793f..a57c46ceee9aa8183eaf60060182e38bd8240653 100644 (file)
@@ -2,6 +2,57 @@
 Cython Changelog
 ================
 
+0.29.1 (2018-11-24)
+===================
+
+Bugs fixed
+----------
+
+* Extensions compiled with MinGW-64 under Windows could misinterpret integer
+  objects larger than 15 bit and return incorrect results.
+  (Github issue #2670)
+
+* Cython no longer requires the source to be writable when copying its data
+  into a memory view slice.
+  Patch by Andrey Paramonov.  (Github issue #2644)
+
+* Line tracing of ``try``-statements generated invalid C code.
+  (Github issue #2274)
+
+* When using the ``warn.undeclared`` directive, Cython's own code generated
+  warnings that are now fixed.
+  Patch by Nicolas Pauss.  (Github issue #2685)
+
+* Cython's memoryviews no longer require strides for setting the shape field
+  but only the ``PyBUF_ND`` flag to be set.
+  Patch by John Kirkham.  (Github issue #2716)
+
+* Some C compiler warnings about unused memoryview code were fixed.
+  Patch by Ho Cheuk Ting.  (Github issue #2588)
+
+* A C compiler warning about implicit signed/unsigned conversion was fixed.
+  (Github issue #2729)
+
+* Assignments to C++ references returned by ``operator[]`` could fail to compile.
+  (Github issue #2671)
+
+* The power operator and the support for NumPy math functions were fixed
+  in Pythran expressions.
+  Patch by Serge Guelton.  (Github issues #2702, #2709)
+
+* Signatures with memory view arguments now show the expected type
+  when embedded in docstrings.
+  Patch by Matthew Chan and Benjamin Weigel.  (Github issue #2634)
+
+* Some ``from ... cimport ...`` constructs were not correctly considered
+  when searching modified dependencies in ``cythonize()`` to decide
+  whether to recompile a module.
+  Patch by Kryštof Pilnáček.  (Github issue #2638)
+
+* A struct field type in the ``cpython.array`` declarations was corrected.
+  Patch by John Kirkham.  (Github issue #2712)
+
+
 0.29 (2018-10-14)
 =================
 
@@ -186,9 +237,26 @@ Other changes
   slightly slower, by about 5-7%.
 
 
+0.28.6 (2018-11-01)
+===================
+
+Bugs fixed
+----------
+
+* Extensions compiled with MinGW-64 under Windows could misinterpret integer
+  objects larger than 15 bit and return incorrect results.
+  (Github issue #2670)
+
+* Multiplied string literals lost their factor when they are part of another
+  constant expression (e.g. 'x' * 10 + 'y' => 'xy').
+
+
 0.28.5 (2018-08-03)
 ===================
 
+Bugs fixed
+----------
+
 * The discouraged usage of GCC's attribute ``optimize("Os")`` was replaced by the
   similar attribute ``cold`` to reduce the code impact of the module init functions.
   (Github issue #2494)
index ae98fd74b45239c2cc49b2de71239fcde950e62e..fbd44e7af78e91ce3793331a693f15c6d156dcb6 100644 (file)
@@ -399,6 +399,10 @@ dependency_regex = re.compile(r"(?:^\s*from +([0-9a-zA-Z_.]+) +cimport)|"
                               r"(?:^\s*cimport +([0-9a-zA-Z_.]+(?: *, *[0-9a-zA-Z_.]+)*))|"
                               r"(?:^\s*cdef +extern +from +['\"]([^'\"]+)['\"])|"
                               r"(?:^\s*include +['\"]([^'\"]+)['\"])", re.M)
+dependency_after_from_regex = re.compile(
+    r"(?:^\s+\(([0-9a-zA-Z_., ]*)\)[#\n])|"
+    r"(?:^\s+([0-9a-zA-Z_., ]*)[#\n])",
+    re.M)
 
 
 def normalize_existing(base_path, rel_paths):
@@ -488,6 +492,13 @@ def parse_dependencies(source_filename):
         cimport_from, cimport_list, extern, include = m.groups()
         if cimport_from:
             cimports.append(cimport_from)
+            m_after_from = dependency_after_from_regex.search(source, pos=m.end())
+            if m_after_from:
+                multiline, one_line = m_after_from.groups()
+                subimports = multiline or one_line
+                cimports.extend("{0}.{1}".format(cimport_from, s.strip())
+                                for s in subimports.split(','))
+
         elif cimport_list:
             cimports.extend(x.strip() for x in cimport_list.split(","))
         elif extern:
@@ -584,14 +595,14 @@ class DependencyTree(object):
             pxd_list = [filename[:-4] + '.pxd']
         else:
             pxd_list = []
+        # Cimports generates all possible combinations package.module
+        # when imported as from package cimport module.
         for module in self.cimports(filename):
             if module[:7] == 'cython.' or module == 'cython':
                 continue
             pxd_file = self.find_pxd(module, filename)
             if pxd_file is not None:
                 pxd_list.append(pxd_file)
-            elif not self.quiet:
-                print("%s: cannot find cimported module '%s'" % (filename, module))
         return tuple(pxd_list)
 
     @cached_method
index c2558dcfade6deac9296cf50ce2be289ccb30636..88479f77b89cc7e3eb3e1cf0f83573b73a564d2f 100644 (file)
@@ -4102,7 +4102,7 @@ class IndexNode(_IndexingBaseNode):
                 # both exception handlers are the same.
                 translate_cpp_exception(code, self.pos,
                     "%s = %s;" % (self.result(), rhs.result()),
-                    self.result() if self.lhs.is_pyobject else None,
+                    self.result() if self.type.is_pyobject else None,
                     self.exception_value, self.in_nogil_context)
         else:
             code.putln(
@@ -11115,12 +11115,19 @@ class BinopNode(ExprNode):
         if self.type.is_pythran_expr:
             code.putln("// Pythran binop")
             code.putln("__Pyx_call_destructor(%s);" % self.result())
-            code.putln("new (&%s) decltype(%s){%s %s %s};" % (
-                self.result(),
-                self.result(),
-                self.operand1.pythran_result(),
-                self.operator,
-                self.operand2.pythran_result()))
+            if self.operator == '**':
+                code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::power{}(%s, %s)};" % (
+                    self.result(),
+                    self.result(),
+                    self.operand1.pythran_result(),
+                    self.operand2.pythran_result()))
+            else:
+                code.putln("new (&%s) decltype(%s){%s %s %s};" % (
+                    self.result(),
+                    self.result(),
+                    self.operand1.pythran_result(),
+                    self.operator,
+                    self.operand2.pythran_result()))
         elif self.operand1.type.is_pyobject:
             function = self.py_operation_function(code)
             if self.operator == '**':
index d4eaf20ab34f73e94b6f52ea789a54a1a7b04aca..ce1a94289942243a603b304975a6f87427ba52b0 100644 (file)
@@ -246,6 +246,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             h_code.put_generated_by()
             api_guard = Naming.api_guard_prefix + self.api_name(env)
             h_code.put_h_guard(api_guard)
+            # Work around https://bugs.python.org/issue4709
+            h_code.putln('#ifdef __MINGW64__')
+            h_code.putln('#define MS_WIN64')
+            h_code.putln('#endif')
+
             h_code.putln('#include "Python.h"')
             if result.h_file:
                 h_code.putln('#include "%s"' % os.path.basename(result.h_file))
index 439a1fde6db915271a9d31fb68f386fe9fce03ae..38183481dee942e9c8c9a2cbeb2957cfad2e7b21 100644 (file)
@@ -7171,6 +7171,9 @@ class TryExceptStatNode(StatNode):
     gil_message = "Try-except statement"
 
     def generate_execution_code(self, code):
+        code.mark_pos(self.pos)  # before changing the error label, in case of tracing errors
+        code.putln("{")
+
         old_return_label = code.return_label
         old_break_label = code.break_label
         old_continue_label = code.continue_label
@@ -7186,8 +7189,6 @@ class TryExceptStatNode(StatNode):
 
         exc_save_vars = [code.funcstate.allocate_temp(py_object_type, False)
                          for _ in range(3)]
-        code.mark_pos(self.pos)
-        code.putln("{")
         save_exc = code.insertion_point()
         code.putln(
             "/*try:*/ {")
@@ -7520,7 +7521,9 @@ class TryFinallyStatNode(StatNode):
     gil_message = "Try-finally statement"
 
     def generate_execution_code(self, code):
-        code.mark_pos(self.pos)
+        code.mark_pos(self.pos)  # before changing the error label, in case of tracing errors
+        code.putln("/*try:*/ {")
+
         old_error_label = code.error_label
         old_labels = code.all_new_labels()
         new_labels = code.get_all_labels()
@@ -7529,7 +7532,6 @@ class TryFinallyStatNode(StatNode):
             code.error_label = old_error_label
         catch_label = code.new_label()
 
-        code.putln("/*try:*/ {")
         was_in_try_finally = code.funcstate.in_try_finally
         code.funcstate.in_try_finally = 1
 
index 9753a2f61b449d865bdca5d3b20ed17a4e33c42e..f4c0f5c36c00ff9ccee275575565f7e8e633cdf4 100644 (file)
@@ -1707,6 +1707,8 @@ if VALUE is not None:
             # so it can be pickled *after* self is memoized.
             unpickle_func = TreeFragment(u"""
                 def %(unpickle_func_name)s(__pyx_type, long __pyx_checksum, __pyx_state):
+                    cdef object __pyx_PickleError
+                    cdef object __pyx_result
                     if __pyx_checksum != %(checksum)s:
                         from pickle import PickleError as __pyx_PickleError
                         raise __pyx_PickleError("Incompatible checksums (%%s vs %(checksum)s = (%(members)s))" %% __pyx_checksum)
@@ -1735,6 +1737,8 @@ if VALUE is not None:
 
             pickle_func = TreeFragment(u"""
                 def __reduce_cython__(self):
+                    cdef tuple state
+                    cdef object _dict
                     cdef bint use_setstate
                     state = (%(members)s)
                     _dict = getattr(self, '__dict__', None)
index ac5913f9ad263bb179e3ce4aa96b33ae398a50d1..2b604bd27760ff315e2e6ebbf3f102da94237204 100644 (file)
@@ -653,8 +653,9 @@ class MemoryViewSliceType(PyrexType):
         assert not pyrex
         assert not dll_linkage
         from . import MemoryView
+        base_code = str(self) if for_display else MemoryView.memviewslice_cname
         return self.base_declaration_code(
-                MemoryView.memviewslice_cname,
+                base_code,
                 entity_code)
 
     def attributes_known(self):
index cabb95799580b99a3286bece8cd3e5745c5b3d13..fc819569674e1045bdf9998b923715ac0891b7dc 100644 (file)
@@ -60,8 +60,12 @@ def type_remove_ref(ty):
 
 
 def pythran_binop_type(op, tA, tB):
-    return "decltype(std::declval<%s>() %s std::declval<%s>())" % (
-        pythran_type(tA), op, pythran_type(tB))
+    if op == '**':
+        return 'decltype(pythonic::numpy::functor::power{}(std::declval<%s>(), std::declval<%s>()))' % (
+            pythran_type(tA), pythran_type(tB))
+    else:
+        return "decltype(std::declval<%s>() %s std::declval<%s>())" % (
+            pythran_type(tA), op, pythran_type(tB))
 
 
 def pythran_unaryop_type(op, type_):
@@ -201,7 +205,7 @@ def is_pythran_buffer(type_):
 
 def pythran_get_func_include_file(func):
     func = np_func_to_list(func)
-    return "pythonic/include/numpy/%s.hpp" % "/".join(func)
+    return "pythonic/numpy/%s.hpp" % "/".join(func)
 
 def include_pythran_generic(env):
     # Generic files
@@ -209,6 +213,7 @@ def include_pythran_generic(env):
     env.add_include_file("pythonic/python/core.hpp")
     env.add_include_file("pythonic/types/bool.hpp")
     env.add_include_file("pythonic/types/ndarray.hpp")
+    env.add_include_file("pythonic/numpy/power.hpp")
     env.add_include_file("<new>")  # for placement new
 
     for i in (8, 16, 32, 64):
index d985e37b1593f1566e9b662c061903faba9bfda4..3d2bb05e435ad2788b87332cf24fb1567a07556e 100644 (file)
@@ -59,7 +59,7 @@ cdef extern from *:  # Hard-coded utility code hack.
     ctypedef object GETF(array a, Py_ssize_t ix)
     ctypedef object SETF(array a, Py_ssize_t ix, object o)
     ctypedef struct arraydescr:  # [object arraydescr]:
-            int typecode
+            char typecode
             int itemsize
             GETF getitem    # PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
             SETF setitem    # int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
index 643556f3de433eadb0623c3311780266617f2402..02355530dcf6a1d110cbc719395651937c11c1cb 100644 (file)
@@ -1,7 +1,7 @@
 # cython.* namespace for pure mode.
 from __future__ import absolute_import
 
-__version__ = "0.29"
+__version__ = "0.29.1"
 
 try:
     from __builtin__ import basestring
index 252f6c217b42ef4aedce2f5f4e21d65dd7f3e704..8cd3138b2c125efe499c1cb9fc073a10ae062793 100644 (file)
@@ -607,7 +607,7 @@ void __Pyx_Coroutine_ExceptionClear(__Pyx_ExcInfoStruct *exc_state) {
 #define __Pyx_Coroutine_AlreadyRunningError(gen)  (__Pyx__Coroutine_AlreadyRunningError(gen), (PyObject*)NULL)
 static void __Pyx__Coroutine_AlreadyRunningError(CYTHON_UNUSED __pyx_CoroutineObject *gen) {
     const char *msg;
-    if (0) {
+    if ((0)) {
     #ifdef __Pyx_Coroutine_USED
     } else if (__Pyx_Coroutine_Check((PyObject*)gen)) {
         msg = "coroutine already executing";
@@ -625,7 +625,7 @@ static void __Pyx__Coroutine_AlreadyRunningError(CYTHON_UNUSED __pyx_CoroutineOb
 #define __Pyx_Coroutine_NotStartedError(gen)  (__Pyx__Coroutine_NotStartedError(gen), (PyObject*)NULL)
 static void __Pyx__Coroutine_NotStartedError(CYTHON_UNUSED PyObject *gen) {
     const char *msg;
-    if (0) {
+    if ((0)) {
     #ifdef __Pyx_Coroutine_USED
     } else if (__Pyx_Coroutine_Check(gen)) {
         msg = "can't send non-None value to a just-started coroutine";
index 965af7b513da08031b777efe73a79554d8abb6fb..d03fddb8653c761c7dc15fb4e7f9aee859722b6c 100644 (file)
@@ -64,6 +64,7 @@ cdef extern from *:
         PyBUF_WRITABLE
         PyBUF_STRIDES
         PyBUF_INDIRECT
+        PyBUF_ND
         PyBUF_RECORDS
         PyBUF_RECORDS_RO
 
@@ -426,7 +427,7 @@ cdef class memoryview(object):
     cdef is_slice(self, obj):
         if not isinstance(obj, memoryview):
             try:
-                obj = memoryview(obj, self.flags|PyBUF_ANY_CONTIGUOUS,
+                obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS,
                                  self.dtype_is_object)
             except TypeError:
                 return None
@@ -514,7 +515,7 @@ cdef class memoryview(object):
         if flags & PyBUF_WRITABLE and self.view.readonly:
             raise ValueError("Cannot create writable memory view from read-only memoryview")
 
-        if flags & PyBUF_STRIDES:
+        if flags & PyBUF_ND:
             info.shape = self.view.shape
         else:
             info.shape = NULL
index b7bd6a04ef5c2695e79d968a5ba4d0a8dd23aa09..5caf3a3ef772b58c81077c84e84c9706719f4c58 100644 (file)
@@ -852,28 +852,40 @@ if (unlikely(__pyx_memoryview_slice_memviewslice(
 
 {
     Py_ssize_t __pyx_tmp_idx = {{idx}};
-    Py_ssize_t __pyx_tmp_shape = {{src}}.shape[{{dim}}];
+
+    {{if wraparound or boundscheck}}
+        Py_ssize_t __pyx_tmp_shape = {{src}}.shape[{{dim}}];
+    {{endif}}
+
     Py_ssize_t __pyx_tmp_stride = {{src}}.strides[{{dim}}];
-    if ({{wraparound}} && (__pyx_tmp_idx < 0))
-        __pyx_tmp_idx += __pyx_tmp_shape;
+    {{if wraparound}}
+        if (__pyx_tmp_idx < 0)
+            __pyx_tmp_idx += __pyx_tmp_shape;
+    {{endif}}
 
-    if ({{boundscheck}} && !__Pyx_is_valid_index(__pyx_tmp_idx, __pyx_tmp_shape)) {
-        {{if not have_gil}}
-            #ifdef WITH_THREAD
-            PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();
-            #endif
-        {{endif}}
+    {{if boundscheck}}
+        if (!__Pyx_is_valid_index(__pyx_tmp_idx, __pyx_tmp_shape)) {
+            {{if not have_gil}}
+                #ifdef WITH_THREAD
+                PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();
+                #endif
+            {{endif}}
 
-        PyErr_SetString(PyExc_IndexError, "Index out of bounds (axis {{dim}})");
+            PyErr_SetString(PyExc_IndexError,
+                            "Index out of bounds (axis {{dim}})");
 
-        {{if not have_gil}}
-            #ifdef WITH_THREAD
-            PyGILState_Release(__pyx_gilstate_save);
-            #endif
-        {{endif}}
+            {{if not have_gil}}
+                #ifdef WITH_THREAD
+                PyGILState_Release(__pyx_gilstate_save);
+                #endif
+            {{endif}}
 
-        {{error_goto}}
-    }
+            {{error_goto}}
+        }
+    {{else}}
+        // make sure label is not un-used
+        if ((0)) {{error_goto}}
+    {{endif}}
 
     {{if all_dimensions_direct}}
         {{dst}}.data += __pyx_tmp_idx * __pyx_tmp_stride;
index 9f1489e60250a083f3fb02c1b0cc5ef43e244a43..109bf929fb7446744fa5576cd485a98f7941c14b 100644 (file)
   #undef SHIFT
   #undef BASE
   #undef MASK
+  /* Compile-time sanity check that these are indeed equal.  Github issue #2670. */
+  #ifdef SIZEOF_VOID_P
+    enum { __pyx_check_sizeof_voidp = 1/(SIZEOF_VOID_P == sizeof(void*)) };
+  #endif
 #endif
 
 #ifndef __has_attribute
@@ -940,11 +944,13 @@ static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) {
     return 0;
 }
 
-static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name) {
+static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) {
     PyObject *value = PyObject_GetAttrString(spec, from_name);
     int result = 0;
     if (likely(value)) {
-        result = PyDict_SetItemString(moddict, to_name, value);
+        if (allow_none || value != Py_None) {
+            result = PyDict_SetItemString(moddict, to_name, value);
+        }
         Py_DECREF(value);
     } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
         PyErr_Clear();
@@ -974,10 +980,10 @@ static CYTHON_SMALL_CODE PyObject* ${pymodule_create_func_cname}(PyObject *spec,
     if (unlikely(!moddict)) goto bad;
     // moddict is a borrowed reference
 
-    if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__") < 0)) goto bad;
-    if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__") < 0)) goto bad;
-    if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__") < 0)) goto bad;
-    if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__") < 0)) goto bad;
+    if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad;
+    if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad;
+    if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad;
+    if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad;
 
     return module;
 bad:
index b147cb33e84bcdc55a7232f8efa01213d7e389bc..a325d45704141fa6465106b601e8534e313abe54 100644 (file)
@@ -1966,7 +1966,7 @@ static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args,
   // because f_localsplus is the last field of PyFrameObject (checked by Py_BUILD_ASSERT_EXPR below).
   #define __Pxy_PyFrame_Initialize_Offsets()  \
     ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)), \
-     (void)(__pyx_pyframe_localsplus_offset = PyFrame_Type.tp_basicsize - Py_MEMBER_SIZE(PyFrameObject, f_localsplus)))
+     (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus)))
   #define __Pyx_PyFrame_GetLocalsplus(frame)  \
     (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset))
 #endif
index 3d5be8f0078b8258b603cf9ec08fb59437a590f0..3366f9cf04dc5e857a41edc92d693c7f99db181c 100644 (file)
@@ -600,7 +600,7 @@ static double __Pyx__PyObject_AsDouble(PyObject* obj); /* proto */
 static double __Pyx__PyObject_AsDouble(PyObject* obj) {
     PyObject* float_value;
 #if !CYTHON_USE_TYPE_SLOTS
-    float_value = PyNumber_Float(obj);  if (0) goto bad;
+    float_value = PyNumber_Float(obj);  if ((0)) goto bad;
 #else
     PyNumberMethods *nb = Py_TYPE(obj)->tp_as_number;
     if (likely(nb) && likely(nb->nb_float)) {
index 0e3c1eb487628738da539ad270b354619bfa2bdc..860fcbb50f4f702e5459499ab7aa6eedc4e9f1d5 100644 (file)
@@ -74,7 +74,7 @@ test: off
 test_script:
   - "%PYTHON%\\Scripts\\pip.exe install -r test-requirements.txt"
   - "set CFLAGS=/Od"
-  - "%WITH_ENV% %PYTHON%\\python.exe runtests.py -vv --no-cpp -j5"
+  - "%WITH_ENV% %PYTHON%\\python.exe runtests.py -vv --no-cpp --no-code-style -j5"
 
 artifacts:
   - path: dist\*
index fde9ef9cfd2f0105d667a1a04b9d0a34e4399ed6..01df3759f37b6617620ef3aca9e94441464c118b 100644 (file)
@@ -8,7 +8,7 @@ cdef class Rectangle:
         self.x1 = x1\r
         self.y1 = y1\r
 \r
-    cpdef int _area(self):\r
+    cpdef int area(self):\r
         area = (self.x1 - self.x0) * (self.y1 - self.y0)\r
         if area < 0:\r
             area = -area\r
index 52506d0799e430c5c062b762eee1729d36553c04..df1863d16e0619dab5c4d1ad43f3e90bb7ab3811 100644 (file)
@@ -458,9 +458,9 @@ integers as before.
 Using multiple threads
 ======================
 
-Cython have support for OpenMP. It have also some nice wrappers around it,
+Cython has support for OpenMP.  It also has some nice wrappers around it,
 like the function :func:`prange`. You can see more information about Cython and
-parralelism in :ref:`parallel`. Since we do elementwise operations, we can easily
+parallelism in :ref:`parallel`. Since we do elementwise operations, we can easily
 distribute the work among multiple threads. It's important not to forget to pass the
 correct arguments to the compiler to enable OpenMP. When using the Jupyter notebook,
 you should use the cell magic like this::
index b9e0481e3d0a26004e3b087321ac45f50d07e7e2..c4f01806d2802662b32f35308c4e9fd7feb0787b 100644 (file)
@@ -920,10 +920,9 @@ How to set directives
 Globally
 :::::::::
 
-One can set compiler directives through a special header comment at the top of the file, like this::
+One can set compiler directives through a special header comment near the top of the file, like this::
 
-    #!python
-    #cython: language_level=3, boundscheck=False
+    # cython: language_level=3, boundscheck=False
 
 The comment must appear before any code (but can appear after other
 comments or whitespace).
index 59f55ec4fc7898217a056e5d92c8fb399f525f2f..80e77b51b1b1d286a30f5071d57c61fc2856917b 100755 (executable)
@@ -1583,6 +1583,8 @@ class TestCodeFormat(unittest.TestCase):
     def runTest(self):
         import pycodestyle
         config_file = os.path.join(self.cython_dir, "tox.ini")
+        if not os.path.exists(config_file):
+            config_file=os.path.join(os.path.dirname(__file__), "tox.ini")
         paths = glob.glob(os.path.join(self.cython_dir, "**/*.py"), recursive=True)
         style = pycodestyle.StyleGuide(config_file=config_file)
         print("")  # Fix the first line of the report.
@@ -1734,7 +1736,10 @@ class EndToEndTest(unittest.TestCase):
             .replace("PYTHON", sys.executable))
         old_path = os.environ.get('PYTHONPATH')
         env = dict(os.environ)
-        env['PYTHONPATH'] = self.cython_syspath + os.pathsep + (old_path or '')
+        new_path = self.cython_syspath
+        if old_path:
+            new_path = new_path + os.pathsep + old_path
+        env['PYTHONPATH'] = new_path
         cmd = []
         out = []
         err = []
@@ -2446,7 +2451,13 @@ def runtests(options, cmd_args, coverage=None):
             test_suite.addTest(filetests.handle_directory(sys_pyregr_dir, 'pyregr'))
 
     if options.code_style and options.shard_num <= 0:
-        test_suite.addTest(TestCodeFormat(options.cython_dir))
+        try:
+            import pycodestyle
+        except ImportError:
+            # Hack to make the exclusion visible.
+            missing_dep_excluder.tests_missing_deps.append('TestCodeFormat')
+        else:
+            test_suite.addTest(TestCodeFormat(options.cython_dir))
 
     if xml_output_dir:
         from Cython.Tests.xmlrunner import XMLTestRunner
index d38efba1a7cfb23d47dc6de6ceb41d4bf23bf686..e61491734037d32e65945ccf4718383fa7e948df 100644 (file)
@@ -92,10 +92,12 @@ CYTHON_PEP489_MULTI_PHASE_INIT  {CYTHON_PEP489_MULTI_PHASE_INIT}
 CYTHON_USE_TP_FINALIZE  {CYTHON_USE_TP_FINALIZE}
 
 PyLong_BASE  0x{PyLong_BASE:X}
-PyLong_MASK  {PyLong_MASK:X}
+PyLong_MASK  0x{PyLong_MASK:X}
 PyLong_SHIFT  {PyLong_SHIFT}
-sizeof(digit)  {sizeof(digit)}
+sizeof(digit)   {sizeof(digit)}
 sizeof(sdigit)  {sizeof(sdigit)}
+sys.int_info  {getattr(sys, 'int_info', '-')}
+sys.getsizeof(1, 2**14, 2**15, 2**29, 2**30, 2**59, 2**60, 2**64)  {tuple(sys.getsizeof(n) for n in (1, 2**14, 2**15, 2**29, 2**30, 2**59, 2**60, 2**64))}
 
 SIZEOF_INT  {SIZEOF_INT}  ({sizeof(int)})
 SIZEOF_LONG  {SIZEOF_LONG}  ({sizeof(long)})
diff --git a/tests/errors/w_undeclared.pyx b/tests/errors/w_undeclared.pyx
new file mode 100644 (file)
index 0000000..585aef1
--- /dev/null
@@ -0,0 +1,20 @@
+# cython: warn.undeclared=True
+# mode: error
+# tag: werror
+
+def foo():
+    a = 1
+    return a
+
+cdef class Bar:
+    cdef int baz(self, a):
+        res = 0
+        for i in range(3):
+            res += i
+        return res
+
+_ERRORS = """
+6:4: implicit declaration of 'a'
+11:8: implicit declaration of 'res'
+12:12: implicit declaration of 'i'
+"""
index 3d01cc1787729e38e6f9b655a9d931448762750b..a4ca02230eb39b3d3f985c0f7e00fcdb471190d9 100644 (file)
@@ -14,6 +14,9 @@ from cpython.object cimport PyObject
 from cpython.ref cimport Py_INCREF, Py_DECREF
 cimport cython
 
+import array as pyarray
+from libc.stdlib cimport malloc, free
+
 cdef extern from "Python.h":
     cdef int PyBUF_C_CONTIGUOUS
 
@@ -1083,3 +1086,37 @@ def optimised_index_of_slice(int[:,:,:] arr, int x, int y, int z):
     print(arr[x, y, z], arr[x][:][:][y][:][:][z])
     print(arr[x, y, z], arr[:][x][:][y][:][:][z])
     print(arr[x, y, z], arr[:, :][x][:, :][y][:][z])
+
+
+def test_assign_from_byteslike(byteslike):
+    # Once http://python3statement.org is accepted, should be just
+    # >>> test_assign_from_byteslike(bytes(b'hello'))
+    # b'hello'
+    # ...
+    """
+    >>> print(test_assign_from_byteslike(bytes(b'hello')).decode())
+    hello
+    >>> print(test_assign_from_byteslike(bytearray(b'howdy')).decode())
+    howdy
+    """
+    # fails on Python 2.7- with
+    #   TypeError: an integer is required
+    # >>> print(test_assign_from_byteslike(pyarray.array('B', b'aloha')).decode())
+    # aloha
+    # fails on Python 2.6- with
+    #   NameError: name 'memoryview' is not defined
+    # >>> print(test_assign_from_byteslike(memoryview(b'bye!!')).decode())
+    # bye!!
+
+    def assign(m):
+        m[:] = byteslike
+
+    cdef void *buf
+    cdef unsigned char[:] mview
+    buf = malloc(5)
+    try:
+        mview = <unsigned char[:5]>(buf)
+        assign(mview)
+        return (<unsigned char*>buf)[:5]
+    finally:
+        free(buf)
index 39e6dd6bbbb1f0c8f0445eac671f1abc88ced6c5..cf9e92971c9f0a2fd4c20189354742684d50bf9e 100644 (file)
@@ -370,6 +370,7 @@ def test_coerce_to_numpy():
     ints[idx] = 222
     longlongs[idx] = 333
     externs[idx] = 444
+    assert externs[idx] == 444  # avoid "set but not used" C compiler warning
 
     floats[idx] = 11.1
     doubles[idx] = 12.2
@@ -699,3 +700,21 @@ def test_refcount_GH507():
     a = np.arange(12).reshape([3, 4])
     cdef np.int_t[:,:] a_view = a
     cdef np.int_t[:,:] b = a_view[1:2,:].T
+
+
+@cython.boundscheck(False)
+@cython.wraparound(False)
+def test_boundscheck_and_wraparound(double[:, :] x):
+    """
+    >>> import numpy as np
+    >>> array = np.ones((2,2)) * 3.5
+    >>> test_boundscheck_and_wraparound(array)
+    """
+    # Make sure we don't generate C compiler warnings for unused code here.
+    cdef Py_ssize_t numrow = x.shape[0]
+    cdef Py_ssize_t i
+    for i in range(numrow):
+        x[i, 0]
+        x[i]
+        x[i, ...]
+        x[i, :]
index 1d09e2adba6f2bac5aca031d9593721d085a40d4..23b4a491a6c9247686695c53663511516ff8d429 100644 (file)
@@ -33,9 +33,18 @@ cdef int foo(int a):
 
 ctypedef int my_int
 
+######## pkg/subpkg/__init__.py ########
+
+######## pkg/subpkg/submod.pxd ########
+
+ctypedef int my_int
+
 ######## a.pyx ########
 
-from other cimport A, foo
+from other cimport (
+    A,
+    foo,
+)
 print A, foo(10)
 
 cimport other
@@ -43,3 +52,5 @@ print other.A, other.foo(10)
 
 from pkg cimport sub
 cdef sub.my_int a = 100
+
+from pkg.subpkg cimport submod
\ No newline at end of file
index f6cdca8c85999072be77b1d668a24030446370e7..419f6dd50fa2419a8767f2f57a516e9168619870 100644 (file)
@@ -1,3 +1,5 @@
+# mode: run
+
 __doc__ = u"""
     >>> int2 = 42
     >>> int3 = 7
@@ -35,3 +37,24 @@ def f():
     int1 ^= int2 << int3 | int2 >> int3
     long1 = char1 | int1
     return int1, long1
+
+
+def long_int_shift():
+    """
+    >>> long_int_shift()
+    80082
+    10010
+    10010
+    10010
+    10010
+    """
+    value = 80082 # int using more than 2 bytes == long
+    print(value)
+    shiftedby3 = value >> 3
+    dividedby8 = value // 8
+    print(shiftedby3)
+    print(dividedby8)
+    shiftedby3 = 80082 >> 3
+    dividedby8 = 80082 // 8
+    print(shiftedby3)
+    print(dividedby8)
index aca865f9c5945d96e7e53f53e95446a1ebe04262..050806d8fac80eb4c23f0226fb7b2e530d6a4d55 100644 (file)
@@ -9,48 +9,56 @@ from cython.operator cimport typeid, dereference as deref
 from libc.string cimport const_char
 from libcpp cimport bool
 
+
 cdef out(s, result_type=None):
     print '%s [%s]' % (s.decode('ascii'), result_type)
 
+
+cdef iout(int s, result_type=None):
+    print '%s [%s]' % (s, result_type)
+
+
 cdef extern from "cpp_operators_helper.h" nogil:
     cdef cppclass TestOps:
 
-        const_char* operator+()
-        const_char* operator-()
-        const_char* operator*()
-        const_char* operator~()
-        const_char* operator!()
+        const_char* operator+() except +
+        const_char* operator-() except +
+        const_char* operator*() except +
+        const_char* operator~() except +
+        const_char* operator!() except +
 
+        # FIXME: using 'except +' here leads to wrong calls ???
         const_char* operator++()
         const_char* operator--()
         const_char* operator++(int)
         const_char* operator--(int)
 
-        const_char* operator+(int)
-        const_char* operator+(int,const TestOps&)
-        const_char* operator-(int)
-        const_char* operator-(int,const TestOps&)
-        const_char* operator*(int)
+        const_char* operator+(int) except +
+        const_char* operator+(int,const TestOps&) except +
+        const_char* operator-(int) except +
+        const_char* operator-(int,const TestOps&) except +
+        const_char* operator*(int) except +
         # deliberately omitted operator* to test case where only defined outside class
-        const_char* operator/(int)
-        const_char* operator/(int,const TestOps&)
-        const_char* operator%(int)
-        const_char* operator%(int,const TestOps&)
-
-        const_char* operator|(int)
-        const_char* operator|(int,const TestOps&)
-        const_char* operator&(int)
-        const_char* operator&(int,const TestOps&)
-        const_char* operator^(int)
-        const_char* operator^(int,const TestOps&)
-        const_char* operator,(int)
-        const_char* operator,(int,const TestOps&)
-
-        const_char* operator<<(int)
-        const_char* operator<<(int,const TestOps&)
-        const_char* operator>>(int)
-        const_char* operator>>(int,const TestOps&)
-
+        const_char* operator/(int) except +
+        const_char* operator/(int,const TestOps&) except +
+        const_char* operator%(int) except +
+        const_char* operator%(int,const TestOps&) except +
+
+        const_char* operator|(int) except +
+        const_char* operator|(int,const TestOps&) except +
+        const_char* operator&(int) except +
+        const_char* operator&(int,const TestOps&) except +
+        const_char* operator^(int) except +
+        const_char* operator^(int,const TestOps&) except +
+        const_char* operator,(int) except +
+        const_char* operator,(int,const TestOps&) except +
+
+        const_char* operator<<(int) except +
+        const_char* operator<<(int,const TestOps&) except +
+        const_char* operator>>(int) except +
+        const_char* operator>>(int,const TestOps&) except +
+
+        # FIXME: using 'except +' here leads to invalid C++ code ???
         const_char* operator==(int)
         const_char* operator!=(int)
         const_char* operator>=(int)
@@ -58,25 +66,73 @@ cdef extern from "cpp_operators_helper.h" nogil:
         const_char* operator>(int)
         const_char* operator<(int)
 
-        const_char* operator[](int)
-        const_char* operator()(int)
-    
+        const_char* operator[](int) except +
+        const_char* operator()(int) except +
+
     # Defining the operator outside the class does work
     # but doesn't help when importing from pxd files
     # (they don't get imported)
-    const_char* operator+(float,const TestOps&)
+    const_char* operator+(float,const TestOps&) except +
     # deliberately omitted operator- to test case where only defined in class
-    const_char* operator*(float,const TestOps&)
-    const_char* operator/(float,const TestOps&)
-    const_char* operator%(float,const TestOps&)
-
-    const_char* operator|(float,const TestOps&)
-    const_char* operator&(float,const TestOps&)
-    const_char* operator^(float,const TestOps&)
-    const_char* operator,(float,const TestOps&)
-
-    const_char* operator<<(float,const TestOps&)
-    const_char* operator>>(float,const TestOps&)
+    const_char* operator*(float,const TestOps&) except +
+    const_char* operator/(float,const TestOps&) except +
+    const_char* operator%(float,const TestOps&) except +
+
+    const_char* operator|(float,const TestOps&) except +
+    const_char* operator&(float,const TestOps&) except +
+    const_char* operator^(float,const TestOps&) except +
+    const_char* operator,(float,const TestOps&) except +
+
+    const_char* operator<<(float,const TestOps&) except +
+    const_char* operator>>(float,const TestOps&) except +
+
+    cdef cppclass RefTestOps:
+
+        int& operator+() except +
+        int& operator-() except +
+        int& operator*() except +
+        int& operator~() except +
+        int& operator!() except +
+
+        int& operator++() except +
+        int& operator--() except +
+        int& operator++(int) except +
+        int& operator--(int) except +
+
+        int& operator+(int) except +
+        int& operator+(int,const TestOps&) except +
+        int& operator-(int) except +
+        int& operator-(int,const TestOps&) except +
+        int& operator*(int) except +
+        # deliberately omitted operator* to test case where only defined outside class
+        int& operator/(int) except +
+        int& operator/(int,const TestOps&) except +
+        int& operator%(int) except +
+        int& operator%(int,const TestOps&) except +
+
+        int& operator|(int) except +
+        int& operator|(int,const TestOps&) except +
+        int& operator&(int) except +
+        int& operator&(int,const TestOps&) except +
+        int& operator^(int) except +
+        int& operator^(int,const TestOps&) except +
+        int& operator,(int) except +
+        int& operator,(int,const TestOps&) except +
+
+        int& operator<<(int) except +
+        int& operator<<(int,const TestOps&) except +
+        int& operator>>(int) except +
+        int& operator>>(int,const TestOps&) except +
+
+        int& operator==(int) except +
+        int& operator!=(int) except +
+        int& operator>=(int) except +
+        int& operator<=(int) except +
+        int& operator>(int) except +
+        int& operator<(int) except +
+
+        int& operator[](int) except +
+        int& operator()(int) except +
 
     cdef cppclass TruthClass:
         TruthClass()
@@ -84,9 +140,11 @@ cdef extern from "cpp_operators_helper.h" nogil:
         bool operator bool()
         bool value
 
+
 cdef cppclass TruthSubClass(TruthClass):
     pass
 
+
 def test_unops():
     """
     >>> test_unops()
@@ -233,6 +291,7 @@ def test_cmp():
     out(t[0] < 1, typeof(t[0] < 1))
     del t
 
+
 def test_index_call():
     """
     >>> test_index_call()
@@ -244,6 +303,20 @@ def test_index_call():
     out(t[0](100), typeof(t[0](100)))
     del t
 
+
+def test_index_assignment():
+    """
+    >>> test_index_assignment()
+    0 [int &]
+    123 [int [&]]
+    """
+    cdef RefTestOps* t = new RefTestOps()
+    iout(t[0][100], typeof(t[0][100]))
+    t[0][99] = 123
+    iout(t[0](100), typeof(t[0](100)))
+    del t
+
+
 def test_bool_op():
     """
     >>> test_bool_op()
index 5ae21ff153509503450da4fe15c20df85f0b2a21..ec77d7f621d8658372cc8411de2c9b5e693a3572 100644 (file)
@@ -76,6 +76,58 @@ NONMEMBER_BIN_OP2(&)
 NONMEMBER_BIN_OP2(^)
 NONMEMBER_BIN_OP2(COMMA)
 
+
+/* RefTestOps */
+
+#define REF_UN_OP(op) int& operator op () { return value; }
+#define REF_POST_UN_OP(op) int& operator op (int x) { x++; return value; }
+#define REF_BIN_OP(op) int& operator op (int x) { x++; return value; }
+
+class RefTestOps {
+    int value = 0;
+
+public:
+
+    REF_UN_OP(-);
+    REF_UN_OP(+);
+    REF_UN_OP(*);
+    REF_UN_OP(~);
+    REF_UN_OP(!);
+    REF_UN_OP(&);
+
+    REF_UN_OP(++);
+    REF_UN_OP(--);
+    REF_POST_UN_OP(++);
+    REF_POST_UN_OP(--);
+
+    REF_BIN_OP(+);
+    REF_BIN_OP(-);
+    REF_BIN_OP(*);
+    REF_BIN_OP(/);
+    REF_BIN_OP(%);
+
+    REF_BIN_OP(<<);
+    REF_BIN_OP(>>);
+
+    REF_BIN_OP(|);
+    REF_BIN_OP(&);
+    REF_BIN_OP(^);
+    REF_BIN_OP(COMMA);
+
+    REF_BIN_OP(==);
+    REF_BIN_OP(!=);
+    REF_BIN_OP(<=);
+    REF_BIN_OP(<);
+    REF_BIN_OP(>=);
+    REF_BIN_OP(>);
+
+    REF_BIN_OP([]);
+    REF_BIN_OP(());
+};
+
+
+/* TruthClass */
+
 class TruthClass {
 public:
   TruthClass() : value(false) {}
index 447f0e5ffb12d8ec661a58382cadd27530c5497c..147f7afdd348d88df9e28b57d1c28cb4a011116f 100644 (file)
@@ -428,6 +428,7 @@ cdef class Foo:
     def m28(self, a: list(range(3))[::1]): pass
     def m29(self, a: list(range(3))[0:1:1]): pass
     def m30(self, a: list(range(3))[7, 3:2:1, ...]): pass
+    def m31(self, double[::1] a): pass
 
 __doc__ += ur"""
 >>> print(Foo.m00.__doc__)
@@ -522,4 +523,7 @@ Foo.m29(self, a: list(range(3))[0:1:1])
 
 >>> print(Foo.m30.__doc__)
 Foo.m30(self, a: list(range(3))[7, 3:2:1, ...])
+
+>>> print(Foo.m31.__doc__)
+Foo.m31(self, double[::1] a)
 """
index ef5015b62070a7888f76f62c070851c2cbf1cddf..d6f9c3d0e53bf8a09a0d7a77d6cfce90ea47861b 100644 (file)
@@ -5,7 +5,7 @@
 
 import sys
 
-from cpython.ref cimport PyObject, Py_INCREF, Py_XINCREF, Py_XDECREF
+from cpython.ref cimport PyObject, Py_INCREF, Py_XDECREF
 
 cdef extern from "frameobject.h":
     ctypedef struct PyFrameObject:
@@ -23,7 +23,7 @@ cdef extern from *:
 
 map_trace_types = {
     PyTrace_CALL:        'call',
-    PyTrace_EXCEPTION:   'exc',
+    PyTrace_EXCEPTION:   'exception',
     PyTrace_LINE:        'line',
     PyTrace_RETURN:      'return',
     PyTrace_C_CALL:      'ccall',
@@ -74,6 +74,10 @@ def _create_trace_func(trace):
     local_names = {}
 
     def _trace_func(frame, event, arg):
+        if sys.version_info < (3,) and 'line_trace' not in frame.f_code.co_filename:
+            # Prevent tracing into Py2 doctest functions.
+            return None
+
         trace.append((map_trace_types(event, event), frame.f_lineno - frame.f_code.co_firstlineno))
 
         lnames = frame.f_code.co_varnames
@@ -85,9 +89,9 @@ def _create_trace_func(trace):
         # Currently, the locals dict is empty for Cython code, but not for Python code.
         if frame.f_code.co_name.startswith('py_'):
             # Change this when we start providing proper access to locals.
-            assert frame.f_locals
+            assert frame.f_locals, frame.f_code.co_name
         else:
-            assert not frame.f_locals
+            assert not frame.f_locals, frame.f_code.co_name
 
         return _trace_func
     return _trace_func
@@ -154,6 +158,13 @@ cdef int cy_add_nogil(int a, int b) nogil except -1:
     return x    # 2
 
 
+def cy_try_except(func):
+    try:
+        return func()
+    except KeyError as exc:
+        raise AttributeError(exc.args[0])
+
+
 def run_trace(func, *args, bint with_sys=False):
     """
     >>> def py_add(a,b):
@@ -226,6 +237,62 @@ def run_trace(func, *args, bint with_sys=False):
     return trace
 
 
+def run_trace_with_exception(func, bint with_sys=False, bint fail=False):
+    """
+    >>> def py_return(retval=123): return retval
+    >>> run_trace_with_exception(py_return)
+    OK: 123
+    [('call', 0), ('line', 1), ('line', 2), ('call', 0), ('line', 0), ('return', 0), ('return', 2)]
+    >>> run_trace_with_exception(py_return, with_sys=True)
+    OK: 123
+    [('call', 0), ('line', 1), ('line', 2), ('call', 0), ('line', 0), ('return', 0), ('return', 2)]
+
+    >>> run_trace_with_exception(py_return, fail=True)
+    ValueError('failing line trace!')
+    [('call', 0)]
+
+    #>>> run_trace_with_exception(lambda: 123, with_sys=True, fail=True)
+    #ValueError('huhu')
+    #[('call', 0), ('line', 1), ('line', 2), ('call', 0), ('line', 0), ('return', 0), ('return', 2)]
+
+    >>> def py_raise_exc(exc=KeyError('huhu')): raise exc
+    >>> run_trace_with_exception(py_raise_exc)
+    AttributeError('huhu')
+    [('call', 0), ('line', 1), ('line', 2), ('call', 0), ('line', 0), ('exception', 0), ('return', 0), ('line', 3), ('line', 4), ('return', 4)]
+    >>> run_trace_with_exception(py_raise_exc, with_sys=True)
+    AttributeError('huhu')
+    [('call', 0), ('line', 1), ('line', 2), ('call', 0), ('line', 0), ('exception', 0), ('return', 0), ('line', 3), ('line', 4), ('return', 4)]
+    >>> run_trace_with_exception(py_raise_exc, fail=True)
+    ValueError('failing line trace!')
+    [('call', 0)]
+
+    #>>> run_trace_with_exception(raise_exc, with_sys=True, fail=True)
+    #ValueError('huhu')
+    #[('call', 0), ('line', 1), ('line', 2), ('call', 0), ('line', 0), ('exception', 0), ('return', 0), ('line', 3), ('line', 4), ('return', 4)]
+    """
+    trace = ['cy_try_except' if fail else 'NO ERROR']
+    trace_func = _create__failing_line_trace_func(trace) if fail else _create_trace_func(trace)
+    if with_sys:
+        sys.settrace(trace_func)
+    else:
+        PyEval_SetTrace(<Py_tracefunc>trace_trampoline, <PyObject*>trace_func)
+    try:
+        try:
+            retval = cy_try_except(func)
+        except ValueError as exc:
+            print("%s(%r)" % (type(exc).__name__, str(exc)))
+        except AttributeError as exc:
+            print("%s(%r)" % (type(exc).__name__, str(exc)))
+        else:
+            print('OK: %r' % retval)
+    finally:
+        if with_sys:
+            sys.settrace(None)
+        else:
+            PyEval_SetTrace(NULL, NULL)
+    return trace[1:]
+
+
 def fail_on_call_trace(func, *args):
     """
     >>> def py_add(a,b):
diff --git a/tests/run/numpy_pythran_unit.pyx b/tests/run/numpy_pythran_unit.pyx
new file mode 100644 (file)
index 0000000..4637e66
--- /dev/null
@@ -0,0 +1,25 @@
+# mode: run
+# tag: pythran, numpy, cpp
+# cython: np_pythran=True
+
+import numpy as np
+cimport numpy as np
+
+def trigo(np.ndarray[double, ndim=1] angles):
+
+    """
+    >>> a = np.array([0., np.pi, np.pi *2])
+    >>> trigo(a)
+    array([ 1., -1.,  1.])
+    """
+    return np.cos(angles)
+
+def power(np.ndarray[double, ndim=1] values):
+
+    """
+    >>> a = np.array([0., 1., 2.])
+    >>> res = power(a)
+    >>> res[0], res[1], res[2]
+    (0.0, 1.0, 8.0)
+    """
+    return values ** 3
index 98b1599814fbe48f3b101057c20982d8e18d0e6d..22b62517ec493a7c62a391b4622dc68225d1cf9a 100644 (file)
@@ -59,11 +59,14 @@ def run_sub():
     assert 0 == run_in_subinterpreter(b'1+1')
     assert 0 == run_in_subinterpreter(b'2+2')
 
-    assert 0 == run_in_subinterpreter(b'import package')
-    assert 0 == run_in_subinterpreter(b'import package')
+    # The subinterpreter does not add the current working directory to
+    # sys.path, so we need to add it manually.
+    pre = b'import sys; sys.path.insert(0, "."); '
+    assert 0 == run_in_subinterpreter(pre + b'import package')
+    assert 0 == run_in_subinterpreter(pre + b'import package')
 
     import sys
-    result = run_in_subinterpreter(b'import package.subtest')
+    result = run_in_subinterpreter(pre + b'import package.subtest')
     if not MAIN_HAS_IMPORTED:
         assert result == 0, result  # imports only in subinterpreters are ok
     elif sys.version_info >= (3, 5):