Package: pep3134
This library is intended to give you an ability to use exception chaining and embedded tracebacks with both
Python 2 and Python 3 (>= 3.3 only). Exception Chaining and Embedded Tracebacks are also well known as
PEP3134 that’s why I have such geeky name for that library.No, it is not. Geeky name is kindaPEP3134 (feat. PEP409, PEP415 Remix)but I think it is an overkill.If you want to get more about exception chaining and tracebacks please refer to the documentation forPython 3with modifications done
inPython 3.3.Short excerpt for those who still sit with Python 2 as me.Exceptions have new attributes:__traceback__,__context__,__suppress_context__and__cause__.Exceptions have new syntax for explicit chaining:raiseCustomError("Cannotread settings") fromIOError("Cannotopen /etc/settings").Exceptions always have their own tracebacks attached in__traceback__attribute.If exception was raised without explicit cause, it has its own context
(say, fromsys.exc_info()) in__context__attribute. In this case__cause__keepsNone.If exception was raised by implicit cause, then__suppress_context__isFalse.If exception was raised with explicit cause (raise ... from ...) then__cause__has a cause,__suppress_context__isTrueand__context__is
(suddenly)None.So this is pretty convenient to have chaining if you want to build human-readable error messages
afterwards, right?This library helps you to keep the same__context__,__cause__and__suppress_context__behavior with both Python 2 and Python 3.I did not mentioned__traceback__. This is a reason__traceback__in Python 2Tracebacks are very convenient data structure to work with but really irritating and magical
if you want to deal with it using pure Python, without patching code or hacking interpreter
internals. If you want to see some magic, please checkout, let’s say,Jinja sources. Armin is rather
good but I am trying to escape magic if possible.I cannot keep the same tracebacks to any exceptions even if I want because it requires to do some
work on interpreter internals. But anyway this method will return you something.The rule of thumb is: if it returns an object, it is the proper object you expect. If it returns None
then no luck. Moreover:__traceback__implemented as property so sometimes it raises traceback but afterwards
it returnsNoneon the same object. Unfortunately I do not know a good way how to deal with it.But I can you give some guarantees:__traceback__on implicit (__context__) and explicit causes (__cause__) always correct.__traceback__in the associatedexceptclause is always correct.Sometimes it works in other cases but do not rely on that.This works like this because of _fixed_sys.exc_info()behavior. Let’s check one example.importsysdefexample():try:raiseKeyError("WOW SUCH ERROR")exceptKeyError:first=sys.exc_info()second=sys.exc_info()returnfirst,secondfirst,second=example()assertfirst==secondIt works as a charm in Python2 but raisesAssertionErrorin Python3. So it is not possible to
keep tracebacks in the same way in both Python2 and Python3. Sad story.So if we will rewrite given example with PEP3134importsysimportpep3134defexample():error=-1try:pep3134.raise_(KeyError("WOW SUCH ERROR"))exceptKeyErroraserr:error=errfirst=sys.exc_info()asserterror.__traceback__isfirst[2]second=sys.exc_info()asserterror.__traceback__isnotsecond[2]# works in Python 2 onlyexample()This is the only pitfall. Causes, as I mentioned, work well.PEP3134 libraryThis library gives you 3 functions you can use. Only 3 so no need to have full documentation on
any external source.pep3134.raise_Works with the same signature asraiseclause in both Python 2 and Python 3. Just a reminder:raiseexc_type,[exc_value,[exc_traceback]]Raises exceptions on the same problems.pep3134.reraiseWorks in the same way asraiseclause without any arguments does in Python 2.pep3134.raise_fromWorks absolutely in the same way asraise ... from ...clause does in Python 3.