if py_attrs or py_buffers:
self.generate_self_cast(scope, code)
- code.putln("PyObject* tmp;")
if base_type:
# want to call it explicitly if possible so inlining can be performed
UtilityCode.load_cached("CallNextTpClear", "ExtensionTypes.c"))
for entry in py_attrs:
- name = "p->%s" % entry.cname
- code.putln("tmp = ((PyObject*)%s);" % name)
- if entry.is_declared_generic:
- code.put_init_to_py_none(name, py_object_type, nanny=False)
- else:
- code.put_init_to_py_none(name, entry.type, nanny=False)
- code.putln("Py_XDECREF(tmp);")
+ code.putln("Py_CLEAR(p->%s);" % entry.cname)
for entry in py_buffers:
# Note: shouldn't this call __Pyx_ReleaseBuffer ??
--- /dev/null
+"""
+Check that Cython generates a tp_clear function that actually clears object
+references to NULL instead of None.
+
+Discussed here: http://article.gmane.org/gmane.comp.python.cython.devel/14833
+"""
+
+from cpython.ref cimport PyObject, Py_TYPE
+
+cdef class ExtensionType:
+ """
+ Just a type which is handled by a specific C type (instead of PyObject)
+ to check that tp_clear works when the C pointer is of a type different
+ from PyObject *.
+ """
+
+
+# Pull tp_clear for PyTypeObject as I did not find another way to access it
+# from Cython code.
+
+cdef extern from "Python.h":
+ ctypedef struct PyTypeObject:
+ void (*tp_clear)(object)
+
+
+cdef class TpClearFixture:
+ """
+ An extension type that has a tp_clear method generated to test that it
+ actually clears the references to NULL.
+
+ >>> fixture = TpClearFixture()
+ >>> isinstance(fixture.extension_type, ExtensionType)
+ True
+ >>> isinstance(fixture.any_object, str)
+ True
+ >>> fixture.call_tp_clear()
+ >>> fixture.check_any_object_status()
+ 'NULL'
+ >>> fixture.check_extension_type_status()
+ 'NULL'
+ """
+
+ cdef public object any_object
+ cdef public ExtensionType extension_type
+
+ def __cinit__(self):
+ self.any_object = "Hello World"
+ self.extension_type = ExtensionType()
+
+ cpdef public call_tp_clear(self):
+ cdef PyTypeObject *pto = Py_TYPE(self)
+ pto.tp_clear(self)
+
+ cpdef public str check_any_object_status(self):
+ if <void*>(self.any_object) == NULL:
+ return 'NULL'
+ elif self.any_object is None:
+ return 'None'
+ else:
+ return 'not cleared'
+
+ cpdef public str check_extension_type_status(self):
+ if <void*>(self.any_object) == NULL:
+ return 'NULL'
+ elif self.any_object is None:
+ return 'None'
+ else:
+ return 'not cleared'