
This is somewhat off-topic, but I'm hoping maybe someone can give a hint why this only happens on Python 2.2.1.
Ok, here's the story:
I've had a bug report against our pyPgSQL database interface package that retrieving Large Objects doesn't work with Python 2.2.1. The reproducible traceback we get is:
Traceback (most recent call last): File "p.py", line 20, in ? res = cs.fetchone() File "pyPgSQL/PgSQL.py", line 2672, in fetchone return self.__fetchOneRow() File "pyPgSQL/PgSQL.py", line 2281, in __fetchOneRow for _i in range(self.res.nfields): AttributeError: 'str' object has no attribute '__bases__'
This traceback is quite obviously bogus, as self.res.nfields is a Python int and no strings are involved here whatsoever. After some debugging, I found that something very strange happens in a function call that happens in this for loop. Inside the for loop, a function typecast is called, which has this code within:
if isinstance(value, PgBytea) or type(value) is PgLargeObjectType:
This code is causing the problems which result in the bogus traceback later on.
Now in my case, 'value' is of type PgLargeObjectType, which is a custom type from our extension module. PgBytea is a Python class.
Now comes the first very strange observation: Swapping the checks, so that the 'type(value) is PgLargeObjectType' check comes first makes the problem go away. So my conclusion is that there's some problem with isinstance and my custom extension type.
The second strange thing is that this only happens on Python 2.2.1 (Linux, FreeBSD, Windows), but _not_ on Python 2.1.3 or Python 2.3-CVS.
Oh, the problem isn't tied to isinstance(value, PgBytea). Any isinstance check causes it later on.
Of course I'm suspecting that there's some problem with the extension type. Looks like some internal interpreter data gets corrupted. No idea how to debug that, too.
Does anybody have any tips where to look or how to debug this further?
Probably some C code receives an exception and decides to go a different path (rather than propagating the exception), but forgets to call PyErr_Clear(). If you call some other code that raises an exception or calls PyErr_Clear(), the spurious exception is gone; but if you call some other code that *tests* for an exception (usually with PyExc_Occurred() or PyErr_ExceptionMatches()), that code may raise the bogus exception at an unexpected place. So I'd look in your extension for places where it tests for an exception and decides to ignore it but forgets to clear it. It's also possible that this occurs in the Python code (have you tried the 2.2.2 CVS? Use "cvs update -r release22-maint") but if I had to bet, I'd bet on your SQL extension. :-) --Guido van Rossum (home page: http://www.python.org/~guido/)