Add "raise ... from" statement.
Add reference to Perl 6 exception RFC.
This commit is contained in:
parent
22bae2bbd0
commit
3d514b0e42
115
pep-0344.txt
115
pep-0344.txt
|
@ -15,7 +15,8 @@ Abstract
|
|||
This PEP proposes three standard attributes on exception instances:
|
||||
the '__context__' attribute for implicitly chained exceptions, the
|
||||
'__cause__' attribute for explicitly chained exceptions, and the
|
||||
'__traceback__' attribute for the traceback.
|
||||
'__traceback__' attribute for the traceback. A new "raise ... from"
|
||||
statement sets the '__cause__' attribute.
|
||||
|
||||
|
||||
Motivation
|
||||
|
@ -68,10 +69,11 @@ History
|
|||
|
||||
Rationale
|
||||
|
||||
This PEP distinguishes implicit chaining from explicit chaining of
|
||||
exceptions because the unexpected raising of a secondary exception
|
||||
and the intentional translation of an exception are two different
|
||||
situations deserving quite different interpretations.
|
||||
The Python-Dev discussions revealed interest in exception chaining
|
||||
for two quite different purposes. To handle the unexpected raising
|
||||
of a secondary exception, the exception must be retained implicitly.
|
||||
To support intentional translation of an exception, there must be a
|
||||
way to chain exceptions explicitly. This PEP addresses both.
|
||||
|
||||
Several attribute names for chained exceptions have been suggested
|
||||
on Python-Dev [2], including 'cause', 'antecedent', 'reason',
|
||||
|
@ -84,9 +86,8 @@ Rationale
|
|||
occurs in the context of handling another exception.
|
||||
|
||||
This PEP suggests names with leading and trailing double-underscores
|
||||
for '__context__' and '__traceback__' because the attributes are set
|
||||
by the Python VM. The name '__cause__' is not set automatically by
|
||||
the VM, but it seems confusing and collision-prone to use 'cause'.
|
||||
for these three attributes because they are set by the Python VM.
|
||||
Only in very special cases should they be set by normal assignment.
|
||||
|
||||
This PEP handles exceptions that occur during 'except' blocks and
|
||||
'finally' blocks in the same way. Reading the traceback makes it
|
||||
|
@ -98,7 +99,7 @@ Rationale
|
|||
raised exception for compatibility with current behaviour.
|
||||
|
||||
This PEP proposes that tracebacks display the outermost exception
|
||||
last, because it would be consistent with the chronological order
|
||||
last, because this would be consistent with the chronological order
|
||||
of tracebacks (from oldest to most recent frame) and because the
|
||||
actual thrown exception is easier to find on the last line.
|
||||
|
||||
|
@ -109,22 +110,21 @@ Rationale
|
|||
As for other languages, Java and Ruby both discard the original
|
||||
exception when another exception occurs in a 'catch'/'rescue' or
|
||||
'finally'/'ensure' clause. Perl 5 lacks built-in structured
|
||||
exception handling. For Perl 6, RFC 88 proposes an exception
|
||||
mechanism that retains chained exceptions in an array named @@.
|
||||
In that RFC, the most recently raised exception is exposed for
|
||||
matching, as in this PEP; also, arbitrary expressions (possibly
|
||||
involving @@) can be evaluated for exception matching.
|
||||
exception handling. For Perl 6, RFC 88 [9] proposes an exception
|
||||
mechanism that implicitly retains chained exceptions in an array
|
||||
named @@. In that RFC, the most recently raised exception is
|
||||
exposed for matching, as in this PEP; also, arbitrary expressions
|
||||
(possibly involving @@) can be evaluated for exception matching.
|
||||
|
||||
Exceptions in C# contain a read-only 'InnerException' property that
|
||||
may point to another exception [9]. According to its documentation,
|
||||
may point to another exception. Its documentation [10] says that
|
||||
"When an exception X is thrown as a direct result of a previous
|
||||
exception Y, the InnerException property of X should contain a
|
||||
reference to Y." This property is not set by the VM automatically;
|
||||
rather, all exception constructors take an optional 'innerException'
|
||||
argument to set it explicitly. The '__cause__' attribute fulfills
|
||||
the same purpose as InnerException, but this PEP proposes adding a
|
||||
single method to the base Exception class rather than extending the
|
||||
constructors of all exceptions.
|
||||
the same purpose as InnerException, but this PEP proposes a new form
|
||||
of 'raise' rather than extending the constructors of all exceptions.
|
||||
|
||||
The reason all three of these attributes are presented together in
|
||||
one proposal is that the '__traceback__' attribute provides
|
||||
|
@ -207,14 +207,16 @@ Implicit Exception Chaining
|
|||
Explicit Exception Chaining
|
||||
|
||||
The '__cause__' attribute on exception objects is always initialized
|
||||
to None. It is set by calling the 'setcause' method, a new method
|
||||
defined on the base Exception class. For convenience, this method
|
||||
returns the exception itself:
|
||||
to None. It is set by a new form of the 'raise' statement:
|
||||
|
||||
def setcause(self, cause):
|
||||
self.__cause__ = cause
|
||||
return self
|
||||
raise EXCEPTION from CAUSE
|
||||
|
||||
which is equivalent to:
|
||||
|
||||
exc = EXCEPTION
|
||||
exc.__cause__ = CAUSE
|
||||
raise exc
|
||||
|
||||
In the following example, a database provides implementations for a
|
||||
few different kinds of storage, with file storage as one kind. The
|
||||
database designer wants errors to propagate as DatabaseError objects
|
||||
|
@ -229,7 +231,11 @@ Explicit Exception Chaining
|
|||
try:
|
||||
self.file = open(filename)
|
||||
except IOError, exc:
|
||||
raise DatabaseError('failed to open').setcause(exc)
|
||||
raise DatabaseError('failed to open') from exc
|
||||
|
||||
If the call to open() raises an exception, the problem will be
|
||||
reported as a DatabaseError, with a __cause__ attribute that reveals
|
||||
the IOError as the original cause.
|
||||
|
||||
|
||||
Traceback Attribute
|
||||
|
@ -297,7 +303,10 @@ Enhanced Reporting
|
|||
exc, link = exc.__context__, 'During handling...'
|
||||
for exc, link in reversed(chain):
|
||||
print_exc(exc)
|
||||
print '\n' + link + '\n'
|
||||
if link:
|
||||
print
|
||||
print link
|
||||
print
|
||||
|
||||
In the 'traceback' module, the format_exception, print_exception,
|
||||
print_exc, and print_last functions will be updated to accept an
|
||||
|
@ -320,7 +329,8 @@ C API
|
|||
A new API function, PyErr_SetContext(context), will help C
|
||||
programmers provide chained exception information. This function
|
||||
will first normalize the current exception so it is an instance,
|
||||
then set its '__context__' attribute.
|
||||
then set its '__context__' attribute. A similar API function,
|
||||
PyErr_SetCause(cause), will set the '__cause__' attribute.
|
||||
|
||||
|
||||
Compatibility
|
||||
|
@ -328,28 +338,50 @@ Compatibility
|
|||
Chained exceptions expose the type of the most recent exception, so
|
||||
they will still match the same 'except' clauses as they do now.
|
||||
|
||||
The proposed changes should not break any code unless the code sets
|
||||
or uses attributes named '__context__', '__cause__', 'setcause', or
|
||||
'__traceback__' on exception instances. As of 2005-05-12, the
|
||||
Python standard library contains no mention of such attributes.
|
||||
The proposed changes should not break any code unless it sets or
|
||||
uses attributes named '__context__', '__cause__', or '__traceback__'
|
||||
on exception instances. As of 2005-05-12, the Python standard
|
||||
library contains no mention of such attributes.
|
||||
|
||||
|
||||
Open Issues
|
||||
|
||||
Walter Dörwald [10] expressed a desire to attach extra information
|
||||
Walter Dörwald [11] expressed a desire to attach extra information
|
||||
to an exception during its upward propagation without changing its
|
||||
type. This could be a useful feature, but it is not addressed by
|
||||
this PEP. It could conceivably be addressed by a separate PEP
|
||||
establishing conventions for other informational attributes on
|
||||
exceptions.
|
||||
|
||||
It is not clear whether the '__context__' and '__cause__' features
|
||||
proposed here would be sufficient to cover all the use cases that
|
||||
Raymond Hettinger [1] originally had in mind.
|
||||
|
||||
As written, this PEP makes it impossible to suppress '__context__',
|
||||
since setting exc.__context__ to None will only result in it being
|
||||
set again the moment that exc is raised.
|
||||
since setting exc.__context__ to None in an 'except' or 'finally'
|
||||
clause will only result in it being set again when exc is raised.
|
||||
|
||||
To improve encapsulation, library implementors may want to wrap all
|
||||
implementation-level exceptions with an application-level exception.
|
||||
One could try to wrap exceptions by writing this:
|
||||
|
||||
try:
|
||||
... implementation may raise an exception ...
|
||||
except:
|
||||
import sys
|
||||
raise ApplicationError from sys.exc_value
|
||||
|
||||
or this:
|
||||
|
||||
try:
|
||||
... implementation may raise an exception ...
|
||||
except Exception, exc:
|
||||
raise ApplicationError from exc
|
||||
|
||||
but both are somewhat flawed. It would be nice to be able to name
|
||||
the current exception in a catch-all 'except' clause, but that isn't
|
||||
addressed here. Such a feature would allow something like this:
|
||||
|
||||
try:
|
||||
... implementation may raise an exception ...
|
||||
except *, exc:
|
||||
raise ApplicationError from exc
|
||||
|
||||
The exception context is lost when a 'yield' statement is executed;
|
||||
resuming the frame after the 'yield' does not restore the context.
|
||||
|
@ -441,11 +473,14 @@ References
|
|||
|
||||
[8] Guido van Rossum discusses automatic chaining in PyErr_Set*
|
||||
http://mail.python.org/pipermail/python-dev/2003-June/036180.html
|
||||
|
||||
[9] Tony Olensky, "Omnibus Structured Exception/Error Handling Mechanism"
|
||||
http://dev.perl.org/perl6/rfc/88.html
|
||||
|
||||
[9] MSDN .NET Framework Library, "Exception.InnerException Property"
|
||||
[10] MSDN .NET Framework Library, "Exception.InnerException Property"
|
||||
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemexceptionclassinnerexceptiontopic.asp
|
||||
|
||||
[10] Walter Dörwald suggests wrapping exceptions to add details
|
||||
[11] Walter Dörwald suggests wrapping exceptions to add details
|
||||
http://mail.python.org/pipermail/python-dev/2003-June/036148.html
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue