[Zope-dev] Is "if sys.exc_info()[2].tb_next is not None: raise"
Evil? Concerns Products.GenericSetup, zope.configuration and others
Ross Patterson
me at rpatterson.net
Fri Aug 3 17:12:24 EDT 2007
While trying to use zope.app.modul.ZopePersistentModuleImporter, I ran
across an interaction with code that uses the following hack to try and
discern where an exception was raised.
>>> if sys.exc_info()[2].tb_next is not None:
>>> raise
The problem is occurs when an application provides an __import__
function written in python. In that case then there is a tb_next for
all ImportError exceptions and this hack no longer indicates when the
error was deeper. The same problem would occur if the hack were used
while catching AttributeError and there was a python implementation for
attribute access involved.
This hack counts on the fact that C code which raises an error doesn't
get included in the stack. It counts on this fact, however, at points
where Python specifically allows application specific implementations
written in Python. See the first paragraph of the __import__
documentation.
http://docs.python.org/lib/built-in-funcs.html#l2h-6
Here's a grep of the Zope 2.10 branch. These first two are catching
TypeError:
./Zope/lib/python/zope/component/_api.py:73: if sys.exc_info()[2].tb_next is not None:
./Zope/lib/python/zope/interface/interface.py:644: if sys.exc_info()[2].tb_next is not None:
And these are catching ImportError:
./Zope/lib/python/zope/configuration/config.py:186: if sys.exc_info()[2].tb_next is not None:
./Zope/lib/python/zope/configuration/config.py:208: if sys.exc_info()[2].tb_next is not None:
For zope.configuration.config.ConfigurationContext.resolve, this hack
makes the difference between an ImportError being raised or a
ConfigurationError. This inturn interacts with
zope.app.component.back35.LayerField.fromUnicode which only catches
ConfigurationError and doesn't catch ImportError.
And here's the GenericSetup 1.3 branch, it is also catching ImportError:
./Products/GenericSetup/utils.py:89: if sys.exc_info()[2].tb_next is not None: raise
Products.GenericSetup.utils._resolveDottedName is particularly
troublesome since the except ImportError is inside a while loop so when
__import__ is a python function and it raises ImportError,
_resolveDottedName ends up not continuing with the while loop as it
should.
It seems like the root of the problem is that Python doesn't provide a
way to distinguish between an error and a deeper error of the same type.
This hack is trying to make that distinction but it interferes with
places that Python specifically allows application specific
implementations written in Python. Does that mean that code using this
hack is broken?
Also, zope.dottedname.resolve.resolve, zope.app.introspector.resolve,
zope.app.component.site.resolve, zope.app.module.resolve,
zope.configuration.name.resolve,
zope.configuration.config.ConfigurationContext.resolve,
Products.GenericSetup.utils._resolveDottedName. How many versions of
this wheel do we need? :)
Thoughts? Corrections? Suggested solutions.
Ross
More information about the Zope-Dev
mailing list