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