classification
Title: maximum recursion depth exceeded in __subclasscheck__
Type: behavior Stage:
Components: Interpreter Core Versions: Python 2.6
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: amaury.forgeotdarc, gangesmaster, georg.brandl, loewis, pitrou
Priority: normal Keywords:

Created on 2009-03-18 15:25 by gangesmaster, last changed 2009-04-05 14:38 by georg.brandl. This issue is now closed.

Messages (3)
msg83752 - (view) Author: ganges master (gangesmaster) Date: 2009-03-18 15:25
this is similar to bug #5370, but this for is a different reason. also,
i have seen several sites on google that mention it, so it has happened
to quite a few people.

the bug is that when calling dir() on a object, it looks for __members__
and __methods__, which might not exist, thus invoking __getattr__ (if it
exists).

if __getattr__ fails, say, due to a never ending recusion, the exception
is silently swallowed. this was the behavior in py2.5. since 2.6, it
emits a warning (that looks like PyErr_WriteUnraisable) with the
strangest message:

Exception RuntimeError: 'maximum recursion depth exceeded in
__subclasscheck__' in <type 'exceptions.AttributeError'> ignored

this is very confusing. either dir() raises this exception, or silently
ignore it, but displaying this message is only confusing.

i haven't been able to detect why this happens:
 * the source of this exception, merge_list_attr, calls PyErr_Clear
 * nobody seems to call PyErr_WriteUnraisable

here's a snippet:

class Foo(object):
    def __getattr__(self, name):
        return self.x  # which will recursively call __getattr__

>>> f = Foo()
>>> print dir(f)
Exception RuntimeError: 'maximum recursion depth exceeded in
__subclasscheck__' in <type 'exceptions.AttributeError'> ignored
Exception RuntimeError: 'maximum recursion depth exceeded in
__subclasscheck__' in <type 'exceptions.AttributeError'> ignored
['__class__', '__delattr__', '__dict__', '__doc__', '__format__',
'__getattr__', '__getattribute__', '__hash__', '__init__', '__module__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__']
msg83764 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-03-18 17:27
Here is the reason. Starting from Python 2.6, classes can redefine
subclass checking using a special method named __subclasscheck__. Since
this method can contain arbitrary code, we have to guard against
recursion when calling it. Therefore, the recursion count is incremented
before doing a subclass checking.

Now the problem is that when checking for an exception, we do exactly
that: check whether the raised exception is a subclass of a given type.
If the raised exception occurred just after a recursion overflow, it can
happen that subclass checking overflows the recursion count again.
However, since we don't want the newly raised exception (during
exception subclass checking) to overwrite the original one, so we just
write out it (using PyErr_WriteUnraisable, precisely) and then discard it.

That's where these strange messages come from.
(note: py3k has a slightly different recursion checking mechanism and
doesn't print such messages)
msg85502 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2009-04-05 14:38
The messages are now suppressed by the temporary bump of the recursion
limit in PyErr_GivenExceptionMatches.
History
Date User Action Args
2009-04-05 14:38:22georg.brandlsetstatus: open -> closed
resolution: out of date
messages: + msg85502
2009-03-18 17:27:52pitrousetnosy: + amaury.forgeotdarc, loewis, pitrou
messages: + msg83764
2009-03-18 15:25:48gangesmastercreate