[Python-Dev] Bizarre new test failure

Tim Peters tim_one@email.msn.com
Fri, 7 Jun 2002 03:49:27 -0400


[Neil Schemenauer]
> It's easy to reproduce.  First, disable the GC.  Next, run:
>
>     regrtest.py test_descr test_gc

Sorry, thinking is cheating.

> My wild guess is that some tp_clear method is not doing it's job.  I'll
> take a closer look tomorrow if someone hasn't figured it out by then.
> Must sleep.  Too much CS.

Ya, Canadian sausage always does me in too.  I'll attach a self-contained
(in the sense that you can run it directly by itself, without regrtest.py)
test program.  Guido might have some idea what does <wink>.  For me, it
prints:

    collected 3
    collected 51
    collected 9
    collected 0

    and, at the end, collected 1

and it's not a coincidence that 9+1 == 10 (the failing value seen when
running the test suite).  It suggests one easy way to fix test_gc <wink>.

> I wonder if some new cyclic garbage structure needs two gc.collect()
> passes in order to break it up.

If there isn't a bug, this case takes 3(!) passes.


from test_support import vereq

def supers():
    class A(object):
        def meth(self, a):
            return "A(%r)" % a

    class B(A):
        def __init__(self):
            self.__super = super(B, self)
        def meth(self, a):
            return "B(%r)" % a + self.__super.meth(a)

    class C(A):
        def meth(self, a):
            return "C(%r)" % a + self.__super.meth(a)
    C._C__super = super(C)

    class D(C, B):
        def meth(self, a):
            return "D(%r)" % a + super(D, self).meth(a)

    class mysuper(super):
        def __init__(self, *args):
            return super(mysuper, self).__init__(*args)

    class E(D):
        def meth(self, a):
            return "E(%r)" % a + mysuper(E, self).meth(a)

    class F(E):
        def meth(self, a):
            s = self.__super
            return "F(%r)[%s]" % (a, s.__class__.__name__) + s.meth(a)
    F._F__super = mysuper(F)

    vereq(F().meth(6), "F(6)[mysuper]E(6)D(6)C(6)B(6)A(6)")

import gc
gc.disable()

L = []
L.append(L)

supers()

while 1:
    n = gc.collect()
    print "collected", n
    if n == 0:
        break

del L
n = gc.collect()
print
print "and, at the end, collected", n