[Pyrex] Subclassing a non-GC type

Stefan Behnel stefan_ml at behnel.de
Thu Jan 10 00:08:52 CET 2008


Hi,

I tried subclassing PyUnicodeObject, which currently makes for a sure crasher
in Cython (and Pyrex, I assume). The problem is that PyUnicodeObject doesn't
implement tp_clear() and tp_traverse(), as it doesn't care about cyclic
garbage collection - it doesn't reference any other types itself, so it
doesn't have to.

However, the first thing the tp_traverse/clear() functions generated by Cython
do is call their base class equivalent - without checking if they are actually
implemented.

Here is a patch that catches this and works for me. However, I'm not sure if
this is the right thing to do, as it catches this at the latest possible time.
Does anyone know if this is enough to subclass a non-GC type? As I said, it
works nicely for PyUnicodeObject. I also considered using "PyType_IS_GC()"
instead, but I find it more explicit to test if the function itself is
implemented than the more generic type test (also, the function pointer is
needed right afterwards anyway, so the impact should be near zero).

BTW, shouldn't we in turn drop these two functions (and TPFLAGS_HAVE_GC) for
extension types that do not have Python object members? If this is the only
difference, I don't see why they should be there.

Stefan


# HG changeset patch
# User Stefan Behnel <scoder at users.berlios.de>
# Date 1199917706 -3600
# Node ID e097bfd9b3b2115f0cec3d53c1062287dab6a816
# Parent  59e4b70626f25058e08467fb708dad7b21b8b8d5
fix subclassing non-GC types like 'unicode'

diff -r 59e4b70626f2 -r e097bfd9b3b2 Compiler/ModuleNode.py
--- a/Compiler/ModuleNode.py    Wed Jan 09 23:26:01 2008 +0100
+++ b/Compiler/ModuleNode.py    Wed Jan 09 23:28:26 2008 +0100
@@ -723,9 +723,11 @@ class ModuleNode(Nodes.Node, Nodes.Block
         if py_attrs:
             self.generate_self_cast(scope, code)
         if base_type:
+            code.putln("if (%s->tp_traverse) {" % base_type.typeptr_cname)
             code.putln(
                     "e = %s->tp_traverse(o, v, a); if (e) return e;" %
                         base_type.typeptr_cname)
+            code.putln("}")
         for entry in py_attrs:
             var_code = "p->%s" % entry.cname
             code.putln(
@@ -756,9 +758,11 @@ class ModuleNode(Nodes.Node, Nodes.Block
         if py_attrs:
             self.generate_self_cast(scope, code)
         if base_type:
+            code.putln("if (%s->tp_clear) {" % base_type.typeptr_cname)
             code.putln(
                 "%s->tp_clear(o);" %
                     base_type.typeptr_cname)
+            code.putln("}")
         for entry in py_attrs:
             name = "p->%s" % entry.cname
             code.put_xdecref(name, entry.type)





More information about the Pyrex mailing list