Imported Upstream version 0.29.6 upstream/0.29.6
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:04:57 +0000 (12:04 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 03:04:57 +0000 (12:04 +0900)
19 files changed:
CHANGES.rst
Cython/Compiler/ExprNodes.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
Cython/Shadow.py
Cython/Utility/Buffer.c
Cython/Utility/CythonFunction.c
Cython/Utility/ObjectHandling.c
Cython/Utility/Optimize.c
Cython/Utility/Overflow.c
Cython/Utility/TypeConversion.c
docs/examples/tutorial/clibraries/queue3.pyx
docs/examples/userguide/memoryviews/quickstart.pyx
docs/src/userguide/early_binding_for_speed.rst
test-requirements-cpython.txt
tests/buffers/buffmt.pyx
tests/run/cpdef_method_override.pyx
tests/run/cpp_stl_string_utf8_auto_encoding.pyx [new file with mode: 0644]
tests/run/fused_def.pyx

index 95f59e36d3b230a874388e25717af8e1eb38c9ae..3048314c469b1f2319eb0d6a36e0518353a40c4b 100644 (file)
@@ -2,6 +2,26 @@
 Cython Changelog
 ================
 
+0.29.6 (2019-02-27)
+===================
+
+Bugs fixed
+----------
+
+* Fix a crash when accessing the ``__kwdefaults__`` special attribute of
+  fused functions.  (Github issue #1470)
+
+* Fix the parsing of buffer format strings that contain numeric sizes, which
+  could lead to incorrect input rejections.  (Github issue #2845)
+
+* Avoid a C #pragma in old gcc versions that was only added in GCC 4.6.
+  Patch by Michael Anselmi.  (Github issue #2838)
+
+* Auto-encoding of Unicode strings to UTF-8 C/C++ strings failed in Python 3,
+  even though the default encoding there is UTF-8.
+  (Github issue #2819)
+
+
 0.29.5 (2019-02-09)
 ===================
 
index 39846c67b3c6e85902da984600eb42c71b7ad338..ed08eeb8a5ff1a92ad6be561b88e1102b03d28ab 100644 (file)
@@ -9460,7 +9460,8 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
         if self.defaults_kwdict:
             code.putln('__Pyx_CyFunction_SetDefaultsKwDict(%s, %s);' % (
                 self.result(), self.defaults_kwdict.py_result()))
-        if def_node.defaults_getter:
+        if def_node.defaults_getter and not self.specialized_cpdefs:
+            # Fused functions do not support dynamic defaults, only their specialisations can have them for now.
             code.putln('__Pyx_CyFunction_SetDefaultsGetter(%s, %s);' % (
                 self.result(), def_node.defaults_getter.entry.pyfunc_cname))
         if self.annotations_dict:
@@ -11532,9 +11533,11 @@ class DivNode(NumBinopNode):
     def generate_evaluation_code(self, code):
         if not self.type.is_pyobject and not self.type.is_complex:
             if self.cdivision is None:
-                self.cdivision = (code.globalstate.directives['cdivision']
-                                    or not self.type.signed
-                                    or self.type.is_float)
+                self.cdivision = (
+                    code.globalstate.directives['cdivision']
+                    or self.type.is_float
+                    or ((self.type.is_numeric or self.type.is_enum) and not self.type.signed)
+                )
             if not self.cdivision:
                 code.globalstate.use_utility_code(
                     UtilityCode.load_cached("DivInt", "CMath.c").specialize(self.type))
index ce1a94289942243a603b304975a6f87427ba52b0..a3bce639a3c59174db85cbacdc8fd6f6ca9ed5ac 100644 (file)
@@ -693,10 +693,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         if c_string_type not in ('bytes', 'bytearray') and not c_string_encoding:
             error(self.pos, "a default encoding must be provided if c_string_type is not a byte type")
         code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII %s' % int(c_string_encoding == 'ascii'))
+        code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 %s' %
+                int(c_string_encoding.replace('-', '').lower() == 'utf8'))
         if c_string_encoding == 'default':
             code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT 1')
         else:
-            code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT 0')
+            code.putln('#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT '
+                    '(PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8)')
             code.putln('#define __PYX_DEFAULT_STRING_ENCODING "%s"' % c_string_encoding)
         if c_string_type == 'bytearray':
             c_string_func_name = 'ByteArray'
index be4683e0d47ac99949bbdfec19b2d882d9118735..9fe38390cc0ac2ba7d1bcb77a2c27d4046371438 100644 (file)
@@ -3443,8 +3443,8 @@ class DefNodeWrapper(FuncDefNode):
             if docstr.is_unicode:
                 docstr = docstr.as_utf8_string()
 
-            code.putln(
-                'static char %s[] = %s;' % (
+            if not (entry.is_special and entry.name in ('__getbuffer__', '__releasebuffer__')):
+                code.putln('static char %s[] = %s;' % (
                     entry.doc_cname,
                     docstr.as_c_string_literal()))
 
@@ -4354,7 +4354,7 @@ class OverrideCheckNode(StatNode):
                        " || (Py_TYPE(%s)->tp_flags & (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) {" % (
                 self_arg, self_arg))
 
-        code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP")
+        code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS")
         code.globalstate.use_utility_code(
             UtilityCode.load_cached("PyDictVersioning", "ObjectHandling.c"))
         # TODO: remove the object dict version check by 'inlining' the getattr implementation for methods.
@@ -4389,7 +4389,7 @@ class OverrideCheckNode(StatNode):
         # NOTE: it's not 100% sure that we catch the exact versions here that were used for the lookup,
         # but it is very unlikely that the versions change during lookup, and the type dict safe guard
         # should increase the chance of detecting such a case.
-        code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP")
+        code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS")
         code.putln("%s = __Pyx_get_tp_dict_version(%s);" % (
             Naming.tp_dict_version_temp, self_arg))
         code.putln("%s = __Pyx_get_object_dict_version(%s);" % (
@@ -4409,7 +4409,7 @@ class OverrideCheckNode(StatNode):
         code.put_decref_clear(func_node_temp, PyrexTypes.py_object_type)
         code.funcstate.release_temp(func_node_temp)
 
-        code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP")
+        code.putln("#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS")
         code.putln("}")
         code.putln("#endif")
 
index 0f2b145eb2a8bd689497a6699b39b7730e9a5e4e..67c45c7f2b215ef509f92008fff29ba8c1b3d5ba 100644 (file)
@@ -1,7 +1,7 @@
 # cython.* namespace for pure mode.
 from __future__ import absolute_import
 
-__version__ = "0.29.5"
+__version__ = "0.29.6"
 
 try:
     from __builtin__ import basestring
index 8842d11f89cf19e049f7bfb9bb894353f9d80d84..7f3a0b15e5a6d7b6183b62cd8e37fe427afc1d4e 100644 (file)
@@ -273,7 +273,7 @@ static int __Pyx_BufFmt_ParseNumber(const char** ts) {
       return -1;
     } else {
         count = *t++ - '0';
-        while (*t >= '0' && *t < '9') {
+        while (*t >= '0' && *t <= '9') {
             count *= 10;
             count += *t++ - '0';
         }
index 6ae80a0a2d8f85f3c44772a9905836350ffed853..ed8df547720a2503259ffe7ff9b8eead15caf3a2 100644 (file)
@@ -1216,7 +1216,7 @@ static int __pyx_FusedFunction_init(void) {
 //////////////////// ClassMethod.proto ////////////////////
 
 #include "descrobject.h"
-static PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/
+static CYTHON_UNUSED PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/
 
 //////////////////// ClassMethod ////////////////////
 
index d58fd42d46b37c9943778ebc01802a360b71477b..612d041bd71a848c8ba035c02f135f3b11e05e25 100644 (file)
@@ -2402,7 +2402,7 @@ static PyObject* __Pyx_PyNumber_InPlaceMatrixMultiply(PyObject* x, PyObject* y)
 
 /////////////// PyDictVersioning.proto ///////////////
 
-#if CYTHON_USE_DICT_VERSIONS
+#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS
 #define __PYX_DICT_VERSION_INIT  ((PY_UINT64_T) -1)
 #define __PYX_GET_DICT_VERSION(dict)  (((PyDictObject*)(dict))->ma_version_tag)
 #define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) \
@@ -2432,24 +2432,28 @@ static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UIN
 
 /////////////// PyDictVersioning ///////////////
 
-#if CYTHON_USE_DICT_VERSIONS
+#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS
 static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) {
     PyObject *dict = Py_TYPE(obj)->tp_dict;
-    return dict ? __PYX_GET_DICT_VERSION(dict) : 0;
+    return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0;
 }
 
 static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) {
     PyObject **dictptr = NULL;
     Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset;
     if (offset) {
-        dictptr = (offset > 0) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj);
+#if CYTHON_COMPILING_IN_CPYTHON
+        dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj);
+#else
+        dictptr = _PyObject_GetDictPtr(obj);
+#endif
     }
     return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0;
 }
 
 static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) {
     PyObject *dict = Py_TYPE(obj)->tp_dict;
-    if (!dict || tp_dict_version != __PYX_GET_DICT_VERSION(dict))
+    if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict)))
         return 0;
     return obj_dict_version == __Pyx_get_object_dict_version(obj);
 }
index 04b3ec75aab3188cd0fa5d15982ea5140e6fc7cb..22d163461aa28818992528754d49d220b70efa11 100644 (file)
@@ -123,13 +123,13 @@ static PyObject* __Pyx__PyList_PopIndex(PyObject* L, PyObject* py_ix, Py_ssize_t
 #define __Pyx_PyObject_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) ( \
     (likely(PyList_CheckExact(L) && __Pyx_fits_Py_ssize_t(ix, type, is_signed))) ? \
         __Pyx__PyList_PopIndex(L, py_ix, ix) : ( \
-        (unlikely(py_ix == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \
+        (unlikely((py_ix) == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \
             __Pyx__PyObject_PopIndex(L, py_ix)))
 
 #define __Pyx_PyList_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) ( \
     __Pyx_fits_Py_ssize_t(ix, type, is_signed) ? \
         __Pyx__PyList_PopIndex(L, py_ix, ix) : ( \
-        (unlikely(py_ix == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \
+        (unlikely((py_ix) == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \
             __Pyx__PyObject_PopIndex(L, py_ix)))
 
 #else
@@ -138,7 +138,7 @@ static PyObject* __Pyx__PyList_PopIndex(PyObject* L, PyObject* py_ix, Py_ssize_t
     __Pyx_PyObject_PopIndex(L, py_ix, ix, is_signed, type, to_py_func)
 
 #define __Pyx_PyObject_PopIndex(L, py_ix, ix, is_signed, type, to_py_func) ( \
-    (unlikely(py_ix == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \
+    (unlikely((py_ix) == Py_None)) ? __Pyx__PyObject_PopNewIndex(L, to_py_func(ix)) : \
         __Pyx__PyObject_PopIndex(L, py_ix))
 #endif
 
index 6ddcf3b25280c7c56ee3b572511c2670b258001c..8629bafaea8578fc9cb0c301b6e7bfc3deb1e7fb 100644 (file)
@@ -47,8 +47,12 @@ static int __Pyx_check_twos_complement(void) {
 #define __Pyx_div_const_no_overflow(a, b, overflow) ((a) / (b))
 
 /////////////// Common.init ///////////////
+//@substitute: naming
 
-__Pyx_check_twos_complement();
+// FIXME: Propagate the error here instead of just printing it.
+if (unlikely(__Pyx_check_twos_complement())) {
+    PyErr_WriteUnraisable($module_cname);
+}
 
 /////////////// BaseCaseUnsigned.proto ///////////////
 
@@ -226,8 +230,12 @@ static CYTHON_INLINE {{INT}} __Pyx_div_{{NAME}}_checking_overflow({{INT}} a, {{I
 
 
 /////////////// SizeCheck.init ///////////////
+//@substitute: naming
 
-__Pyx_check_sane_{{NAME}}();
+// FIXME: Propagate the error here instead of just printing it.
+if (unlikely(__Pyx_check_sane_{{NAME}}())) {
+    PyErr_WriteUnraisable($module_cname);
+}
 
 /////////////// SizeCheck.proto ///////////////
 
index 9cba1b04cfed21a6298768a99004160ba3075770..1983457902eb92095703b90144c679daa6ec6898 100644 (file)
@@ -702,6 +702,10 @@ static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value, Py_ssize_t wid
 
 // NOTE: inlining because most arguments are constant, which collapses lots of code below
 
+// GCC diagnostic pragmas were introduced in GCC 4.6
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#define GCC_DIAGNOSTIC
+#endif
 static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value, Py_ssize_t width, char padding_char, char format_char) {
     // simple and conservative C string allocation on the stack: each byte gives at most 3 digits, plus sign
     char digits[sizeof({{TYPE}})*3+2];
@@ -711,12 +715,12 @@ static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value, Py_ssize_t wid
     Py_ssize_t length, ulength;
     int prepend_sign, last_one_off;
     {{TYPE}} remaining;
-#ifdef __GNUC__
+#ifdef GCC_DIAGNOSTIC
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wconversion"
 #endif
     const {{TYPE}} neg_one = ({{TYPE}}) -1, const_zero = ({{TYPE}}) 0;
-#ifdef __GNUC__
+#ifdef GCC_DIAGNOSTIC
 #pragma GCC diagnostic pop
 #endif
     const int is_unsigned = neg_one > const_zero;
index 38d26c6a428a3927512a513f0e769aeaa89c1690..cc84cf1722d21d4ccffae1e103833843383aa5d1 100644 (file)
@@ -1,61 +1,61 @@
-# queue.pyx\r
-\r
-cimport cqueue\r
-\r
-cdef class Queue:\r
-    """A queue class for C integer values.\r
-\r
-    >>> q = Queue()\r
-    >>> q.append(5)\r
-    >>> q.peek()\r
-    5\r
-    >>> q.pop()\r
-    5\r
-    """\r
-    cdef cqueue.Queue* _c_queue\r
-    def __cinit__(self):\r
-        self._c_queue = cqueue.queue_new()\r
-        if self._c_queue is NULL:\r
-            raise MemoryError()\r
-\r
-    def __dealloc__(self):\r
-        if self._c_queue is not NULL:\r
-            cqueue.queue_free(self._c_queue)\r
-\r
-    cpdef append(self, int value):\r
-        if not cqueue.queue_push_tail(self._c_queue,\r
-                                      <void*> value):\r
-            raise MemoryError()\r
-\r
-    # The `cpdef` feature is obviously not available for the original "extend()"\r
-    # method, as the method signature is incompatible with Python argument\r
-    # types (Python does not have pointers).  However, we can rename\r
-    # the C-ish "extend()" method to e.g. "extend_ints()", and write\r
-    # a new "extend()" method that provides a suitable Python interface by\r
-    # accepting an arbitrary Python iterable.\r
-    cpdef extend(self, values):\r
-        for value in values:\r
-            self.append(value)\r
-\r
-    cdef extend_ints(self, int* values, size_t count):\r
-        cdef int value\r
-        for value in values[:count]:  # Slicing pointer to limit the iteration boundaries.\r
-            self.append(value)\r
-\r
-    cpdef int peek(self) except? -1:\r
-        cdef int value = <Py_ssize_t> cqueue.queue_peek_head(self._c_queue)\r
-\r
-        if value == 0:\r
-            # this may mean that the queue is empty,\r
-            # or that it happens to contain a 0 value\r
-            if cqueue.queue_is_empty(self._c_queue):\r
-                raise IndexError("Queue is empty")\r
-        return value\r
-\r
-    cpdef int pop(self) except? -1:\r
-        if cqueue.queue_is_empty(self._c_queue):\r
-            raise IndexError("Queue is empty")\r
-        return <Py_ssize_t> cqueue.queue_pop_head(self._c_queue)\r
-\r
-    def __bool__(self):\r
-        return not cqueue.queue_is_empty(self._c_queue)\r
+# queue.pyx
+
+cimport cqueue
+
+cdef class Queue:
+    """A queue class for C integer values.
+
+    >>> q = Queue()
+    >>> q.append(5)
+    >>> q.peek()
+    5
+    >>> q.pop()
+    5
+    """
+    cdef cqueue.Queue* _c_queue
+    def __cinit__(self):
+        self._c_queue = cqueue.queue_new()
+        if self._c_queue is NULL:
+            raise MemoryError()
+
+    def __dealloc__(self):
+        if self._c_queue is not NULL:
+            cqueue.queue_free(self._c_queue)
+
+    cpdef append(self, int value):
+        if not cqueue.queue_push_tail(self._c_queue,
+                                      <void*> <Py_ssize_t> value):
+            raise MemoryError()
+
+    # The `cpdef` feature is obviously not available for the original "extend()"
+    # method, as the method signature is incompatible with Python argument
+    # types (Python does not have pointers).  However, we can rename
+    # the C-ish "extend()" method to e.g. "extend_ints()", and write
+    # a new "extend()" method that provides a suitable Python interface by
+    # accepting an arbitrary Python iterable.
+    cpdef extend(self, values):
+        for value in values:
+            self.append(value)
+
+    cdef extend_ints(self, int* values, size_t count):
+        cdef int value
+        for value in values[:count]:  # Slicing pointer to limit the iteration boundaries.
+            self.append(value)
+
+    cpdef int peek(self) except? -1:
+        cdef int value = <Py_ssize_t> cqueue.queue_peek_head(self._c_queue)
+
+        if value == 0:
+            # this may mean that the queue is empty,
+            # or that it happens to contain a 0 value
+            if cqueue.queue_is_empty(self._c_queue):
+                raise IndexError("Queue is empty")
+        return value
+
+    cpdef int pop(self) except? -1:
+        if cqueue.queue_is_empty(self._c_queue):
+            raise IndexError("Queue is empty")
+        return <Py_ssize_t> cqueue.queue_pop_head(self._c_queue)
+
+    def __bool__(self):
+        return not cqueue.queue_is_empty(self._c_queue)
index 5066f8a34393ac1f1608008de120ca5aef91f750..58335c0cffefd773202a8447a86449b974f76c47 100644 (file)
@@ -1,52 +1,52 @@
-from cython.view cimport array as cvarray\r
-import numpy as np\r
-\r
-# Memoryview on a NumPy array\r
-narr = np.arange(27, dtype=np.dtype("i")).reshape((3, 3, 3))\r
-cdef int [:, :, :] narr_view = narr\r
-\r
-# Memoryview on a C array\r
-cdef int carr[3][3][3]\r
-cdef int [:, :, :] carr_view = carr\r
-\r
-# Memoryview on a Cython array\r
-cyarr = cvarray(shape=(3, 3, 3), itemsize=sizeof(int), format="i")\r
-cdef int [:, :, :] cyarr_view = cyarr\r
-\r
-# Show the sum of all the arrays before altering it\r
-print("NumPy sum of the NumPy array before assignments: %s" % narr.sum())\r
-\r
-# We can copy the values from one memoryview into another using a single\r
-# statement, by either indexing with ... or (NumPy-style) with a colon.\r
-carr_view[...] = narr_view\r
-cyarr_view[:] = narr_view\r
-# NumPy-style syntax for assigning a single value to all elements.\r
-narr_view[:, :, :] = 3\r
-\r
-# Just to distinguish the arrays\r
-carr_view[0, 0, 0] = 100\r
-cyarr_view[0, 0, 0] = 1000\r
-\r
-# Assigning into the memoryview on the NumPy array alters the latter\r
-print("NumPy sum of NumPy array after assignments: %s" % narr.sum())\r
-\r
-# A function using a memoryview does not usually need the GIL\r
-cpdef int sum3d(int[:, :, :] arr) nogil:\r
-    cdef size_t i, j, k\r
-    cdef int total = 0\r
-    I = arr.shape[0]\r
-    J = arr.shape[1]\r
-    K = arr.shape[2]\r
-    for i in range(I):\r
-        for j in range(J):\r
-            for k in range(K):\r
-                total += arr[i, j, k]\r
-    return total\r
-\r
-# A function accepting a memoryview knows how to use a NumPy array,\r
-# a C array, a Cython array...\r
-print("Memoryview sum of NumPy array is %s" % sum3d(narr))\r
-print("Memoryview sum of C array is %s" % sum3d(carr))\r
-print("Memoryview sum of Cython array is %s" % sum3d(cyarr))\r
-# ... and of course, a memoryview.\r
-print("Memoryview sum of C memoryview is %s" % sum3d(carr_view))\r
+from cython.view cimport array as cvarray
+import numpy as np
+
+# Memoryview on a NumPy array
+narr = np.arange(27, dtype=np.dtype("i")).reshape((3, 3, 3))
+cdef int [:, :, :] narr_view = narr
+
+# Memoryview on a C array
+cdef int carr[3][3][3]
+cdef int [:, :, :] carr_view = carr
+
+# Memoryview on a Cython array
+cyarr = cvarray(shape=(3, 3, 3), itemsize=sizeof(int), format="i")
+cdef int [:, :, :] cyarr_view = cyarr
+
+# Show the sum of all the arrays before altering it
+print("NumPy sum of the NumPy array before assignments: %s" % narr.sum())
+
+# We can copy the values from one memoryview into another using a single
+# statement, by either indexing with ... or (NumPy-style) with a colon.
+carr_view[...] = narr_view
+cyarr_view[:] = narr_view
+# NumPy-style syntax for assigning a single value to all elements.
+narr_view[:, :, :] = 3
+
+# Just to distinguish the arrays
+carr_view[0, 0, 0] = 100
+cyarr_view[0, 0, 0] = 1000
+
+# Assigning into the memoryview on the NumPy array alters the latter
+print("NumPy sum of NumPy array after assignments: %s" % narr.sum())
+
+# A function using a memoryview does not usually need the GIL
+cpdef int sum3d(int[:, :, :] arr) nogil:
+    cdef size_t i, j, k, I, J, K
+    cdef int total = 0
+    I = arr.shape[0]
+    J = arr.shape[1]
+    K = arr.shape[2]
+    for i in range(I):
+        for j in range(J):
+            for k in range(K):
+                total += arr[i, j, k]
+    return total
+
+# A function accepting a memoryview knows how to use a NumPy array,
+# a C array, a Cython array...
+print("Memoryview sum of NumPy array is %s" % sum3d(narr))
+print("Memoryview sum of C array is %s" % sum3d(carr))
+print("Memoryview sum of Cython array is %s" % sum3d(cyarr))
+# ... and of course, a memoryview.
+print("Memoryview sum of C memoryview is %s" % sum3d(carr_view))
index 28eab56bd7ca7f14865ad92b4288da0cc5579e1d..9bb8cf7249e16a1c2e70bf137da1fe12b21e120d 100644 (file)
@@ -55,7 +55,7 @@ efficiently callable as a C function, but still accessible from pure Python
 If within Cython code, we have a variable already 'early-bound' (ie, declared
 explicitly as type Rectangle, (or cast to type Rectangle), then invoking its
 area method will use the efficient C code path and skip the Python overhead.
-But if in Pyrex or regular Python code we have a regular object variable
+But if in Cython or regular Python code we have a regular object variable
 storing a Rectangle object, then invoking the area method will require:
 
 * an attribute lookup for the area method
index 39c438f274d708be8aa449c58ac91dee20c6ea78..db74d13ce469002a2b05ee5abfd405e2eb3f32d8 100644 (file)
@@ -1,2 +1,4 @@
 jupyter
 line_profiler
+# transitive dependency of jupyter (17.0+ lacks wheels for Py3.4)
+pyzmq<17
index be131a7acb87fc33d8fe4330e6385fc9a03a6de8..851193f3f844d0fcf6e6ed762c804a7aa0ff9115 100644 (file)
@@ -37,7 +37,7 @@ if int_align != 4 or sizeof(int) != 4:
 cdef class MockBuffer:
     cdef Py_ssize_t zero
     cdef Py_ssize_t minusone
-    cdef object format
+    cdef bytes format
     cdef object itemsize
 
     def __init__(self, format, itemsize):
@@ -117,6 +117,9 @@ ctypedef struct Char3Int:
     int c
     int d
 
+ctypedef struct LongString:
+    char[90198] c
+
 cdef struct CharIntCFloat:
     char a
     int b
@@ -180,6 +183,16 @@ def char3int(fmt):
     cdef object obj = MockBuffer(fmt, sizeof(Char3Int))
     cdef object[Char3Int, ndim=1] buf = obj
 
+
+@testcase
+def long_string(fmt):
+    """
+    >>> long_string("90198s")
+    """
+    cdef object obj = MockBuffer(fmt, sizeof(LongString))
+    cdef object[LongString, ndim=1] buf = obj
+
+
 @testcase
 def unpacked_struct(fmt):
     """
index ea23c658f7a140212339f10b1e44b42d9a79b1ba..97aafe56254200a34f92c98446692ccbf2c3c8f3 100644 (file)
@@ -31,12 +31,35 @@ cdef class BaseType:
     BaseType.meth
     BaseType.meth
     """
-    def callmeth(self):
+    cpdef callmeth(self):
+        return self.callmeth2()
+    cpdef callmeth2(self):
+        # not overridden by subclasses
         return self.meth()
     cpdef meth(self):
+        # overridden by subclasses
         print("BaseType.meth")
 
 
+class NonOverride(BaseType):
+    """
+    >>> NonOverride().callmeth()
+    BaseType.meth
+    >>> obj = NonOverride()
+    >>> obj.callmeth()
+    BaseType.meth
+    >>> obj.callmeth()
+    BaseType.meth
+    >>> _call_method(NonOverride)
+    BaseType.meth
+    BaseType.meth
+    BaseType.meth
+    BaseType.meth
+    BaseType.meth
+    BaseType.meth
+    """
+
+
 class PyClass(BaseType):
     """
     >>> PyClass().callmeth()
@@ -83,3 +106,34 @@ class PySlotsClass(BaseType):
 
     def meth(self):
         print("PySlotsClass.meth")
+
+
+class DynamicOverride(BaseType):
+    """
+    >>> DynamicOverride().callmeth()
+    meth1
+    >>> obj = DynamicOverride()
+    >>> obj.callmeth()
+    meth1
+    >>> obj.callmeth()
+    meth2
+    >>> obj.callmeth()
+    BaseType.meth
+    >>> obj.callmeth()
+    BaseType.meth
+    >>> _call_method(DynamicOverride)
+    meth1
+    meth1
+    meth2
+    meth1
+    meth2
+    BaseType.meth
+    """
+    def __init__(self):
+        self.meth = self.meth1
+    def meth1(self):
+        self.meth = self.meth2
+        print("meth1")
+    def meth2(self):
+        del self.meth
+        print("meth2")
diff --git a/tests/run/cpp_stl_string_utf8_auto_encoding.pyx b/tests/run/cpp_stl_string_utf8_auto_encoding.pyx
new file mode 100644 (file)
index 0000000..ef81adb
--- /dev/null
@@ -0,0 +1,150 @@
+# mode: run
+# tag: cpp, werror
+# cython: c_string_encoding=utf-8, c_string_type=unicode
+
+cimport cython
+
+from libcpp.string cimport string
+
+b_asdf = b'asdf'
+s_asdf = 'asdf'
+u_asdf = u'asdf'
+u_s = u's'
+
+
+def test_conversion(py_obj):
+    """
+    >>> test_conversion(b_asdf) == u_asdf or test_conversion(b_asdf)
+    True
+    >>> test_conversion(u_asdf) == u_asdf or test_conversion(u_asdf)
+    True
+    >>> test_conversion(123)  # doctest: +ELLIPSIS
+    Traceback (most recent call last):
+    TypeError: expected ..., int found
+    """
+    cdef string s = py_obj
+    assert <size_t>len(py_obj) == s.length(), '%d != %d' % (len(py_obj), s.length())
+    return s
+
+
+def test_empty(py_obj):
+    """
+    >>> test_empty('')
+    True
+    >>> test_empty('abc')
+    False
+    >>> test_empty(u_asdf[:0])
+    True
+    >>> test_empty(u_asdf)
+    False
+    """
+    cdef string a = py_obj
+    return a.empty()
+
+
+def test_push_back(a):
+    """
+    >>> test_push_back(b_asdf) == u_asdf + u_s
+    True
+    >>> test_push_back(u_asdf) == u_asdf + u_s
+    True
+    """
+    cdef string s = a
+    s.push_back(<char>ord('s'))
+    return s
+
+
+def test_clear(a):
+    """
+    >>> test_clear(u_asdf) == u_s[:0]
+    True
+    >>> test_clear(b_asdf) == u_s[:0]
+    True
+    """
+    cdef string s = a
+    s.clear()
+    return s
+
+
+def test_assign(char *a):
+    """
+    >>> test_assign(b_asdf) == 'ggg'
+    True
+    """
+    cdef string s = string(a)
+    s.assign(<char *>"ggg")
+    return s.c_str()
+
+
+def test_bytes_cast(a):
+    """
+    >>> b = test_bytes_cast(b'abc')
+    >>> isinstance(b, bytes)
+    True
+    >>> print(b.decode('ascii'))
+    abc
+    >>> b = test_bytes_cast(b'abc\\xe4\\xfc')
+    >>> isinstance(b, bytes)
+    True
+    >>> len(b)
+    5
+    >>> print(b[:3].decode('ascii'))
+    abc
+    >>> print(ord(b[3:4]))
+    228
+    >>> print(ord(b[4:5]))
+    252
+    """
+    cdef string s = a
+    assert s.length() == <size_t>len(a), "%d != %d" % (s.length(), len(a))
+    return <bytes>s
+
+
+def test_bytearray_cast(a):
+    """
+    >>> b = test_bytearray_cast(b'abc')
+    >>> isinstance(b, bytearray)
+    True
+    >>> print(b.decode('ascii'))
+    abc
+    >>> b = test_bytearray_cast(b'abc\\xe4\\xfc')
+    >>> isinstance(b, bytearray)
+    True
+    >>> len(b)
+    5
+    >>> print(b[:3].decode('ascii'))
+    abc
+    >>> print(ord(b[3:4]))
+    228
+    >>> print(ord(b[4:5]))
+    252
+    """
+    cdef string s = a
+    assert s.length() == <size_t>len(a), "%d != %d" % (s.length(), len(a))
+    return <bytearray>s
+
+
+def test_unicode_cast(a):
+    """
+    >>> u = test_unicode_cast(b'abc')
+    >>> type(u) is type(u_asdf) or type(u)
+    True
+    >>> print(u)
+    abc
+    """
+    cdef string s = a
+    assert s.length() == <size_t>len(a), "%d != %d" % (s.length(), len(a))
+    return <unicode>s
+
+
+def test_str_cast(a):
+    """
+    >>> s = test_str_cast(b'abc')
+    >>> type(s) is type(s_asdf) or type(s)
+    True
+    >>> print(s)
+    abc
+    """
+    cdef string s = a
+    assert s.length() == <size_t>len(a), "%d != %d" % (s.length(), len(a))
+    return <str>s
index 10e3c61e23ebeff1ea0bfcd24ba9cb24d3cda5c7..9f30142f33b4305e694a5c4f21a7fbafee299b04 100644 (file)
@@ -58,12 +58,21 @@ def opt_func(fused_t obj, cython.floating myf = 1.2, cython.integral myi = 7):
     >>> opt_func("spam", f, i)
     str object double long
     spam 5.60 9 5.60 9
+    >>> opt_func("spam", f, myi=i)
+    str object double long
+    spam 5.60 9 5.60 9
+    >>> opt_func("spam", myf=f, myi=i)
+    str object double long
+    spam 5.60 9 5.60 9
     >>> opt_func[str, float, int]("spam", f, i)
     str object float int
     spam 5.60 9 5.60 9
     >>> opt_func[str, cy.double, cy.long]("spam", f, i)
     str object double long
     spam 5.60 9 5.60 9
+    >>> opt_func[str, cy.double, cy.long]("spam", f, myi=i)
+    str object double long
+    spam 5.60 9 5.60 9
     >>> opt_func[str, float, cy.int]("spam", f, i)
     str object float int
     spam 5.60 9 5.60 9
@@ -129,6 +138,28 @@ def test_opt_func():
     opt_func("ham", f, entry4)
 
 
+def test_opt_func_introspection():
+    """
+    >>> opt_func.__defaults__
+    (1.2, 7)
+    >>> opt_func.__kwdefaults__
+    >>> opt_func.__annotations__
+    {}
+
+    >>> opt_func[str, float, int].__defaults__
+    (1.2, 7)
+    >>> opt_func[str, float, int].__kwdefaults__
+    >>> opt_func[str, float, int].__annotations__
+    {}
+
+    >>> opt_func[str, cy.double, cy.long].__defaults__
+    (1.2, 7)
+    >>> opt_func[str, cy.double, cy.long].__kwdefaults__
+    >>> opt_func[str, cy.double, cy.long].__annotations__
+    {}
+    """
+
+
 def func_with_object(fused_with_object obj, cython.integral myi = 7):
     """
     >>> func_with_object(1)