[Python-3000] self-contained exceptions

tomer filiba tomerfiliba at gmail.com
Mon Jan 1 23:38:30 CET 2007


a while back some people suggested having the traceback
as an attribute of the exception object, which allows for
nested exceptions.

i would also like to note that having the traceback part of
the exception object allows the exception to print itself,
i.e., its repr would format the traceback text on it's own.

this makes sys.excepthook unnecessary, as well as
traceback.format_exception (which i greatly dislike).

even if the exception's repr would raise an exception
(recursion limit, etc.), that exception would be a builtin
one, so we won't end up in a repr-exception-loop.

with this approach, sys.excepthook is needless, or at least
simplified greatly (just print repr(exc)). for example, exceptions
raised by RPyC have a special attribute to them -- remote_traceback,
which is the text of the remote traceback. currently i have to
replace excepthook to have it displayed with the local exception
traceback, which is means just importing RPyC messes with
your interpreter's internals, and may cause problems when
another library installs its own hook.

apart from self-repr'ing, nested exceptions are very useful too:

try:
    foo()
except Exception, ex:
    raise MyException("something happened", nested = ex)

so that when i pdb.pm() my code, i can inspect the inner
exception too (which is desirable of course).

the major argument against having the traceback part of
the exception object was increasing memory consumption,
so that exceptions are no longer "light weight" (as used by
StopIteration, etc.)

i don't see why this argument stands. the traceback object
exists either way, the only question is in what namespace
it exists, and the fact it may "live longer" than necessary,
i.e., the traceback exists for as long as the exception object
exists.

i don't think it's really that bad. first, for StopIteration, the exception
object is decref()ed immediately after being raised. moreover,
since no one is expected to see that traceback, it can be set
directly to None, i.e., a PyErr_SetStopIter() function which sets
exc.traceback to None internally.

other than that, you *want* to keep the traceback alive. therefore,
i suggest adding two new attributes to the exception class:
* traceback - the traceback object, or None
* nested - nested ("inner") exception, or None

Exception.__repr__ will be extended to formatting the
traceback (if not None) and formatting all the nested
exceptions (+ detect recursion).

this may be an expensive operation, but as it only happens
when the exceptions is printed to stderr, it's negligible.


-tomer


More information about the Python-3000 mailing list