Commit a261a911 authored by Robert Bradshaw's avatar Robert Bradshaw

Merge branch 'master' into 0.20.x

parents bbd49a35 8ce5dbcb
...@@ -23,6 +23,9 @@ Features added ...@@ -23,6 +23,9 @@ Features added
* Constant Python float values are cached. * Constant Python float values are cached.
* String/Unicode formatting using the '%' operator uses a faster
C-API call.
* ``bytearray`` has become a known type and supports coercion from and * ``bytearray`` has become a known type and supports coercion from and
to C strings. Indexing, slicing and decoding is optimised. Note that to C strings. Indexing, slicing and decoding is optimised. Note that
this may have an impact on existing code due to type inference. this may have an impact on existing code due to type inference.
...@@ -64,6 +67,9 @@ Features added ...@@ -64,6 +67,9 @@ Features added
oft-used utility code once in a separate directory rather than as oft-used utility code once in a separate directory rather than as
part of each generated file. part of each generated file.
* ``unraisable_tracebacks`` directive added to control printing of
tracebacks of unraisable exceptions.
Bugs fixed Bugs fixed
---------- ----------
......
...@@ -2077,9 +2077,10 @@ class CCodeWriter(object): ...@@ -2077,9 +2077,10 @@ class CCodeWriter(object):
Naming.clineno_cname, Naming.clineno_cname,
Naming.lineno_cname, Naming.lineno_cname,
Naming.filename_cname, Naming.filename_cname,
int(self.globalstate.directives['unraisable_tracebacks'])
) )
self.funcstate.uses_error_indicator = True self.funcstate.uses_error_indicator = True
self.putln('__Pyx_WriteUnraisable("%s", %s, %s, %s);' % format_tuple) self.putln('__Pyx_WriteUnraisable("%s", %s, %s, %s, %s);' % format_tuple)
self.globalstate.use_utility_code( self.globalstate.use_utility_code(
UtilityCode.load_cached("WriteUnraisableException", "Exceptions.c")) UtilityCode.load_cached("WriteUnraisableException", "Exceptions.c"))
......
...@@ -2538,6 +2538,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2538,6 +2538,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
'__releasebuffer__') '__releasebuffer__')
if (func.is_special and Options.docstrings and if (func.is_special and Options.docstrings and
func.wrapperbase_cname and not is_buffer): func.wrapperbase_cname and not is_buffer):
slot = TypeSlots.method_name_to_slot[func.name]
preprocessor_guard = slot.preprocessor_guard_code()
if preprocessor_guard:
code.putln(preprocessor_guard)
code.putln('#if CYTHON_COMPILING_IN_CPYTHON') code.putln('#if CYTHON_COMPILING_IN_CPYTHON')
code.putln("{") code.putln("{")
code.putln( code.putln(
...@@ -2558,6 +2562,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2558,6 +2562,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("}") code.putln("}")
code.putln("}") code.putln("}")
code.putln('#endif') code.putln('#endif')
if preprocessor_guard:
code.putln('#endif')
if type.vtable_cname: if type.vtable_cname:
code.putln( code.putln(
"if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % ( "if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % (
......
...@@ -1245,7 +1245,9 @@ class CVarDefNode(StatNode): ...@@ -1245,7 +1245,9 @@ class CVarDefNode(StatNode):
if (len(self.declarators) > 1 if (len(self.declarators) > 1
and not isinstance(declarator, CNameDeclaratorNode) and not isinstance(declarator, CNameDeclaratorNode)
and env.directives['warn.multiple_declarators']): and env.directives['warn.multiple_declarators']):
warning(declarator.pos, "Non-trivial type declarators in shared declaration.", 1) warning(declarator.pos,
"Non-trivial type declarators in shared declaration (e.g. mix of pointers and values). " +
"Each pointer declaration should be on its own line.", 1)
if isinstance(declarator, CFuncDeclaratorNode): if isinstance(declarator, CFuncDeclaratorNode):
name_declarator, type = declarator.analyse(base_type, env, directive_locals=self.directive_locals) name_declarator, type = declarator.analyse(base_type, env, directive_locals=self.directive_locals)
......
...@@ -112,6 +112,7 @@ directive_defaults = { ...@@ -112,6 +112,7 @@ directive_defaults = {
'c_string_type': 'bytes', 'c_string_type': 'bytes',
'c_string_encoding': '', 'c_string_encoding': '',
'type_version_tag': True, # enables Py_TPFLAGS_HAVE_VERSION_TAG on extension types 'type_version_tag': True, # enables Py_TPFLAGS_HAVE_VERSION_TAG on extension types
'unraisable_tracebacks': False,
# set __file__ and/or __path__ to known source/target path at import time (instead of not having them available) # set __file__ and/or __path__ to known source/target path at import time (instead of not having them available)
'set_initial_path' : None, # SOURCEFILE or "/full/path/to/module" 'set_initial_path' : None, # SOURCEFILE or "/full/path/to/module"
......
...@@ -6,6 +6,7 @@ import DebugFlags ...@@ -6,6 +6,7 @@ import DebugFlags
import Options import Options
from Visitor import CythonTransform from Visitor import CythonTransform
from Errors import CompileError, InternalError, AbortError from Errors import CompileError, InternalError, AbortError
import Naming
# #
# Really small pipeline stages # Really small pipeline stages
...@@ -279,6 +280,9 @@ def create_pyx_as_pxd_pipeline(context, result): ...@@ -279,6 +280,9 @@ def create_pyx_as_pxd_pipeline(context, result):
for entry in root.scope.entries.values(): for entry in root.scope.entries.values():
if not entry.in_cinclude: if not entry.in_cinclude:
entry.defined_in_pxd = 1 entry.defined_in_pxd = 1
if entry.name == entry.cname and entry.visibility != 'extern':
# Always mangle non-extern cimported entries.
entry.cname = entry.scope.mangle(Naming.func_prefix, entry.name)
return StatListNode(root.pos, stats=[]), root.scope return StatListNode(root.pos, stats=[]), root.scope
pipeline.append(fake_pxd) pipeline.append(fake_pxd)
return pipeline return pipeline
......
...@@ -417,16 +417,22 @@ static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, ...@@ -417,16 +417,22 @@ static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value,
/////////////// WriteUnraisableException.proto /////////////// /////////////// WriteUnraisableException.proto ///////////////
static void __Pyx_WriteUnraisable(const char *name, int clineno, static void __Pyx_WriteUnraisable(const char *name, int clineno,
int lineno, const char *filename); /*proto*/ int lineno, const char *filename,
int full_traceback); /*proto*/
/////////////// WriteUnraisableException /////////////// /////////////// WriteUnraisableException ///////////////
//@requires: PyErrFetchRestore //@requires: PyErrFetchRestore
static void __Pyx_WriteUnraisable(const char *name, CYTHON_UNUSED int clineno, static void __Pyx_WriteUnraisable(const char *name, CYTHON_UNUSED int clineno,
CYTHON_UNUSED int lineno, CYTHON_UNUSED const char *filename) { CYTHON_UNUSED int lineno, CYTHON_UNUSED const char *filename,
int full_traceback) {
PyObject *old_exc, *old_val, *old_tb; PyObject *old_exc, *old_val, *old_tb;
PyObject *ctx; PyObject *ctx;
__Pyx_ErrFetch(&old_exc, &old_val, &old_tb); __Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
if (full_traceback) {
__Pyx_ErrRestore(old_exc, old_val, old_tb);
PyErr_PrintEx(1);
}
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
ctx = PyString_FromString(name); ctx = PyString_FromString(name);
#else #else
......
...@@ -695,13 +695,18 @@ static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyO ...@@ -695,13 +695,18 @@ static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyO
PyErr_SetString(PyExc_ValueError, "string must be of size 1"); PyErr_SetString(PyExc_ValueError, "string must be of size 1");
return -1; return -1;
} }
ival = PyString_AS_STRING(value)[0]; ival = (unsigned char) (PyString_AS_STRING(value)[0]);
} else } else
#endif #endif
{ {
// CPython calls PyNumber_Index() internally
ival = __Pyx_PyIndex_AsSsize_t(value); ival = __Pyx_PyIndex_AsSsize_t(value);
if (unlikely(ival == -1 && PyErr_Occurred())) if (unlikely((ival < 0) | (ival > 255))) {
if (ival == -1 && PyErr_Occurred())
return -1; return -1;
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
return -1;
}
} }
return __Pyx_PyByteArray_Append(bytearray, ival); return __Pyx_PyByteArray_Append(bytearray, ival);
} }
...@@ -713,7 +718,6 @@ static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, int value ...@@ -713,7 +718,6 @@ static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, int value
//////////////////// ByteArrayAppend //////////////////// //////////////////// ByteArrayAppend ////////////////////
//@requires: ObjectHandling.c::PyObjectCallMethod //@requires: ObjectHandling.c::PyObjectCallMethod
// signature uses Py_ssize_t to make coercions use PyNumber_Index(), as CPython does
static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, int value) { static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, int value) {
PyObject *pyval, *retval; PyObject *pyval, *retval;
#if CYTHON_COMPILING_IN_CPYTHON #if CYTHON_COMPILING_IN_CPYTHON
......
...@@ -276,11 +276,34 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) { ...@@ -276,11 +276,34 @@ static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) {
return res; return res;
} }
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
#if CYTHON_USE_PYLONG_INTERNALS
#include "longintrepr.h"
#endif
#endif
static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) {
Py_ssize_t ival; Py_ssize_t ival;
PyObject *x; PyObject *x;
#if PY_MAJOR_VERSION < 3
if (likely(PyInt_CheckExact(b))) if (likely(PyInt_CheckExact(b)))
return PyInt_AS_LONG(b);
#endif
if (likely(PyLong_CheckExact(b))) {
#if CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3
#if CYTHON_USE_PYLONG_INTERNALS
switch (Py_SIZE(b)) {
case -1: return -(sdigit)((PyLongObject*)b)->ob_digit[0];
case 0: return 0;
case 1: return ((PyLongObject*)b)->ob_digit[0];
}
#endif
#endif
#if PY_VERSION_HEX < 0x02060000
return PyInt_AsSsize_t(b); return PyInt_AsSsize_t(b);
#else
return PyLong_AsSsize_t(b);
#endif
}
x = PyNumber_Index(b); x = PyNumber_Index(b);
if (!x) return -1; if (!x) return -1;
ival = PyInt_AsSsize_t(x); ival = PyInt_AsSsize_t(x);
......
...@@ -363,6 +363,9 @@ Cython code. Here is the list of currently supported directives: ...@@ -363,6 +363,9 @@ Cython code. Here is the list of currently supported directives:
internally without paying attention to cache consistency, this option can internally without paying attention to cache consistency, this option can
be set to False. be set to False.
``unraisable_tracebacks`` (True / False)
Whether to print tracebacks when suppressing unraisable exceptions.
How to set directives How to set directives
--------------------- ---------------------
......
...@@ -26,7 +26,7 @@ main new features of Cython v0.13 regarding C++ support: ...@@ -26,7 +26,7 @@ main new features of Cython v0.13 regarding C++ support:
* C++ objects can now be dynamically allocated with ``new`` and ``del`` keywords. * C++ objects can now be dynamically allocated with ``new`` and ``del`` keywords.
* C++ objects can be stack-allocated. * C++ objects can be stack-allocated.
* C++ classes can be declared with the new keyword ``cppclass``. * C++ classes can be declared with the new keyword ``cppclass``.
* Templated classes are supported. * Templated classes and functions are supported.
* Overloaded functions are supported. * Overloaded functions are supported.
* Overloading of C++ operators (such as operator+, operator[],...) is supported. * Overloading of C++ operators (such as operator+, operator[],...) is supported.
...@@ -388,7 +388,15 @@ Cython uses a bracket syntax for templating. A simple example for wrapping C++ v ...@@ -388,7 +388,15 @@ Cython uses a bracket syntax for templating. A simple example for wrapping C++ v
del v del v
Multiple template parameters can be defined as a list, such as [T, U, V] Multiple template parameters can be defined as a list, such as [T, U, V]
or [int, bool, char]. or [int, bool, char]. Template functions are defined similarly, with
the template parameter list following the function name::
cdef extern from "<algorithm>" namespace "std":
T max[T](T a, T b)
print max[long](3, 4)
print max(1.5, 2.5) # simple template argument deduction
Standard library Standard library
----------------- -----------------
......
...@@ -448,6 +448,9 @@ class TestBuilder(object): ...@@ -448,6 +448,9 @@ class TestBuilder(object):
continue continue
if filename.startswith('.'): if filename.startswith('.'):
continue # certain emacs backup files continue # certain emacs backup files
if context == 'pyregr':
tags = defaultdict(list)
else:
tags = parse_tags(filepath) tags = parse_tags(filepath)
fqmodule = "%s.%s" % (context, module) fqmodule = "%s.%s" % (context, module)
if not [ 1 for match in self.selectors if not [ 1 for match in self.selectors
......
...@@ -21,7 +21,7 @@ cdef class C: ...@@ -21,7 +21,7 @@ cdef class C:
def __set__(self, x): def __set__(self, x):
"And here is another one." "And here is another one."
def __add__(self, other): def __div__(self, other):
"usable docstring" "usable docstring"
def __iter__(self): def __iter__(self):
"usable docstring" "usable docstring"
......
...@@ -26,6 +26,16 @@ See also: ...@@ -26,6 +26,16 @@ See also:
import numpy as np import numpy as np
numpy_version = np.__version__.split('.')[:2]
try:
numpy_version = tuple(map(int, numpy_version))
except ValueError:
numpy_version = (20, 0)
NUMPY_HAS_RELAXED_STRIDES = (
numpy_version < (1, 8) or
np.ones((10, 1), order="C").flags.f_contiguous)
def test_one_sized(array): def test_one_sized(array):
""" """
...@@ -33,7 +43,8 @@ def test_one_sized(array): ...@@ -33,7 +43,8 @@ def test_one_sized(array):
>>> test_one_sized(contig)[0] >>> test_one_sized(contig)[0]
1.0 1.0
>>> a = np.arange(10, dtype=np.double)[::100] >>> a = np.arange(10, dtype=np.double)[::100]
>>> test_one_sized(a)[0] >>> if NUMPY_HAS_RELAXED_STRIDES: print(test_one_sized(a)[0])
... else: print(1.0)
1.0 1.0
""" """
cdef double[::1] a = array cdef double[::1] a = array
...@@ -47,7 +58,7 @@ def test_zero_sized(array): ...@@ -47,7 +58,7 @@ def test_zero_sized(array):
>>> _ = test_zero_sized(contig) >>> _ = test_zero_sized(contig)
>>> a = np.arange(10, dtype=np.double)[100:200:10] >>> a = np.arange(10, dtype=np.double)[100:200:10]
>>> _ = test_zero_sized(a) >>> if NUMPY_HAS_RELAXED_STRIDES: _ = test_zero_sized(a)
""" """
cdef double[::1] a = array cdef double[::1] a = array
return a return a
...@@ -211,6 +211,21 @@ def bytearray_append(bytearray b, char c, int i, object o): ...@@ -211,6 +211,21 @@ def bytearray_append(bytearray b, char c, int i, object o):
>>> print(b.decode('ascii')) >>> print(b.decode('ascii'))
abcXxyz abcXxyz
>>> b = bytearray(b'abc')
>>> b = bytearray_append(b, ord('x'), ord('y'), ord('\\xc3') if IS_PY3 else b'\\xc3')
>>> print(b[:-1].decode('ascii'))
abcXxy
>>> print('%x' % b[-1])
c3
>>> b = bytearray(b'abc')
>>> try:
... b = bytearray_append(b, ord('x'), ord('y'), b'zz')
... except (TypeError, ValueError): pass # (Py3, Py2)
... else: print("FAIL")
>>> print(b.decode('ascii'))
abcXxy
>>> b = bytearray(b'abc') >>> b = bytearray(b'abc')
>>> b = bytearray_append(b, -1, ord('y'), ord('z')) # doctest: +ELLIPSIS >>> b = bytearray_append(b, -1, ord('y'), ord('z')) # doctest: +ELLIPSIS
Traceback (most recent call last): Traceback (most recent call last):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment