[ python-Bugs-864944 ] doctest chokes on recursive members

SourceForge.net noreply at sourceforge.net
Sun Aug 8 05:29:53 CEST 2004


Bugs item #864944, was opened at 2003-12-23 06:51
Message generated for change (Comment added) made by tim_one
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=864944&group_id=5470

Category: Python Library
Group: Python 2.3
Status: Closed
Resolution: Fixed
Priority: 5
Submitted By: Gintautas Miliauskas (gintautasm)
Assigned to: Tim Peters (tim_one)
Summary: doctest chokes on recursive members

Initial Comment:
doctests recurse infinitely when they find a recursive
member in a class. A simple example:

--b0rk.py--
class Crash:
    pass

Crash.c = Crash
-----

--test.py--
import doctest
import b0rk

doctest.testmod(b0rk)
-----

--output of test.py--
Traceback (most recent call last):
  File "test.py", line 5, in ?
    doctest.testmod(b0rk)
  File "/usr/lib/python2.3/doctest.py", line 1148, in
testmod
    f, t = tester.rundict(m.__dict__, name, m)
  File "/usr/lib/python2.3/doctest.py", line 908, in
rundict
    f2, t2 = self.__runone(value, name + "." + thisname)
  File "/usr/lib/python2.3/doctest.py", line 1069, in
__runone
    return self.rundoc(target, name)
  File "/usr/lib/python2.3/doctest.py", line 828, in rundoc
    f2, t2 = self.run__test__(d, name)
<.............................>
  File "/usr/lib/python2.3/doctest.py", line 935, in
run__test__
    f, t = self.rundoc(v, thisname)
  File "/usr/lib/python2.3/doctest.py", line 790, in rundoc
    for tag, kind, homecls, value in
_classify_class_attrs(object):
  File "/usr/lib/python2.3/inspect.py", line 201, in
classify_class_attrs
    mro = getmro(cls)
RuntimeError: maximum recursion depth exceeded
-----

----------------------------------------------------------------------

>Comment By: Tim Peters (tim_one)
Date: 2004-08-07 23:29

Message:
Logged In: YES 
user_id=31435

BTW, since you mentioned Zope3, Zope3 will use its own 
copy of 2.4's doctest.py until 2.4 becomes the minimum 
version.  So there's no need to backport anything for Zope3's 
benefit.

----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2004-08-07 23:25

Message:
Logged In: YES 
user_id=31435

This is fixed in Python 2.4's doctest.py, which does keep a 
set of already-seen objects.  But, since this was done as 
part of a massive refactoring of doctest.py, I have no plan to 
backport any part of it to the 2.3 line.

----------------------------------------------------------------------

Comment By: Marius Gedminas (mgedmin)
Date: 2003-12-29 05:52

Message:
Logged In: YES 
user_id=44660

The fact that the traceback ends in getmro is just an accident.
There is an infinite recursion between run__test__ and rundoc
when a class attribute references the class itself.

The problem was originally noticed by playing with Zope 3.
Apparently Zope 3 interfaces add a class attribute that
references the class itself (perhaps indirectly) and causes this
problem to appear whenever a class declares that it implements
some interface, e.g.

  from zope.interface import implements

  class SomeClass(object):
      """docstring

      >>> x = SomeClass()
      ...
      """

      implements(ISomeInterface)

Since Zope 3 component architecture requires that virtually
all classes declare what interfaces they implement, it makes
class doctests unusable with Zope 3.

A possible solution is to keep a set of "seen" objects and check
near the beginning of Tester.rundoc whether an object was
already processed.


----------------------------------------------------------------------

Comment By: Gintautas Miliauskas (gintautasm)
Date: 2003-12-29 05:46

Message:
Logged In: YES 
user_id=936754

I guess I snipped a little too much traceback...

Here is a part of traceback (reproduced with python 2.2.)
that illustrates the idea:

<...>
  File "/usr/lib/python2.2/doctest.py", line 905, in run__test__
    f, t = self.rundoc(v, thisname)
  File "/usr/lib/python2.2/doctest.py", line 798, in rundoc
    f2, t2 = self.run__test__(d, name)
  File "/usr/lib/python2.2/doctest.py", line 905, in run__test__
    f, t = self.rundoc(v, thisname)
  File "/usr/lib/python2.2/doctest.py", line 798, in rundoc
    f2, t2 = self.run__test__(d, name)
  File "/usr/lib/python2.2/doctest.py", line 905, in run__test__
    f, t = self.rundoc(v, thisname)
  File "/usr/lib/python2.2/doctest.py", line 798, in rundoc
    f2, t2 = self.run__test__(d, name)
<...>

It's definitely not a fault of getmro(). Besides, I've
tested and the crash occurs on Python 2.1, 2.2 and 2.3.

----------------------------------------------------------------------

Comment By: Terry J. Reedy (tjreedy)
Date: 2003-12-28 17:05

Message:
Logged In: YES 
user_id=593130

Traceback says crash happens in inspect.getmro and not in 
doctest itself.  In 2.2.1, I get

>>> class C: pass
...
>>> C.c=C
>>> import inspect as i
>>> i.getmro(C)
(<class __main__.C at 0x00867510>,)

However, mro resolution was changed for 2.3.  See if above 
changes in 2.3.  Or if calling on class inside imported module 
makes a difference.


----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=864944&group_id=5470


More information about the Python-bugs-list mailing list