before_install:
- |
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
+ if [ "$TRAVIS_OS_NAME" == "linux" ]; then
# adding apt repos in travis is really fragile => retry a couple of times.
for i in {1..10}; do travis_retry sudo apt-add-repository --yes 'ppa:ubuntu-toolchain-r/test' && break; sleep 2; done
for i in {1..10}; do travis_retry sudo apt-get update && travis_retry sudo apt-get install --yes gcc-8 $(if [ -z "${BACKEND##*cpp*}" ]; then echo -n "g++-8"; fi ) && break; sleep 2; done
fi
- |
- if [[ "$TRAVIS_OS_NAME" == "osx" ]] || [[ "$STACKLESS" == "true" ]]; then # Install Miniconda
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then CONDA_PLATFORM=MacOSX; else CONDA_PLATFORM=Linux; fi
- travis_retry curl -s -o miniconda.sh https://repo.continuum.io/miniconda/Miniconda$PY-latest-${CONDA_PLATFORM}-x86_64.sh
- bash miniconda.sh -b -p $HOME/miniconda && rm miniconda.sh
+ if [ "$TRAVIS_OS_NAME" == "osx" -o "$STACKLESS" == "true" ]; then
+ echo "Installing Miniconda"
+ if [ "$TRAVIS_OS_NAME" == "osx" ]; then CONDA_PLATFORM=MacOSX; else CONDA_PLATFORM=Linux; fi
+ travis_retry wget -O miniconda.sh https://repo.continuum.io/miniconda/Miniconda$PY-latest-${CONDA_PLATFORM}-x86_64.sh || exit 1
+ bash miniconda.sh -b -p $HOME/miniconda && rm miniconda.sh || exit 1
+ conda --version || exit 1
#conda install --quiet --yes nomkl --file=test-requirements.txt --file=test-requirements-cpython.txt
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+ if [ "$TRAVIS_OS_NAME" == "osx" ]; then
which clang && clang --version && export CC=clang || true
which clang++ && clang++ --version && export CXX=clang++ || true
fi
- if [ -n "$CC" ]; then which $CC; $CC --version; fi
- if [ -n "$CXX" ]; then which $CXX; $CXX --version; fi
- - if [[ "$STACKLESS" == "true" ]]; then
+ - if [ "$STACKLESS" == "true" ]; then
conda config --add channels stackless;
travis_retry conda install --quiet --yes stackless;
fi
Cython Changelog
================
+0.29.17 (2020-04-26)
+====================
+
+Features added
+--------------
+
+* ``std::move()`` is now available from ``libcpp.utility``.
+ Patch by Omer Ozarslan. (Github issue #2169)
+
+* The ``@cython.binding`` decorator is available in Python code.
+ (Github issue #3505)
+
+Bugs fixed
+----------
+
+* Creating an empty unicode slice with large bounds could crash.
+ Patch by Sam Sneddon. (Github issue #3531)
+
+* Decoding an empty bytes/char* slice with large bounds could crash.
+ Patch by Sam Sneddon. (Github issue #3534)
+
+* Re-importing a Cython extension no longer raises the error
+ "``__reduce_cython__ not found``".
+ (Github issue #3545)
+
+* Unused C-tuples could generate incorrect code in 0.29.16.
+ Patch by Kirk Meyer. (Github issue #3543)
+
+* Creating a fused function attached it to the garbage collector before it
+ was fully initialised, thus risking crashes in rare failure cases.
+ Original patch by achernomorov. (Github issue #3215)
+
+* Temporary buffer indexing variables were not released and could show up in
+ C compiler warnings, e.g. in generators.
+ Patch by David Woods. (Github issues #3430, #3522)
+
+* The compilation cache in ``cython.inline("…")`` failed to take the language
+ level into account.
+ Patch by will-ca. (Github issue #3419)
+
+* The deprecated ``PyUnicode_GET_SIZE()`` function is no longer used in Py3.
+
+
0.29.16 (2020-03-24)
====================
else:
print("Couldn't find %r" % symbol)
+def _inline_key(orig_code, arg_sigs, language_level):
+ key = orig_code, arg_sigs, sys.version_info, sys.executable, language_level, Cython.__version__
+ return hashlib.sha1(_unicode(key).encode('utf-8')).hexdigest()
+
def cython_inline(code, get_type=unsafe_type,
lib_dir=os.path.join(get_cython_cache_dir(), 'inline'),
cython_include_dirs=None, cython_compiler_directives=None,
get_type = lambda x: 'object'
ctx = _create_context(tuple(cython_include_dirs)) if cython_include_dirs else _cython_inline_default_context
+ cython_compiler_directives = dict(cython_compiler_directives or {})
+ if language_level is None and 'language_level' not in cython_compiler_directives:
+ language_level = '3str'
+ if language_level is not None:
+ cython_compiler_directives['language_level'] = language_level
+
# Fast path if this has been called in this session.
_unbound_symbols = _cython_inline_cache.get(code)
if _unbound_symbols is not None:
_populate_unbound(kwds, _unbound_symbols, locals, globals)
args = sorted(kwds.items())
arg_sigs = tuple([(get_type(value, ctx), arg) for arg, value in args])
- invoke = _cython_inline_cache.get((code, arg_sigs))
+ key_hash = _inline_key(code, arg_sigs, language_level)
+ invoke = _cython_inline_cache.get((code, arg_sigs, key_hash))
if invoke is not None:
arg_list = [arg[1] for arg in args]
return invoke(*arg_list)
# Parsing from strings not fully supported (e.g. cimports).
print("Could not parse code as a string (to extract unbound symbols).")
- cython_compiler_directives = dict(cython_compiler_directives or {})
- if language_level is not None:
- cython_compiler_directives['language_level'] = language_level
-
cimports = []
for name, arg in list(kwds.items()):
if arg is cython_module:
del kwds[name]
arg_names = sorted(kwds)
arg_sigs = tuple([(get_type(kwds[arg], ctx), arg) for arg in arg_names])
- key = orig_code, arg_sigs, sys.version_info, sys.executable, language_level, Cython.__version__
- module_name = "_cython_inline_" + hashlib.md5(_unicode(key).encode('utf-8')).hexdigest()
+ key_hash = _inline_key(orig_code, arg_sigs, language_level)
+ module_name = "_cython_inline_" + key_hash
if module_name in sys.modules:
module = sys.modules[module_name]
module = load_dynamic(module_name, module_path)
- _cython_inline_cache[orig_code, arg_sigs] = module.__invoke
+ _cython_inline_cache[orig_code, arg_sigs, key_hash] = module.__invoke
arg_list = [kwds[arg] for arg in arg_names]
return module.__invoke(*arg_list)
6
)
+ def test_lang_version(self):
+ # GH-3419. Caching for inline code didn't always respect compiler directives.
+ inline_divcode = "def f(int a, int b): return a/b"
+ self.assertEqual(
+ inline(inline_divcode, language_level=2)['f'](5,2),
+ 2
+ )
+ self.assertEqual(
+ inline(inline_divcode, language_level=3)['f'](5,2),
+ 2.5
+ )
+
if has_numpy:
def test_numpy(self):
# Whether we're assigning to a buffer (in that case it needs to be writable)
writable_needed = False
+ # Any indexing temp variables that we need to clean up.
+ index_temps = ()
+
def analyse_target_types(self, env):
self.analyse_types(env, getting=False)
warning(self.pos, "Use boundscheck(False) for faster access", level=1)
# Assign indices to temps of at least (s)size_t to allow further index calculations.
- index_temps = [self.get_index_in_temp(code,ivar) for ivar in self.indices]
+ self.index_temps = index_temps = [self.get_index_in_temp(code,ivar) for ivar in self.indices]
# Generate buffer access code using these temps
from . import Buffer
code.putln("%s = (PyObject *) *%s;" % (self.result(), self.buffer_ptr_code))
code.putln("__Pyx_INCREF((PyObject*)%s);" % self.result())
+ def free_temps(self, code):
+ for temp in self.index_temps:
+ code.funcstate.release_temp(temp)
+ self.index_temps = ()
+ super(BufferIndexNode, self).free_temps(code)
+
class MemoryViewIndexNode(BufferIndexNode):
if self.specialized_cpdefs or self.is_specialization:
code.globalstate.use_utility_code(
UtilityCode.load_cached("FusedFunction", "CythonFunction.c"))
- constructor = "__pyx_FusedFunction_NewEx"
+ constructor = "__pyx_FusedFunction_New"
else:
code.globalstate.use_utility_code(
UtilityCode.load_cached("CythonFunction", "CythonFunction.c"))
- constructor = "__Pyx_CyFunction_NewEx"
+ constructor = "__Pyx_CyFunction_New"
if self.code_object:
code_object_result = self.code_object.py_result()
definition = module is env
type_entries = []
for entry in module.type_entries:
- if entry.type.is_ctuple:
+ if entry.type.is_ctuple and entry.used:
if entry.name not in ctuple_names:
ctuple_names.add(entry.name)
type_entries.append(entry)
bint operator>(pair&, pair&)
bint operator<=(pair&, pair&)
bint operator>=(pair&, pair&)
+
+cdef extern from * namespace "cython_std" nogil:
+ """
+ #if __cplusplus > 199711L
+ #include <type_traits>
+
+ namespace cython_std {
+ template <typename T> typename std::remove_reference<T>::type&& move(T& t) noexcept { return std::move(t); }
+ template <typename T> typename std::remove_reference<T>::type&& move(T&& t) noexcept { return std::move(t); }
+ }
+
+ #endif
+ """
+ cdef T move[T](T)
# cython.* namespace for pure mode.
from __future__ import absolute_import
-__version__ = "0.29.16"
+__version__ = "0.29.17"
try:
from __builtin__ import basestring
final = internal = type_version_tag = no_gc_clear = no_gc = _empty_decorator
+binding = lambda _: _empty_decorator
+
_cython_inline = None
def inline(f, *args, **kwds):
+//////////////////// CythonFunctionShared.proto ////////////////////
-//////////////////// CythonFunction.proto ////////////////////
#define __Pyx_CyFunction_USED 1
#define __Pyx_CYFUNCTION_STATICMETHOD 0x01
#define __Pyx_CyFunction_Check(obj) (__Pyx_TypeCheck(obj, __pyx_CyFunctionType))
-#define __Pyx_CyFunction_NewEx(ml, flags, qualname, self, module, globals, code) \
- __Pyx_CyFunction_New(__pyx_CyFunctionType, ml, flags, qualname, self, module, globals, code)
-
-static PyObject *__Pyx_CyFunction_New(PyTypeObject *, PyMethodDef *ml,
+static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml,
int flags, PyObject* qualname,
PyObject *self,
PyObject *module, PyObject *globals,
static int __pyx_CyFunction_init(void);
-//////////////////// CythonFunction ////////////////////
+
+//////////////////// CythonFunctionShared ////////////////////
//@substitute: naming
//@requires: CommonStructures.c::FetchCommonType
////@requires: ObjectHandling.c::PyObjectGetAttrStr
#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func.m_weakreflist)
#endif
-
-static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags, PyObject* qualname,
- PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) {
- __pyx_CyFunctionObject *op = PyObject_GC_New(__pyx_CyFunctionObject, type);
- if (op == NULL)
+static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname,
+ PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) {
+ if (unlikely(op == NULL))
return NULL;
op->flags = flags;
__Pyx_CyFunction_weakreflist(op) = NULL;
op->defaults_kwdict = NULL;
op->defaults_getter = NULL;
op->func_annotations = NULL;
- PyObject_GC_Track(op);
return (PyObject *) op;
}
Py_INCREF(dict);
}
+
+//////////////////// CythonFunction.proto ////////////////////
+
+static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml,
+ int flags, PyObject* qualname,
+ PyObject *closure,
+ PyObject *module, PyObject *globals,
+ PyObject* code);
+
+//////////////////// CythonFunction ////////////////////
+//@requires: CythonFunctionShared
+
+static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname,
+ PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) {
+ PyObject *op = __Pyx_CyFunction_Init(
+ PyObject_GC_New(__pyx_CyFunctionObject, __pyx_CyFunctionType),
+ ml, flags, qualname, closure, module, globals, code
+ );
+ if (likely(op)) {
+ PyObject_GC_Track(op);
+ }
+ return op;
+}
+
+
//////////////////// CyFunctionClassCell.proto ////////////////////
static int __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *classobj);/*proto*/
//////////////////// CyFunctionClassCell ////////////////////
-//@requires: CythonFunction
+//@requires: CythonFunctionShared
static int __Pyx_CyFunction_InitClassCell(PyObject *cyfunctions, PyObject *classobj) {
Py_ssize_t i, count = PyList_GET_SIZE(cyfunctions);
return 0;
}
+
//////////////////// FusedFunction.proto ////////////////////
+
typedef struct {
__pyx_CyFunctionObject func;
PyObject *__signatures__;
PyObject *self;
} __pyx_FusedFunctionObject;
-#define __pyx_FusedFunction_NewEx(ml, flags, qualname, self, module, globals, code) \
- __pyx_FusedFunction_New(__pyx_FusedFunctionType, ml, flags, qualname, self, module, globals, code)
-static PyObject *__pyx_FusedFunction_New(PyTypeObject *type,
- PyMethodDef *ml, int flags,
- PyObject *qualname, PyObject *self,
+static PyObject *__pyx_FusedFunction_New(PyMethodDef *ml, int flags,
+ PyObject *qualname, PyObject *closure,
PyObject *module, PyObject *globals,
PyObject *code);
#define __Pyx_FusedFunction_USED
//////////////////// FusedFunction ////////////////////
-//@requires: CythonFunction
+//@requires: CythonFunctionShared
static PyObject *
-__pyx_FusedFunction_New(PyTypeObject *type, PyMethodDef *ml, int flags,
- PyObject *qualname, PyObject *self,
+__pyx_FusedFunction_New(PyMethodDef *ml, int flags,
+ PyObject *qualname, PyObject *closure,
PyObject *module, PyObject *globals,
PyObject *code)
{
- __pyx_FusedFunctionObject *fusedfunc =
- (__pyx_FusedFunctionObject *) __Pyx_CyFunction_New(type, ml, flags, qualname,
- self, module, globals, code);
- if (!fusedfunc)
- return NULL;
-
- fusedfunc->__signatures__ = NULL;
- fusedfunc->type = NULL;
- fusedfunc->self = NULL;
- return (PyObject *) fusedfunc;
+ PyObject *op = __Pyx_CyFunction_Init(
+ // __pyx_CyFunctionObject is correct below since that's the cast that we want.
+ PyObject_GC_New(__pyx_CyFunctionObject, __pyx_FusedFunctionType),
+ ml, flags, qualname, closure, module, globals, code
+ );
+ if (likely(op)) {
+ __pyx_FusedFunctionObject *fusedfunc = (__pyx_FusedFunctionObject *) op;
+ fusedfunc->__signatures__ = NULL;
+ fusedfunc->type = NULL;
+ fusedfunc->self = NULL;
+ PyObject_GC_Track(op);
+ }
+ return op;
}
static void
if (obj == Py_None)
obj = NULL;
- meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_NewEx(
+ meth = (__pyx_FusedFunctionObject *) __pyx_FusedFunction_New(
((PyCFunctionObject *) func)->m_ml,
((__pyx_CyFunctionObject *) func)->flags,
((__pyx_CyFunctionObject *) func)->func_qualname,
if (PyTuple_Check(idx)) {
PyObject *list = PyList_New(0);
Py_ssize_t n = PyTuple_GET_SIZE(idx);
- PyObject *string = NULL;
PyObject *sep = NULL;
int i;
- if (!list)
+ if (unlikely(!list))
return NULL;
for (i = 0; i < n; i++) {
+ int ret;
+ PyObject *string;
#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
PyObject *item = PyTuple_GET_ITEM(idx, i);
#else
- PyObject *item = PySequence_ITEM(idx, i);
+ PyObject *item = PySequence_ITEM(idx, i); if (unlikely(!item)) goto __pyx_err;
#endif
string = _obj_to_str(item);
#if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS)
Py_DECREF(item);
#endif
- if (!string || PyList_Append(list, string) < 0)
- goto __pyx_err;
-
+ if (unlikely(!string)) goto __pyx_err;
+ ret = PyList_Append(list, string);
Py_DECREF(string);
+ if (unlikely(ret < 0)) goto __pyx_err;
}
sep = PyUnicode_FromString("|");
- if (sep)
+ if (likely(sep))
signature = PyUnicode_Join(sep, list);
__pyx_err:
;
static int __Pyx_setup_reduce(PyObject* type_obj);
/////////////// SetupReduce ///////////////
+//@requires: ObjectHandling.c::PyObjectGetAttrStrNoError
//@requires: ObjectHandling.c::PyObjectGetAttrStr
//@substitute: naming
reduce = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__reduce__")); if (unlikely(!reduce)) goto __PYX_BAD;
if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, PYIDENT("__reduce_cython__"))) {
- reduce_cython = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__reduce_cython__")); if (unlikely(!reduce_cython)) goto __PYX_BAD;
- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce__"), reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+ reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, PYIDENT("__reduce_cython__"));
+ if (likely(reduce_cython)) {
+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce__"), reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__reduce_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+ } else if (reduce == object_reduce || PyErr_Occurred()) {
+ // Ignore if we're done, i.e. if 'reduce' already has the right name and the original is gone.
+ // Otherwise: error.
+ goto __PYX_BAD;
+ }
setstate = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__setstate__"));
if (!setstate) PyErr_Clear();
if (!setstate || __Pyx_setup_reduce_is_named(setstate, PYIDENT("__setstate_cython__"))) {
- setstate_cython = __Pyx_PyObject_GetAttrStr(type_obj, PYIDENT("__setstate_cython__")); if (unlikely(!setstate_cython)) goto __PYX_BAD;
- ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate__"), setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
- ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+ setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, PYIDENT("__setstate_cython__"));
+ if (likely(setstate_cython)) {
+ ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate__"), setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD;
+ ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, PYIDENT("__setstate_cython__")); if (unlikely(ret < 0)) goto __PYX_BAD;
+ } else if (!setstate || PyErr_Occurred()) {
+ // Ignore if we're done, i.e. if 'setstate' already has the right name and the original is gone.
+ // Otherwise: error.
+ goto __PYX_BAD;
+ }
}
PyType_Modified((PyTypeObject*)type_obj);
}
name = first_kw_arg;
#if PY_MAJOR_VERSION < 3
- if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) {
+ if (likely(PyString_Check(key))) {
while (*name) {
if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key))
&& _PyString_Eq(**name, key)) {
while (*name) {
int cmp = (**name == key) ? 0 :
#if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3
- (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 :
+ (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 :
#endif
- // need to convert argument name from bytes to unicode for comparison
+ // In Py2, we may need to convert the argument name from str to unicode for comparison.
PyUnicode_Compare(**name, key);
if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad;
if (cmp == 0) {
while (argname != first_kw_arg) {
int cmp = (**argname == key) ? 0 :
#if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3
- (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 :
+ (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 :
#endif
// need to convert argument name from bytes to unicode for comparison
PyUnicode_Compare(**argname, key);
{
#if PY_MAJOR_VERSION >= 3
if (level == -1) {
- if (strchr(__Pyx_MODULE_NAME, '.')) {
+ // Avoid C compiler warning if strchr() evaluates to false at compile time.
+ if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) {
/* try package relative import first */
module = PyImport_ImportModuleLevelObject(
name, global_dict, empty_dict, list, 1);
#endif
+/////////////// PyObjectGetAttrStrNoError.proto ///////////////
+
+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name);/*proto*/
+
+/////////////// PyObjectGetAttrStrNoError ///////////////
+//@requires: PyObjectGetAttrStr
+//@requires: Exceptions.c::PyThreadStateGet
+//@requires: Exceptions.c::PyErrFetchRestore
+//@requires: Exceptions.c::PyErrExceptionMatches
+
+static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) {
+ __Pyx_PyThreadState_declare
+ __Pyx_PyThreadState_assign
+ if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError)))
+ __Pyx_PyErr_Clear();
+}
+
+static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) {
+ PyObject *result;
+#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1
+ // _PyObject_GenericGetAttrWithDict() in CPython 3.7+ can avoid raising the AttributeError.
+ // See https://bugs.python.org/issue32544
+ PyTypeObject* tp = Py_TYPE(obj);
+ if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) {
+ return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1);
+ }
+#endif
+ result = __Pyx_PyObject_GetAttrStr(obj, attr_name);
+ if (unlikely(!result)) {
+ __Pyx_PyObject_GetAttrStr_ClearAttributeError();
+ }
+ return result;
+}
+
+
/////////////// PyObjectGetAttrStr.proto ///////////////
#if CYTHON_USE_TYPE_SLOTS
if (stop < 0)
stop += length;
}
- length = stop - start;
- if (unlikely(length <= 0))
+ if (unlikely(stop <= start))
return PyUnicode_FromUnicode(NULL, 0);
+ length = stop - start;
cstring += start;
if (decode_func) {
return decode_func(cstring, length, errors);
}
if (stop > length)
stop = length;
- length = stop - start;
- if (unlikely(length <= 0))
+ if (unlikely(stop <= start))
return PyUnicode_FromUnicode(NULL, 0);
+ length = stop - start;
cstring += start;
if (decode_func) {
return decode_func(cstring, length, errors);
stop += length;
else if (stop > length)
stop = length;
- length = stop - start;
- if (length <= 0)
+ if (stop <= start)
return PyUnicode_FromUnicode(NULL, 0);
#if CYTHON_PEP393_ENABLED
return PyUnicode_FromKindAndData(PyUnicode_KIND(text),
PYTHON_VERSION: "2.7"
PYTHON_ARCH: "64"
+ - PYTHON: "C:\\Python38"
+ PYTHON_VERSION: "3.8"
+ PYTHON_ARCH: "32"
+
+ - PYTHON: "C:\\Python38-x64"
+ PYTHON_VERSION: "3.8"
+ PYTHON_ARCH: "64"
+
- PYTHON: "C:\\Python37"
PYTHON_VERSION: "3.7"
PYTHON_ARCH: "32"
Cython module can be used as a bridge to allow Python code to call C code, it
can also be used to allow C code to call Python code.
-.. _embedding Python: http://www.freenet.org.nz/python/embeddingpyrex/
+.. _embedding Python: https://web.archive.org/web/20120225082358/http://www.freenet.org.nz:80/python/embeddingpyrex/
External declarations
=======================
# to be unsafe...
(2,999): (operator.lt, lambda x: x in ['run.special_methods_T561_py3',
'run.test_raisefrom',
+ 'run.reimport_failure', # reimports don't do anything in Py2
]),
(3,): (operator.ge, lambda x: x in ['run.non_future_division',
'compile.extsetslice',
from Cython.Build.Dependencies import update_pythran_extension
update_pythran_extension(extension)
+ # Compile with -DCYTHON_CLINE_IN_TRACEBACK=1 unless we have
+ # the "traceback" tag
+ if 'traceback' not in self.tags['tag']:
+ extension.define_macros.append(("CYTHON_CLINE_IN_TRACEBACK", 1))
+
for matcher, fixer in list(EXT_EXTRAS.items()):
if isinstance(matcher, str):
# lazy init
Python code.
Note that for one-time builds, e.g. for CI/testing, on platforms that are not
- covered by one of the wheel packages provided on PyPI, it is substantially faster
- than a full source build to install an uncompiled (slower) version of Cython with::
+ covered by one of the wheel packages provided on PyPI *and* the pure Python wheel
+ that we provide is not used, it is substantially faster than a full source build
+ to install an uncompiled (slower) version of Cython with::
pip install Cython --install-option="--no-cython-compile"
--- /dev/null
+# ticket: 3543
+# mode: compile
+
+# Views define unused ctuples, including (long,)
+from cython cimport view
+
+# Implicitly generate a ctuple (long,)
+obj = None
+obj or (1,)
yield_from_pep380
memoryview_inplace_division
+run.reimport_failure
+
# gc issue?
memoryview_in_subclasses
external_ref_reassignment
cimport cython
+def assert_typeerror_no_keywords(func, *args, **kwds):
+ # Python 3.9 produces an slightly different error message
+ # to previous versions, so doctest isn't matching the
+ # traceback
+ try:
+ func(*args, **kwds)
+ except TypeError as e:
+ assert e.args[0].endswith(" takes no keyword arguments"), e.args[0]
+ else:
+ assert False, "call did not raise TypeError"
+
def func1(arg):
"""
>>> func1(None)
>>> func1(*[None])
- >>> func1(arg=None)
- Traceback (most recent call last):
- ...
- TypeError: func1() takes no keyword arguments
+ >>> assert_typeerror_no_keywords(func1, arg=None)
"""
pass
"""
>>> func2(None)
>>> func2(*[None])
- >>> func2(arg=None)
- Traceback (most recent call last):
- ...
- TypeError: func2() takes no keyword arguments
+ >>> assert_typeerror_no_keywords(func2, arg=None)
"""
pass
"""
>>> A().meth1(None)
>>> A().meth1(*[None])
- >>> A().meth1(arg=None)
- Traceback (most recent call last):
- ...
- TypeError: meth1() takes no keyword arguments
+ >>> assert_typeerror_no_keywords(A().meth1, arg=None)
>>> A().meth2(None)
>>> A().meth2(*[None])
- >>> A().meth2(arg=None)
- Traceback (most recent call last):
- ...
- TypeError: meth2() takes no keyword arguments
+ >>> assert_typeerror_no_keywords(A().meth2, arg=None)
>>> A().meth3(None)
>>> A().meth3(*[None])
>>> A().meth3(arg=None)
cimport cython
+cdef extern from *:
+ cdef Py_ssize_t PY_SSIZE_T_MIN
+ cdef Py_ssize_t PY_SSIZE_T_MAX
+
+SSIZE_T_MAX = PY_SSIZE_T_MAX
+SSIZE_T_MIN = PY_SSIZE_T_MIN
+
+
b_a = b'a'
b_b = b'b'
<BLANKLINE>
>>> print(bytes_decode(s, -300, -500))
<BLANKLINE>
+ >>> print(bytes_decode(s, SSIZE_T_MIN, SSIZE_T_MIN))
+ <BLANKLINE>
+ >>> print(bytes_decode(s, SSIZE_T_MIN, SSIZE_T_MAX))
+ abaab
+ >>> print(bytes_decode(s, SSIZE_T_MAX, SSIZE_T_MIN))
+ <BLANKLINE>
+ >>> print(bytes_decode(s, SSIZE_T_MAX, SSIZE_T_MAX))
+ <BLANKLINE>
>>> s[:'test'] # doctest: +ELLIPSIS
Traceback (most recent call last):
cimport cython
+cdef extern from *:
+ cdef Py_ssize_t PY_SSIZE_T_MIN
+ cdef Py_ssize_t PY_SSIZE_T_MAX
+
+
############################################################
# tests for char* slicing
(cstring+1)[:].decode('UTF-8'),
(cstring+1)[return1():return5()].decode('UTF-8'))
+@cython.test_assert_path_exists("//PythonCapiCallNode")
+@cython.test_fail_if_path_exists("//AttributeNode")
+def slice_charptr_decode_large_bounds():
+ """
+ >>> print(str(slice_charptr_decode_large_bounds()).replace("u'", "'"))
+ ('abcABCqtp', '', '', '')
+ """
+ return (cstring[PY_SSIZE_T_MIN:9].decode('UTF-8'),
+ cstring[PY_SSIZE_T_MAX:PY_SSIZE_T_MIN].decode('UTF-8'),
+ cstring[PY_SSIZE_T_MIN:PY_SSIZE_T_MIN].decode('UTF-8'),
+ cstring[PY_SSIZE_T_MAX:PY_SSIZE_T_MAX].decode('UTF-8'))
+
+
cdef return1(): return 1
cdef return3(): return 3
cdef return4(): return 4
--- /dev/null
+# mode: run
+# tag: cpp, werror, cpp11
+
+from libcpp cimport nullptr
+from libcpp.memory cimport shared_ptr, make_shared
+from libcpp.utility cimport move
+from cython.operator cimport dereference
+
+cdef extern from *:
+ """
+ #include <string>
+
+ template<typename T> const char* move_helper(T&) { return "lvalue-ref"; }
+ template<typename T> const char* move_helper(T&&) { return "rvalue-ref"; }
+ """
+ const char* move_helper[T](T)
+
+def test_move_assignment():
+ """
+ >>> test_move_assignment()
+ """
+ cdef shared_ptr[int] p1, p2
+ p1 = make_shared[int](1337)
+ p2 = move(p1)
+ assert p1 == nullptr
+ assert dereference(p2) == 1337
+
+def test_move_func_call():
+ """
+ >>> test_move_func_call()
+ """
+ cdef shared_ptr[int] p
+ assert move_helper(p) == b'lvalue-ref'
+ assert move_helper(move(p)) == b'rvalue-ref'
--- /dev/null
+# mode: run
+# tag: pep489
+
+"""
+PYTHON setup.py build_ext -i
+PYTHON tester.py
+"""
+
+######## setup.py ########
+
+from Cython.Build.Dependencies import cythonize
+from distutils.core import setup
+
+setup(
+ ext_modules = cythonize("*.pyx"),
+)
+
+
+######## failure.pyx ########
+
+if globals(): # runtime True to confuse dead code removal
+ raise ImportError
+
+cdef class C:
+ cdef int a
+
+
+######## tester.py ########
+
+try:
+ try:
+ import failure # 1
+ except ImportError:
+ import failure # 2
+except ImportError:
+ pass
+else:
+ raise RuntimeError("ImportError was not raised on second import!")
-import traceback
+# tag: traceback
def foo1():
foo2()
try:
foo1()
except:
+ import traceback
tb_string = traceback.format_exc()
expected = (
'tracebacks.pyx',
>>> slice_none_none(None, 2, 4)
Traceback (most recent call last):
TypeError: 'NoneType' object is not subscriptable
+
+ >>> slice_start_end(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+ <BLANKLINE>
+ >>> slice_start(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+ <BLANKLINE>
+ >>> slice_end(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+ abcdef
+ >>> slice_all(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+ abcdef
+ >>> slice_start_none(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+ <BLANKLINE>
+ >>> slice_none_end(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+ abcdef
+ >>> slice_none_none(u'abcdef', SSIZE_T_MAX, SSIZE_T_MIN)
+ abcdef
"""
+cdef extern from *:
+ cdef Py_ssize_t PY_SSIZE_T_MIN
+ cdef Py_ssize_t PY_SSIZE_T_MAX
+
+SSIZE_T_MAX = PY_SSIZE_T_MAX
+SSIZE_T_MIN = PY_SSIZE_T_MIN
+
import sys
if sys.version_info[0] >= 3:
__doc__ = __doc__.replace(u"(u'", u"('").replace(u" u'", u" '")
-def slice_start_end(unicode s, int i, int j):
+def slice_start_end(unicode s, Py_ssize_t i, Py_ssize_t j):
print(s[i:j])
-def slice_start(unicode s, int i, int j):
+def slice_start(unicode s, Py_ssize_t i, Py_ssize_t j):
print(s[i:])
-def slice_end(unicode s, int i, int j):
+def slice_end(unicode s, Py_ssize_t i, Py_ssize_t j):
print(s[:i])
-def slice_all(unicode s, int i, int j):
+def slice_all(unicode s, Py_ssize_t i, Py_ssize_t j):
print(s[:])
-def slice_start_none(unicode s, int i, int j):
+def slice_start_none(unicode s, Py_ssize_t i, Py_ssize_t j):
print(s[i:None])
-def slice_none_end(unicode s, int i, int j):
+def slice_none_end(unicode s, Py_ssize_t i, Py_ssize_t j):
print(s[None:i])
-def slice_none_none(unicode s, int i, int j):
+def slice_none_none(unicode s, Py_ssize_t i, Py_ssize_t j):
print(s[None:None])