xoutil.eight.exceptions
- Exceptions handling compatibility¶
Solve compatibility issues for exceptions handling.
This module tries to solve, as much as possible, differences between how the
raise`, and try ... except
statements are executed between Python
versions 2 and 3. See Exception Chaining and Embedded Tracebacks.
First issue is that before Python 3, module exceptions was defined, but not
anymore. We decided not to implement this concept in xoutil.future
package because all these exception classes are built-ins in both Python major
versions, so use any of them directly. But StandardError
is
undefined in Python 3, we introduce it here.
Raising an exception it’s the biggest difference between both major versions,
starting with that there is no way to achieve syntax compatibility. In
Python 2 the syntax for raise
is:
"raise" [type ["," value ["," traceback]]]
and in Python 3:
"raise" [error[.with_traceback(traceback)] ["from" cause]]
There are two partial solutions in this module:
Using the function
throw()
function instead theraise
statement:throw([error[, traceback=traceback[, cause=cause]]])
This is suitable only when you need the trace-back information is fully tracked when you raise the exception (see below).
Using the function
grab()
the context attributes are assigned, but the trace-back information is not tracked in the system call context.raise grab(error[, traceback=traceback[, cause=cause]])
Python 3 is consistent by always assigning context information in the following scenarios:
- If an exception is raised inside an exception handler or a finally clause:
the previous exception is then attached as the new exception’s
__context__
attribute. This is guaranteed in Python 2 using either thegrab()
function or thethrow()
function. - Clause
from
is used for exception chaining, the expression must be another exception instance or class, which will be attached to the newly raised exception in the__cause__
attribute. This information is printed when the raised exception is not handled, but in Python 2 this information can be custom managed by using eithergrab()
orthrow()
function. - Trace-back information is automatically attached to the attribute
__traceback__
when an exception is raised. You can set your own trace-back using thewith_traceback
method (or in the compatibility functionthrow()
usingtraceback
argument). This can be partially guaranteed in Python 2 by using thecatch()
function in some exception handler or finally clause.
-
xoutil.eight.exceptions.
catch
(base=Unset)[source]¶ Fix
sys.exc_info
context in Python 2.Parameters: base – A subclass of BaseException
or Unset.Next example of Python 3 doesn’t work in Python 2:
>>> def test(): ... try: ... try: ... 1/0 ... except Exception as error: ... raise RuntimeError('xxx') from error ... except Exception as error: ... return error >>> error = test() >>> error.__context__ is error.__cause__ True >>> isinstance(error.__cause__, ZeroDivisionError) True
In this case, we can solve most issues by two replacements (
throw
andcatch
):>>> def test(): ... try: ... try: ... 1/0 ... except catch(Exception) as error: ... throw(RuntimeError('xxx'), cause=error) ... except catch(Exception) as error: ... return error
If base is unset, the catched system error value is returned, so never use this function as:
>>> try: ... 1/0 ... except catch(): ... pass
-
xoutil.eight.exceptions.
catch_traceback
(error, traceback)[source]¶ Catch a trace-back information in a corresponding error.
-
xoutil.eight.exceptions.
grab
(error, traceback=Unset, cause=Unset)[source]¶ Prepare an error with traceback, and context to raise it.
-
xoutil.eight.exceptions.
throw
(error=Unset, traceback=Unset, cause=Unset)[source]¶ Unify syntax for raising an error with trace-back information.
Instead of using the Python
raise
statement, usethrow
:"raise" [error[.with_traceback(traceback)] ["from" cause]]
becomes:
throw([error, [traceback=traceback, ][cause=cause]])
If traceback argument is not given, it is looked up in the error.
-
xoutil.eight.exceptions.
traceof
(error)[source]¶ Get the trace-back information of the given error.
Python 3 is consistent by always assigning the trace-back information in the attribute
__traceback__
, but in Python 2 it’s a “little tricky” to obtain a good solution, and not always, only in some contexts.Returns None if it could not be found.