Cython Changelog
================
+0.28.4 (2018-07-08)
+===================
+
+Bugs fixed
+----------
+
+* Reallowing ``tp_clear()`` in a subtype of an ``@no_gc_clear`` extension type
+ generated an invalid C function call to the (non-existent) base type implementation.
+ (Github issue #2309)
+
+* Exception catching based on a non-literal (runtime) tuple could fail to match the
+ exception. (Github issue #2425)
+
+* Compile fix for CPython 3.7.0a2. (Github issue #2477)
+
+
0.28.3 (2018-05-27)
===================
code.putln("}")
def generate_clear_function(self, scope, code, cclass_entry):
- tp_slot = TypeSlots.GCDependentSlot("tp_clear")
+ tp_slot = TypeSlots.get_slot_by_name("tp_clear")
slot_func = scope.mangle_internal("tp_clear")
base_type = scope.parent_type.base_type
if tp_slot.slot_code(scope) != slot_func:
# cython.* namespace for pure mode.
from __future__ import absolute_import
-__version__ = "0.28.3"
+__version__ = "0.28.4"
try:
from __builtin__ import basestring
}
#if CYTHON_FAST_THREAD_STATE
__Pyx_PyThreadState_assign
- #if PY_VERSION_HEX >= 0x030700A2
+ #if PY_VERSION_HEX >= 0x030700A3
if (!$local_tstate_cname->exc_state.exc_type)
#else
if (!$local_tstate_cname->exc_type)
*value = local_value;
*tb = local_tb;
#if CYTHON_FAST_THREAD_STATE
- #if PY_VERSION_HEX >= 0x030700A2
+ #if PY_VERSION_HEX >= 0x030700A3
tmp_type = tstate->exc_state.exc_type;
tmp_value = tstate->exc_state.exc_value;
tmp_tb = tstate->exc_state.exc_traceback;
PyObject *type = NULL, *value = NULL, *tb = NULL;
#if CYTHON_FAST_THREAD_STATE
PyThreadState *tstate = PyThreadState_GET();
- #if PY_VERSION_HEX >= 0x030700A2
+ #if PY_VERSION_HEX >= 0x030700A3
type = tstate->exc_state.exc_type;
value = tstate->exc_state.exc_value;
tb = tstate->exc_state.exc_traceback;
#if CYTHON_FAST_THREAD_STATE
static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
- #if PY_VERSION_HEX >= 0x030700A2
+ #if PY_VERSION_HEX >= 0x030700A3
*type = tstate->exc_state.exc_type;
*value = tstate->exc_state.exc_value;
*tb = tstate->exc_state.exc_traceback;
static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
- #if PY_VERSION_HEX >= 0x030700A2
+ #if PY_VERSION_HEX >= 0x030700A3
tmp_type = tstate->exc_state.exc_type;
tmp_value = tstate->exc_state.exc_value;
tmp_tb = tstate->exc_state.exc_traceback;
static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
- #if PY_VERSION_HEX >= 0x030700A2
+ #if PY_VERSION_HEX >= 0x030700A3
tmp_type = tstate->exc_state.exc_type;
tmp_value = tstate->exc_state.exc_value;
tmp_tb = tstate->exc_state.exc_traceback;
// so far, we only call PyErr_GivenExceptionMatches() with an exception type (not instance) as first argument
// => optimise for that case
+static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) {
+ Py_ssize_t i, n;
+ assert(PyExceptionClass_Check(exc_type));
+ n = PyTuple_GET_SIZE(tuple);
+#if PY_MAJOR_VERSION >= 3
+ // the tighter subtype checking in Py3 allows faster out-of-order comparison
+ for (i=0; i<n; i++) {
+ if (exc_type == PyTuple_GET_ITEM(tuple, i)) return 1;
+ }
+#endif
+ for (i=0; i<n; i++) {
+ PyObject *t = PyTuple_GET_ITEM(tuple, i);
+ #if PY_MAJOR_VERSION < 3
+ if (likely(exc_type == t)) return 1;
+ #endif
+ if (likely(PyExceptionClass_Check(t))) {
+ if (__Pyx_inner_PyErr_GivenExceptionMatches2(exc_type, NULL, t)) return 1;
+ } else {
+ // FIXME: Py3: PyErr_SetString(PyExc_TypeError, "catching classes that do not inherit from BaseException is not allowed");
+ }
+ }
+ return 0;
+}
+
static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject* exc_type) {
if (likely(err == exc_type)) return 1;
if (likely(PyExceptionClass_Check(err))) {
- return __Pyx_inner_PyErr_GivenExceptionMatches2(err, NULL, exc_type);
+ if (likely(PyExceptionClass_Check(exc_type))) {
+ return __Pyx_inner_PyErr_GivenExceptionMatches2(err, NULL, exc_type);
+ } else if (likely(PyTuple_Check(exc_type))) {
+ return __Pyx_PyErr_GivenExceptionMatchesTuple(err, exc_type);
+ } else {
+ // FIXME: Py3: PyErr_SetString(PyExc_TypeError, "catching classes that do not inherit from BaseException is not allowed");
+ }
}
return PyErr_GivenExceptionMatches(err, exc_type);
}
static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *exc_type1, PyObject *exc_type2) {
+ // Only used internally with known exception types => pure safety check assertions.
+ assert(PyExceptionClass_Check(exc_type1));
+ assert(PyExceptionClass_Check(exc_type2));
if (likely(err == exc_type1 || err == exc_type2)) return 1;
if (likely(PyExceptionClass_Check(err))) {
return __Pyx_inner_PyErr_GivenExceptionMatches2(err, exc_type1, exc_type2);
PYTHON_VERSION: "2.7"
PYTHON_ARCH: "64"
- - PYTHON: "C:\\Python34"
- PYTHON_VERSION: "3.4"
+ - PYTHON: "C:\\Python36"
+ PYTHON_VERSION: "3.6"
PYTHON_ARCH: "32"
- - PYTHON: "C:\\Python34-x64"
- PYTHON_VERSION: "3.4"
+ - PYTHON: "C:\\Python36-x64"
+ PYTHON_VERSION: "3.6"
PYTHON_ARCH: "64"
- PYTHON: "C:\\Python35"
PYTHON_VERSION: "3.5"
PYTHON_ARCH: "64"
- - PYTHON: "C:\\Python36"
- PYTHON_VERSION: "3.6"
+ - PYTHON: "C:\\Python34"
+ PYTHON_VERSION: "3.4"
PYTHON_ARCH: "32"
- - PYTHON: "C:\\Python36-x64"
- PYTHON_VERSION: "3.6"
+ - PYTHON: "C:\\Python34-x64"
+ PYTHON_VERSION: "3.4"
PYTHON_ARCH: "64"
clone_depth: 5
pto.tp_clear(self)
+cdef class ReallowTpClear(DisableTpClear):
+ """
+ >>> import gc
+ >>> obj = ReallowTpClear()
+ >>> is_tp_clear_null(obj)
+ False
+
+ >>> obj.attr = obj # create hard reference cycle
+ >>> del obj; _ignore = gc.collect()
+
+ # Problem: cannot really validate that the cycle was cleaned up without using weakrefs etc...
+ """
+ cdef public object attr
+
+
def test_closure_without_clear(str x):
"""
>>> c = test_closure_without_clear('abc')
i = 3
return i
+
+exceptions = (ValueError, TypeError)
+
+
+def single_except_global_tuple(x):
+ """
+ >>> single_except_global_tuple(None)
+ 2
+ >>> single_except_global_tuple(ValueError('test'))
+ 3
+ >>> single_except_global_tuple(TypeError('test'))
+ 3
+ >>> class TypeErrorSubtype(TypeError): pass
+ >>> single_except_global_tuple(TypeErrorSubtype('test'))
+ 3
+ >>> single_except_global_tuple(AttributeError('test'))
+ Traceback (most recent call last):
+ AttributeError: test
+ """
+ cdef int i
+ try:
+ i = 1
+ if x:
+ raise x
+ i = 2
+ except exceptions:
+ i = 3
+ return i
+
+
def double_except_no_raise(a,b):
"""
>>> double_except_no_raise(TypeError, ValueError)
2
>>> normal_and_bare_except_raise(ValueError('test'), TypeError)
3
+ >>> normal_and_bare_except_raise(TypeError('test'), (TypeError, ValueError))
+ 2
+ >>> normal_and_bare_except_raise(ValueError('test'), (TypeError, ValueError))
+ 2
>>> normal_and_bare_except_raise(None, TypeError)
1
"""