reSTify 5 PEPs (#276)
This commit is contained in:
parent
02969ebbd2
commit
329ed7e935
472
pep-0236.txt
472
pep-0236.txt
|
@ -5,369 +5,375 @@ Last-Modified: $Date$
|
||||||
Author: Tim Peters <tim.peters@gmail.com>
|
Author: Tim Peters <tim.peters@gmail.com>
|
||||||
Status: Final
|
Status: Final
|
||||||
Type: Standards Track
|
Type: Standards Track
|
||||||
|
Content-Type: text/x-rst
|
||||||
Created: 26-Feb-2001
|
Created: 26-Feb-2001
|
||||||
Python-Version: 2.1
|
Python-Version: 2.1
|
||||||
Post-History: 26-Feb-2001
|
Post-History: 26-Feb-2001
|
||||||
|
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
From time to time, Python makes an incompatible change to the
|
From time to time, Python makes an incompatible change to the advertised
|
||||||
advertised semantics of core language constructs, or changes their
|
semantics of core language constructs, or changes their accidental
|
||||||
accidental (implementation-dependent) behavior in some way. While this
|
(implementation-dependent) behavior in some way. While this is never done
|
||||||
is never done capriciously, and is always done with the aim of
|
capriciously, and is always done with the aim of improving the language over
|
||||||
improving the language over the long term, over the short term it's
|
the long term, over the short term it's contentious and disrupting.
|
||||||
contentious and disrupting.
|
|
||||||
|
|
||||||
PEP 5, Guidelines for Language Evolution[1] suggests ways to ease
|
PEP 5, Guidelines for Language Evolution [1]_ suggests ways to ease the pain,
|
||||||
the pain, and this PEP introduces some machinery in support of that.
|
and this PEP introduces some machinery in support of that.
|
||||||
|
|
||||||
PEP 227, Statically Nested Scopes[2] is the first application, and
|
PEP 227, Statically Nested Scopes [2]_ is the first application, and will be
|
||||||
will be used as an example here.
|
used as an example here.
|
||||||
|
|
||||||
|
|
||||||
Intent
|
Intent
|
||||||
|
======
|
||||||
|
|
||||||
[Note: This is policy, and so should eventually move into PEP 5 [1]]
|
[Note: This is policy, and so should eventually move into PEP 5 [1]_]
|
||||||
|
|
||||||
When an incompatible change to core language syntax or semantics is
|
When an incompatible change to core language syntax or semantics is being
|
||||||
being made:
|
made:
|
||||||
|
|
||||||
1. The release C that introduces the change does not change the
|
1. The release C that introduces the change does not change the syntax or
|
||||||
syntax or semantics by default.
|
semantics by default.
|
||||||
|
|
||||||
2. A future release R is identified in which the new syntax or semantics
|
2. A future release R is identified in which the new syntax or semantics will
|
||||||
will be enforced.
|
be enforced.
|
||||||
|
|
||||||
3. The mechanisms described in PEP 3, Warning Framework[3] are
|
3. The mechanisms described in PEP 3, Warning Framework [3]_ are used to
|
||||||
used to generate warnings, whenever possible, about constructs
|
generate warnings, whenever possible, about constructs or operations whose
|
||||||
or operations whose meaning may[4] change in release R.
|
meaning may [4]_ change in release R.
|
||||||
|
|
||||||
4. The new future_statement (see below) can be explicitly included in a
|
4. The new future_statement (see below) can be explicitly included in a module
|
||||||
module M to request that the code in module M use the new syntax or
|
M to request that the code in module M use the new syntax or semantics in
|
||||||
semantics in the current release C.
|
the current release C.
|
||||||
|
|
||||||
So old code continues to work by default, for at least one release,
|
So old code continues to work by default, for at least one release, although
|
||||||
although it may start to generate new warning messages. Migration to
|
it may start to generate new warning messages. Migration to the new syntax or
|
||||||
the new syntax or semantics can proceed during that time, using the
|
semantics can proceed during that time, using the future_statement to make
|
||||||
future_statement to make modules containing it act as if the new syntax
|
modules containing it act as if the new syntax or semantics were already being
|
||||||
or semantics were already being enforced.
|
enforced.
|
||||||
|
|
||||||
Note that there is no need to involve the future_statement machinery
|
Note that there is no need to involve the future_statement machinery in new
|
||||||
in new features unless they can break existing code; fully backward-
|
features unless they can break existing code; fully backward- compatible
|
||||||
compatible additions can-- and should --be introduced without a
|
additions can-- and should --be introduced without a corresponding
|
||||||
corresponding future_statement.
|
future_statement.
|
||||||
|
|
||||||
|
|
||||||
Syntax
|
Syntax
|
||||||
|
======
|
||||||
|
|
||||||
A future_statement is simply a from/import statement using the reserved
|
A future_statement is simply a from/import statement using the reserved module
|
||||||
module name __future__:
|
name ``__future__``::
|
||||||
|
|
||||||
future_statement: "from" "__future__" "import" feature ["as" name]
|
future_statement: "from" "__future__" "import" feature ["as" name]
|
||||||
("," feature ["as" name])*
|
(","feature ["as" name])*
|
||||||
|
|
||||||
feature: identifier
|
feature: identifier
|
||||||
name: identifier
|
name: identifier
|
||||||
|
|
||||||
In addition, all future_statments must appear near the top of the
|
In addition, all future_statments must appear near the top of the module. The
|
||||||
module. The only lines that can appear before a future_statement are:
|
only lines that can appear before a future_statement are:
|
||||||
|
|
||||||
+ The module docstring (if any).
|
+ The module docstring (if any).
|
||||||
+ Comments.
|
+ Comments.
|
||||||
+ Blank lines.
|
+ Blank lines.
|
||||||
+ Other future_statements.
|
+ Other future_statements.
|
||||||
|
|
||||||
Example:
|
Example::
|
||||||
"""This is a module docstring."""
|
|
||||||
|
|
||||||
# This is a comment, preceded by a blank line and followed by
|
"""This is a module docstring."""
|
||||||
# a future_statement.
|
|
||||||
from __future__ import nested_scopes
|
|
||||||
|
|
||||||
from math import sin
|
# This is a comment, preceded by a blank line and followed by
|
||||||
from __future__ import alabaster_weenoblobs # compile-time error!
|
# a future_statement.
|
||||||
# That was an error because preceded by a non-future_statement.
|
from __future__ import nested_scopes
|
||||||
|
|
||||||
|
from math import sin
|
||||||
|
from __future__ import alabaster_weenoblobs # compile-time error!
|
||||||
|
# That was an error because preceded by a non-future_statement.
|
||||||
|
|
||||||
|
|
||||||
Semantics
|
Semantics
|
||||||
|
=========
|
||||||
|
|
||||||
A future_statement is recognized and treated specially at compile time:
|
A future_statement is recognized and treated specially at compile time:
|
||||||
changes to the semantics of core constructs are often implemented by
|
changes to the semantics of core constructs are often implemented by
|
||||||
generating different code. It may even be the case that a new feature
|
generating different code. It may even be the case that a new feature
|
||||||
introduces new incompatible syntax (such as a new reserved word), in
|
introduces new incompatible syntax (such as a new reserved word), in which
|
||||||
which case the compiler may need to parse the module differently. Such
|
case the compiler may need to parse the module differently. Such decisions
|
||||||
decisions cannot be pushed off until runtime.
|
cannot be pushed off until runtime.
|
||||||
|
|
||||||
For any given release, the compiler knows which feature names have been
|
For any given release, the compiler knows which feature names have been
|
||||||
defined, and raises a compile-time error if a future_statement contains
|
defined, and raises a compile-time error if a future_statement contains a
|
||||||
a feature not known to it[5].
|
feature not known to it [5]_.
|
||||||
|
|
||||||
The direct runtime semantics are the same as for any import statement:
|
The direct runtime semantics are the same as for any ``import`` statement:
|
||||||
there is a standard module __future__.py, described later, and it will
|
there is a standard module ``__future__.py``, described later, and it will be
|
||||||
be imported in the usual way at the time the future_statement is
|
imported in the usual way at the time the future_statement is executed.
|
||||||
executed.
|
|
||||||
|
|
||||||
The *interesting* runtime semantics depend on the specific feature(s)
|
The *interesting* runtime semantics depend on the specific feature(s)
|
||||||
"imported" by the future_statement(s) appearing in the module.
|
"imported" by the future_statement(s) appearing in the module.
|
||||||
|
|
||||||
Note that there is nothing special about the statement:
|
Note that there is nothing special about the statement::
|
||||||
|
|
||||||
import __future__ [as name]
|
import __future__ [as name]
|
||||||
|
|
||||||
That is not a future_statement; it's an ordinary import statement, with
|
That is not a future_statement; it's an ordinary import statement, with no
|
||||||
no special semantics or syntax restrictions.
|
special semantics or syntax restrictions.
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
Consider this code, in file scope.py:
|
Consider this code, in file scope.py::
|
||||||
|
|
||||||
x = 42
|
x = 42
|
||||||
def f():
|
def f():
|
||||||
x = 666
|
x = 666
|
||||||
def g():
|
def g():
|
||||||
print "x is", x
|
print "x is", x
|
||||||
g()
|
g()
|
||||||
f()
|
f()
|
||||||
|
|
||||||
Under 2.0, it prints:
|
Under 2.0, it prints::
|
||||||
|
|
||||||
x is 42
|
x is 42
|
||||||
|
|
||||||
Nested scopes[2] are being introduced in 2.1. But under 2.1, it still
|
Nested scopes [2]_ are being introduced in 2.1. But under 2.1, it still
|
||||||
prints
|
prints::
|
||||||
|
|
||||||
x is 42
|
x is 42
|
||||||
|
|
||||||
and also generates a warning.
|
and also generates a warning.
|
||||||
|
|
||||||
In 2.2, and also in 2.1 *if* "from __future__ import nested_scopes" is
|
In 2.2, and also in 2.1 *if* ``from __future__ import nested_scopes`` is
|
||||||
included at the top of scope.py, it prints
|
included at the top of ``scope.py``, it prints::
|
||||||
|
|
||||||
x is 666
|
x is 666
|
||||||
|
|
||||||
|
|
||||||
Standard Module __future__.py
|
Standard Module __future__.py
|
||||||
|
=============================
|
||||||
|
|
||||||
Lib/__future__.py is a real module, and serves three purposes:
|
``Lib/__future__.py`` is a real module, and serves three purposes:
|
||||||
|
|
||||||
1. To avoid confusing existing tools that analyze import statements and
|
1. To avoid confusing existing tools that analyze import statements and expect
|
||||||
expect to find the modules they're importing.
|
to find the modules they're importing.
|
||||||
|
|
||||||
2. To ensure that future_statements run under releases prior to 2.1
|
2. To ensure that future_statements run under releases prior to 2.1 at least
|
||||||
at least yield runtime exceptions (the import of __future__ will
|
yield runtime exceptions (the import of ``__future__`` will fail, because
|
||||||
fail, because there was no module of that name prior to 2.1).
|
there was no module of that name prior to 2.1).
|
||||||
|
|
||||||
3. To document when incompatible changes were introduced, and when they
|
3. To document when incompatible changes were introduced, and when they will
|
||||||
will be-- or were --made mandatory. This is a form of executable
|
be-- or were --made mandatory. This is a form of executable documentation,
|
||||||
documentation, and can be inspected programatically via importing
|
and can be inspected programatically via importing ``__future__`` and
|
||||||
__future__ and examining its contents.
|
examining its contents.
|
||||||
|
|
||||||
Each statement in __future__.py is of the form:
|
Each statement in ``__future__.py`` is of the form::
|
||||||
|
|
||||||
FeatureName = "_Feature(" OptionalRelease "," MandatoryRelease ")"
|
FeatureName = "_Feature(" OptionalRelease "," MandatoryRelease ")"
|
||||||
|
|
||||||
where, normally, OptionalRelease < MandatoryRelease, and both are
|
where, normally, *OptionalRelease* < *MandatoryRelease*, and both are
|
||||||
5-tuples of the same form as sys.version_info:
|
5-tuples of the same form as ``sys.version_info``::
|
||||||
|
|
||||||
(PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int
|
(PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int
|
||||||
PY_MINOR_VERSION, # the 1; an int
|
PY_MINOR_VERSION, # the 1; an int
|
||||||
PY_MICRO_VERSION, # the 0; an int
|
PY_MICRO_VERSION, # the 0; an int
|
||||||
PY_RELEASE_LEVEL, # "alpha", "beta", "candidate" or "final"; string
|
PY_RELEASE_LEVEL, # "alpha", "beta", "candidate" or "final"; string
|
||||||
PY_RELEASE_SERIAL # the 3; an int
|
PY_RELEASE_SERIAL # the 3; an int )
|
||||||
)
|
|
||||||
|
|
||||||
OptionalRelease records the first release in which
|
*OptionalRelease* records the first release in which::
|
||||||
|
|
||||||
from __future__ import FeatureName
|
from __future__ import FeatureName
|
||||||
|
|
||||||
was accepted.
|
was accepted.
|
||||||
|
|
||||||
In the case of MandatoryReleases that have not yet occurred,
|
In the case of *MandatoryReleases* that have not yet occurred,
|
||||||
MandatoryRelease predicts the release in which the feature will become
|
*MandatoryRelease* predicts the release in which the feature will become part
|
||||||
part of the language.
|
of the language.
|
||||||
|
|
||||||
Else MandatoryRelease records when the feature became part of the
|
Else *MandatoryRelease* records when the feature became part of the language;
|
||||||
language; in releases at or after that, modules no longer need
|
in releases at or after that, modules no longer need::
|
||||||
|
|
||||||
from __future__ import FeatureName
|
from __future__ import FeatureName
|
||||||
|
|
||||||
to use the feature in question, but may continue to use such imports.
|
to use the feature in question, but may continue to use such imports.
|
||||||
|
|
||||||
MandatoryRelease may also be None, meaning that a planned feature got
|
*MandatoryRelease* may also be ``None``, meaning that a planned feature got
|
||||||
dropped.
|
dropped.
|
||||||
|
|
||||||
Instances of class _Feature have two corresponding methods,
|
Instances of ``class _Feature`` have two corresponding methods,
|
||||||
.getOptionalRelease() and .getMandatoryRelease().
|
``.getOptionalRelease()`` and ``.getMandatoryRelease()``.
|
||||||
|
|
||||||
No feature line will ever be deleted from __future__.py.
|
No feature line will ever be deleted from ``__future__.py``.
|
||||||
|
|
||||||
Example line:
|
Example line::
|
||||||
|
|
||||||
nested_scopes = _Feature((2, 1, 0, "beta", 1), (2, 2, 0, "final", 0))
|
nested_scopes = _Feature((2, 1, 0, "beta", 1), (2, 2, 0, "final", 0))
|
||||||
|
|
||||||
This means that
|
This means that::
|
||||||
|
|
||||||
from __future__ import nested_scopes
|
from __future__ import nested_scopes
|
||||||
|
|
||||||
will work in all releases at or after 2.1b1, and that nested_scopes are
|
will work in all releases at or after 2.1b1, and that nested_scopes are
|
||||||
intended to be enforced starting in release 2.2.
|
intended to be enforced starting in release 2.2.
|
||||||
|
|
||||||
|
|
||||||
Resolved Problem: Runtime Compilation
|
Resolved Problem: Runtime Compilation
|
||||||
|
======================================
|
||||||
|
|
||||||
Several Python features can compile code during a module's runtime:
|
Several Python features can compile code during a module's runtime:
|
||||||
|
|
||||||
1. The exec statement.
|
1. The ``exec`` statement.
|
||||||
2. The execfile() function.
|
2. The ``execfile()`` function.
|
||||||
3. The compile() function.
|
3. The ``compile()`` function.
|
||||||
4. The eval() function.
|
4. The ``eval()`` function.
|
||||||
5. The input() function.
|
5. The ``input()`` function.
|
||||||
|
|
||||||
Since a module M containing a future_statement naming feature F
|
Since a module M containing a future_statement naming feature F explicitly
|
||||||
explicitly requests that the current release act like a future release
|
requests that the current release act like a future release with respect to F,
|
||||||
with respect to F, any code compiled dynamically from text passed to
|
any code compiled dynamically from text passed to one of these from within M
|
||||||
one of these from within M should probably also use the new syntax or
|
should probably also use the new syntax or semantics associated with F. The
|
||||||
semantics associated with F. The 2.1 release does behave this way.
|
2.1 release does behave this way.
|
||||||
|
|
||||||
This isn't always desired, though. For example, doctest.testmod(M)
|
This isn't always desired, though. For example, ``doctest.testmod(M)``
|
||||||
compiles examples taken from strings in M, and those examples should
|
compiles examples taken from strings in M, and those examples should use M's
|
||||||
use M's choices, not necessarily the doctest module's choices. In the
|
choices, not necessarily the doctest module's choices. In the 2.1 release,
|
||||||
2.1 release, this isn't possible, and no scheme has yet been suggested
|
this isn't possible, and no scheme has yet been suggested for working around
|
||||||
for working around this. NOTE: PEP 264 later addressed this in a
|
this. NOTE: PEP 264 later addressed this in a flexible way, by adding
|
||||||
flexible way, by adding optional arguments to compile().
|
optional arguments to ``compile()``.
|
||||||
|
|
||||||
In any case, a future_statement appearing "near the top" (see Syntax
|
In any case, a future_statement appearing "near the top" (see Syntax above) of
|
||||||
above) of text compiled dynamically by an exec, execfile() or compile()
|
text compiled dynamically by an ``exec``, ``execfile()`` or ``compile()``
|
||||||
applies to the code block generated, but has no further effect on the
|
applies to the code block generated, but has no further effect on the module
|
||||||
module that executes such an exec, execfile() or compile(). This
|
that executes such an ``exec``, ``execfile()`` or ``compile()``. This can't
|
||||||
can't be used to affect eval() or input(), however, because they only
|
be used to affect ``eval()`` or ``input()``, however, because they only allow
|
||||||
allow expression input, and a future_statement is not an expression.
|
expression input, and a future_statement is not an expression.
|
||||||
|
|
||||||
|
|
||||||
Resolved Problem: Native Interactive Shells
|
Resolved Problem: Native Interactive Shells
|
||||||
|
============================================
|
||||||
|
|
||||||
There are two ways to get an interactive shell:
|
There are two ways to get an interactive shell:
|
||||||
|
|
||||||
1. By invoking Python from a command line without a script argument.
|
1. By invoking Python from a command line without a script argument.
|
||||||
|
|
||||||
2. By invoking Python from a command line with the -i switch and with a
|
2. By invoking Python from a command line with the ``-i`` switch and with a
|
||||||
script argument.
|
script argument.
|
||||||
|
|
||||||
An interactive shell can be seen as an extreme case of runtime
|
An interactive shell can be seen as an extreme case of runtime compilation
|
||||||
compilation (see above): in effect, each statement typed at an
|
(see above): in effect, each statement typed at an interactive shell prompt
|
||||||
interactive shell prompt runs a new instance of exec, compile() or
|
runs a new instance of ``exec``, ``compile()`` or ``execfile()``. A
|
||||||
execfile(). A future_statement typed at an interactive shell applies to
|
future_statement typed at an interactive shell applies to the rest of the
|
||||||
the rest of the shell session's life, as if the future_statement had
|
shell session's life, as if the future_statement had appeared at the top of a
|
||||||
appeared at the top of a module.
|
module.
|
||||||
|
|
||||||
|
|
||||||
Resolved Problem: Simulated Interactive Shells
|
Resolved Problem: Simulated Interactive Shells
|
||||||
|
===============================================
|
||||||
|
|
||||||
Interactive shells "built by hand" (by tools such as IDLE and the Emacs
|
Interactive shells "built by hand" (by tools such as IDLE and the Emacs
|
||||||
Python-mode) should behave like native interactive shells (see above).
|
Python-mode) should behave like native interactive shells (see above).
|
||||||
However, the machinery used internally by native interactive shells has
|
However, the machinery used internally by native interactive shells has not
|
||||||
not been exposed, and there isn't a clear way for tools building their
|
been exposed, and there isn't a clear way for tools building their own
|
||||||
own interactive shells to achieve the desired behavior.
|
interactive shells to achieve the desired behavior.
|
||||||
|
|
||||||
NOTE: PEP 264 later addressed this, by adding intelligence to the
|
NOTE: PEP 264 later addressed this, by adding intelligence to the standard
|
||||||
standard codeop.py. Simulated shells that don't use the standard
|
``codeop.py``. Simulated shells that don't use the standard library shell
|
||||||
library shell helpers can get a similar effect by exploiting the
|
helpers can get a similar effect by exploiting the new optional arguments to
|
||||||
new optional arguments to compile() added by PEP 264.
|
``compile()`` added by PEP 264.
|
||||||
|
|
||||||
|
|
||||||
Questions and Answers
|
Questions and Answers
|
||||||
|
=====================
|
||||||
|
|
||||||
Q: What about a "from __past__" version, to get back *old* behavior?
|
What about a "from __past__" version, to get back *old* behavior?
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
A: Outside the scope of this PEP. Seems unlikely to the author,
|
Outside the scope of this PEP. Seems unlikely to the author, though. Write a
|
||||||
though. Write a PEP if you want to pursue it.
|
PEP if you want to pursue it.
|
||||||
|
|
||||||
Q: What about incompatibilities due to changes in the Python virtual
|
What about incompatibilities due to changes in the Python virtual machine?
|
||||||
machine?
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
A: Outside the scope of this PEP, although PEP 5 [1] suggests a grace
|
Outside the scope of this PEP, although PEP 5 [1]_ suggests a grace period
|
||||||
period there too, and the future_statement may also have a role to
|
there too, and the future_statement may also have a role to play there.
|
||||||
play there.
|
|
||||||
|
|
||||||
Q: What about incompatibilities due to changes in Python's C API?
|
What about incompatibilities due to changes in Python's C API?
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
A: Outside the scope of this PEP.
|
Outside the scope of this PEP.
|
||||||
|
|
||||||
Q: I want to wrap future_statements in try/except blocks, so I can
|
I want to wrap future_statements in try/except blocks, so I can use different code depending on which version of Python I'm running. Why can't I?
|
||||||
use different code depending on which version of Python I'm running.
|
-------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
Why can't I?
|
|
||||||
|
|
||||||
A: Sorry! try/except is a runtime feature; future_statements are
|
Sorry! ``try/except`` is a runtime feature; future_statements are primarily
|
||||||
primarily compile-time gimmicks, and your try/except happens long
|
compile-time gimmicks, and your ``try/except`` happens long after the compiler
|
||||||
after the compiler is done. That is, by the time you do
|
is done. That is, by the time you do ``try/except``, the semantics in effect
|
||||||
try/except, the semantics in effect for the module are already a
|
for the module are already a done deal. Since the ``try/except`` wouldn't
|
||||||
done deal. Since the try/except wouldn't accomplish what it
|
accomplish what it *looks* like it should accomplish, it's simply not allowed.
|
||||||
*looks* like it should accomplish, it's simply not allowed. We
|
We also want to keep these special statements very easy to find and to
|
||||||
also want to keep these special statements very easy to find and to
|
recognize.
|
||||||
recognize.
|
|
||||||
|
|
||||||
Note that you *can* import __future__ directly, and use the
|
Note that you *can* import ``__future__`` directly, and use the information in
|
||||||
information in it, along with sys.version_info, to figure out where
|
it, along with ``sys.version_info``, to figure out where the release you're
|
||||||
the release you're running under stands in relation to a given
|
running under stands in relation to a given feature's status.
|
||||||
feature's status.
|
|
||||||
|
|
||||||
Q: Going back to the nested_scopes example, what if release 2.2 comes
|
Going back to the nested_scopes example, what if release 2.2 comes along and I still haven't changed my code? How can I keep the 2.1 behavior then?
|
||||||
along and I still haven't changed my code? How can I keep the 2.1
|
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
behavior then?
|
|
||||||
|
|
||||||
A: By continuing to use 2.1, and not moving to 2.2 until you do change
|
By continuing to use 2.1, and not moving to 2.2 until you do change your
|
||||||
your code. The purpose of future_statement is to make life easier
|
code. The purpose of future_statement is to make life easier for people who
|
||||||
for people who keep current with the latest release in a timely
|
keep current with the latest release in a timely fashion. We don't hate you
|
||||||
fashion. We don't hate you if you don't, but your problems are
|
if you don't, but your problems are much harder to solve, and somebody with
|
||||||
much harder to solve, and somebody with those problems will need to
|
those problems will need to write a PEP addressing them. future_statement is
|
||||||
write a PEP addressing them. future_statement is aimed at a
|
aimed at a different audience.
|
||||||
different audience.
|
|
||||||
|
|
||||||
Q: Overloading "import" sucks. Why not introduce a new statement for
|
Overloading ``import`` sucks. Why not introduce a new statement for this?
|
||||||
this?
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
A: Like maybe "lambda lambda nested_scopes"? That is, unless we
|
Like maybe ``lambda lambda nested_scopes``? That is, unless we introduce a
|
||||||
introduce a new keyword, we can't introduce an entirely new
|
new keyword, we can't introduce an entirely new statement. But if we
|
||||||
statement. But if we introduce a new keyword, that in itself
|
introduce a new keyword, that in itself would break old code. That would be
|
||||||
would break old code. That would be too ironic to bear. Yes,
|
too ironic to bear. Yes, overloading ``import`` does suck, but not as
|
||||||
overloading "import" does suck, but not as energetically as the
|
energetically as the alternatives -- as is, future_statements are 100%
|
||||||
alternatives -- as is, future_statements are 100% backward
|
backward compatible.
|
||||||
compatible.
|
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
This document has been placed in the public domain.
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
References and Footnotes
|
References and Footnotes
|
||||||
|
========================
|
||||||
|
|
||||||
[1] PEP 5, Guidelines for Language Evolution, Prescod
|
.. [1] PEP 5, Guidelines for Language Evolution, Prescod
|
||||||
http://www.python.org/dev/peps/pep-0005/
|
http://www.python.org/dev/peps/pep-0005/
|
||||||
|
|
||||||
[2] PEP 227, Statically Nested Scopes, Hylton
|
.. [2] PEP 227, Statically Nested Scopes, Hylton
|
||||||
http://www.python.org/dev/peps/pep-0227/
|
http://www.python.org/dev/peps/pep-0227/
|
||||||
|
|
||||||
[3] PEP 230, Warning Framework, Van Rossum
|
.. [3] PEP 230, Warning Framework, Van Rossum
|
||||||
http://www.python.org/dev/peps/pep-0230/
|
http://www.python.org/dev/peps/pep-0230/
|
||||||
|
|
||||||
[4] Note that this is "may" and not "will": better safe than sorry. Of
|
.. [4] Note that this is *may* and not *will*: better safe than sorry. Of course
|
||||||
course spurious warnings won't be generated when avoidable with
|
spurious warnings won't be generated when avoidable with reasonable cost.
|
||||||
reasonable cost.
|
|
||||||
|
|
||||||
[5] This ensures that a future_statement run under a release prior to
|
.. [5] This ensures that a future_statement run under a release prior to the
|
||||||
the first one in which a given feature is known (but >= 2.1) will
|
first one in which a given feature is known (but >= 2.1) will raise a
|
||||||
raise a compile-time error rather than silently do a wrong thing.
|
compile-time error rather than silently do a wrong thing. If transported
|
||||||
If transported to a release prior to 2.1, a runtime error will be
|
to a release prior to 2.1, a runtime error will be raised because of the
|
||||||
raised because of the failure to import __future__ (no such module
|
failure to import ``__future__`` (no such module existed in the standard
|
||||||
existed in the standard distribution before the 2.1 release, and
|
distribution before the 2.1 release, and the double underscores make it a
|
||||||
the double underscores make it a reserved name).
|
reserved name).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Local Variables:
|
..
|
||||||
mode: indented-text
|
Local Variables:
|
||||||
indent-tabs-mode: nil
|
mode: indented-text
|
||||||
End:
|
indent-tabs-mode: nil
|
||||||
|
End:
|
||||||
|
|
226
pep-0247.txt
226
pep-0247.txt
|
@ -5,169 +5,169 @@ Last-Modified: $Date$
|
||||||
Author: A.M. Kuchling <amk@amk.ca>
|
Author: A.M. Kuchling <amk@amk.ca>
|
||||||
Status: Final
|
Status: Final
|
||||||
Type: Informational
|
Type: Informational
|
||||||
|
Content-Type: text/x-rst
|
||||||
Created: 23-Mar-2001
|
Created: 23-Mar-2001
|
||||||
Post-History: 20-Sep-2001
|
Post-History: 20-Sep-2001
|
||||||
|
|
||||||
Abstract
|
|
||||||
|
|
||||||
There are several different modules available that implement
|
Abstract
|
||||||
cryptographic hashing algorithms such as MD5 or SHA. This
|
========
|
||||||
document specifies a standard API for such algorithms, to make it
|
|
||||||
easier to switch between different implementations.
|
There are several different modules available that implement cryptographic
|
||||||
|
hashing algorithms such as MD5 or SHA. This document specifies a standard API
|
||||||
|
for such algorithms, to make it easier to switch between different
|
||||||
|
implementations.
|
||||||
|
|
||||||
|
|
||||||
Specification
|
Specification
|
||||||
|
=============
|
||||||
|
|
||||||
All hashing modules should present the same interface. Additional
|
All hashing modules should present the same interface. Additional methods or
|
||||||
methods or variables can be added, but those described in this
|
variables can be added, but those described in this document should always be
|
||||||
document should always be present.
|
present.
|
||||||
|
|
||||||
Hash function modules define one function:
|
Hash function modules define one function:
|
||||||
|
|
||||||
new([string]) (unkeyed hashes)
|
| ``new([string]) (unkeyed hashes)``
|
||||||
new([key] , [string]) (keyed hashes)
|
| ``new([key] , [string]) (keyed hashes)``
|
||||||
|
|
||||||
Create a new hashing object and return it. The first form is
|
Create a new hashing object and return it. The first form is for hashes
|
||||||
for hashes that are unkeyed, such as MD5 or SHA. For keyed
|
that are unkeyed, such as MD5 or SHA. For keyed hashes such as HMAC, *key*
|
||||||
hashes such as HMAC, 'key' is a required parameter containing
|
is a required parameter containing a string giving the key to use. In both
|
||||||
a string giving the key to use. In both cases, the optional
|
cases, the optional *string* parameter, if supplied, will be immediately
|
||||||
'string' parameter, if supplied, will be immediately hashed
|
hashed into the object's starting state, as if ``obj.update(string)``
|
||||||
into the object's starting state, as if obj.update(string) was
|
was called.
|
||||||
called.
|
|
||||||
|
|
||||||
After creating a hashing object, arbitrary strings can be fed
|
After creating a hashing object, arbitrary strings can be fed into the
|
||||||
into the object using its update() method, and the hash value
|
object using its ``update()`` method, and the hash value can be obtained at
|
||||||
can be obtained at any time by calling the object's digest()
|
any time by calling the object's ``digest()`` method.
|
||||||
method.
|
|
||||||
|
|
||||||
Arbitrary additional keyword arguments can be added to this
|
Arbitrary additional keyword arguments can be added to this function, but if
|
||||||
function, but if they're not supplied, sensible default values
|
they're not supplied, sensible default values should be used. For example,
|
||||||
should be used. For example, 'rounds' and 'digest_size'
|
``rounds`` and ``digest_size`` keywords could be added for a hash function
|
||||||
keywords could be added for a hash function which supports a
|
which supports a variable number of rounds and several different output
|
||||||
variable number of rounds and several different output sizes,
|
sizes, and they should default to values believed to be secure.
|
||||||
and they should default to values believed to be secure.
|
|
||||||
|
|
||||||
Hash function modules define one variable:
|
Hash function modules define one variable:
|
||||||
|
|
||||||
digest_size
|
| ``digest_size``
|
||||||
|
|
||||||
An integer value; the size of the digest produced by the
|
An integer value; the size of the digest produced by the hashing objects
|
||||||
hashing objects created by this module, measured in bytes.
|
created by this module, measured in bytes. You could also obtain this value
|
||||||
You could also obtain this value by creating a sample object
|
by creating a sample object and accessing its ``digest_size`` attribute, but
|
||||||
and accessing its 'digest_size' attribute, but it can be
|
it can be convenient to have this value available from the module. Hashes
|
||||||
convenient to have this value available from the module.
|
with a variable output size will set this variable to ``None``.
|
||||||
Hashes with a variable output size will set this variable to
|
|
||||||
None.
|
|
||||||
|
|
||||||
Hashing objects require a single attribute:
|
Hashing objects require a single attribute:
|
||||||
|
|
||||||
digest_size
|
| ``digest_size``
|
||||||
|
|
||||||
This attribute is identical to the module-level digest_size
|
This attribute is identical to the module-level ``digest_size`` variable,
|
||||||
variable, measuring the size of the digest produced by the
|
measuring the size of the digest produced by the hashing object, measured in
|
||||||
hashing object, measured in bytes. If the hash has a variable
|
bytes. If the hash has a variable output size, this output size must be
|
||||||
output size, this output size must be chosen when the hashing
|
chosen when the hashing object is created, and this attribute must contain
|
||||||
object is created, and this attribute must contain the
|
the selected size. Therefore, ``None`` is *not* a legal value for this
|
||||||
selected size. Therefore, None is *not* a legal value for this
|
attribute.
|
||||||
attribute.
|
|
||||||
|
|
||||||
|
|
||||||
Hashing objects require the following methods:
|
Hashing objects require the following methods:
|
||||||
|
|
||||||
copy()
|
| ``copy()``
|
||||||
|
|
||||||
Return a separate copy of this hashing object. An update to
|
Return a separate copy of this hashing object. An update to this copy won't
|
||||||
this copy won't affect the original object.
|
affect the original object.
|
||||||
|
|
||||||
digest()
|
| ``digest()``
|
||||||
|
|
||||||
Return the hash value of this hashing object as a string
|
Return the hash value of this hashing object as a string containing 8-bit
|
||||||
containing 8-bit data. The object is not altered in any way
|
data. The object is not altered in any way by this function; you can
|
||||||
by this function; you can continue updating the object after
|
continue updating the object after calling this function.
|
||||||
calling this function.
|
|
||||||
|
|
||||||
hexdigest()
|
| ``hexdigest()``
|
||||||
|
|
||||||
Return the hash value of this hashing object as a string
|
Return the hash value of this hashing object as a string containing
|
||||||
containing hexadecimal digits. Lowercase letters should be used
|
hexadecimal digits. Lowercase letters should be used for the digits ``a``
|
||||||
for the digits 'a' through 'f'. Like the .digest() method, this
|
through ``f``. Like the ``.digest()`` method, this method mustn't alter the
|
||||||
method mustn't alter the object.
|
object.
|
||||||
|
|
||||||
update(string)
|
| ``update(string)``
|
||||||
|
|
||||||
Hash 'string' into the current state of the hashing object.
|
Hash *string* into the current state of the hashing object. ``update()`` can
|
||||||
update() can be called any number of times during a hashing
|
be called any number of times during a hashing object's lifetime.
|
||||||
object's lifetime.
|
|
||||||
|
|
||||||
Hashing modules can define additional module-level functions or
|
Hashing modules can define additional module-level functions or object methods
|
||||||
object methods and still be compliant with this specification.
|
and still be compliant with this specification.
|
||||||
|
|
||||||
Here's an example, using a module named 'MD5':
|
Here's an example, using a module named ``MD5``::
|
||||||
|
|
||||||
>>> from Crypto.Hash import MD5
|
>>> from Crypto.Hash import MD5
|
||||||
>>> m = MD5.new()
|
>>> m = MD5.new()
|
||||||
>>> m.digest_size
|
>>> m.digest_size
|
||||||
16
|
16
|
||||||
>>> m.update('abc')
|
>>> m.update('abc')
|
||||||
>>> m.digest()
|
>>> m.digest()
|
||||||
'\x90\x01P\x98<\xd2O\xb0\xd6\x96?}(\xe1\x7fr'
|
'\x90\x01P\x98<\xd2O\xb0\xd6\x96?}(\xe1\x7fr'
|
||||||
>>> m.hexdigest()
|
>>> m.hexdigest()
|
||||||
'900150983cd24fb0d6963f7d28e17f72'
|
'900150983cd24fb0d6963f7d28e17f72'
|
||||||
>>> MD5.new('abc').digest()
|
>>> MD5.new('abc').digest()
|
||||||
'\x90\x01P\x98<\xd2O\xb0\xd6\x96?}(\xe1\x7fr'
|
'\x90\x01P\x98<\xd2O\xb0\xd6\x96?}(\xe1\x7fr'
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
The digest size is measured in bytes, not bits, even though hash
|
The digest size is measured in bytes, not bits, even though hash algorithm
|
||||||
algorithm sizes are usually quoted in bits; MD5 is a 128-bit
|
sizes are usually quoted in bits; MD5 is a 128-bit algorithm and not a 16-byte
|
||||||
algorithm and not a 16-byte one, for example. This is because, in
|
one, for example. This is because, in the sample code I looked at, the length
|
||||||
the sample code I looked at, the length in bytes is often needed
|
in bytes is often needed (to seek ahead or behind in a file; to compute the
|
||||||
(to seek ahead or behind in a file; to compute the length of an
|
length of an output string) while the length in bits is rarely used. Therefore,
|
||||||
output string) while the length in bits is rarely used.
|
the burden will fall on the few people actually needing the size in bits, who
|
||||||
Therefore, the burden will fall on the few people actually needing
|
will have to multiply ``digest_size`` by 8.
|
||||||
the size in bits, who will have to multiply digest_size by 8.
|
|
||||||
|
|
||||||
It's been suggested that the update() method would be better named
|
It's been suggested that the ``update()`` method would be better named
|
||||||
append(). However, that method is really causing the current
|
``append()``. However, that method is really causing the current state of the
|
||||||
state of the hashing object to be updated, and update() is already
|
hashing object to be updated, and ``update()`` is already used by the md5 and
|
||||||
used by the md5 and sha modules included with Python, so it seems
|
sha modules included with Python, so it seems simplest to leave the name
|
||||||
simplest to leave the name update() alone.
|
``update()`` alone.
|
||||||
|
|
||||||
The order of the constructor's arguments for keyed hashes was a
|
The order of the constructor's arguments for keyed hashes was a sticky issue.
|
||||||
sticky issue. It wasn't clear whether the key should come first
|
It wasn't clear whether the *key* should come first or second. It's a required
|
||||||
or second. It's a required parameter, and the usual convention is
|
parameter, and the usual convention is to place required parameters first, but
|
||||||
to place required parameters first, but that also means that the
|
that also means that the *string* parameter moves from the first position to
|
||||||
'string' parameter moves from the first position to the second.
|
the second. It would be possible to get confused and pass a single argument to
|
||||||
It would be possible to get confused and pass a single argument to
|
a keyed hash, thinking that you're passing an initial string to an unkeyed
|
||||||
a keyed hash, thinking that you're passing an initial string to an
|
hash, but it doesn't seem worth making the interface for keyed hashes more
|
||||||
unkeyed hash, but it doesn't seem worth making the interface
|
obscure to avoid this potential error.
|
||||||
for keyed hashes more obscure to avoid this potential error.
|
|
||||||
|
|
||||||
|
|
||||||
Changes
|
Changes
|
||||||
|
=======
|
||||||
|
|
||||||
2001-09-17: Renamed clear() to reset(); added digest_size attribute
|
2001-09-17: Renamed ``clear()`` to ``reset()``; added ``digest_size`` attribute
|
||||||
to objects; added .hexdigest() method.
|
to objects; added ``.hexdigest()`` method.
|
||||||
2001-09-20: Removed reset() method completely.
|
|
||||||
2001-09-28: Set digest_size to None for variable-size hashes.
|
2001-09-20: Removed ``reset()`` method completely.
|
||||||
|
|
||||||
|
2001-09-28: Set ``digest_size`` to ``None`` for variable-size hashes.
|
||||||
|
|
||||||
|
|
||||||
Acknowledgements
|
Acknowledgements
|
||||||
|
================
|
||||||
|
|
||||||
Thanks to Aahz, Andrew Archibald, Rich Salz, Itamar
|
Thanks to Aahz, Andrew Archibald, Rich Salz, Itamar Shtull-Trauring, and the
|
||||||
Shtull-Trauring, and the readers of the python-crypto list for
|
readers of the python-crypto list for their comments on this PEP.
|
||||||
their comments on this PEP.
|
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
This document has been placed in the public domain.
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Local Variables:
|
..
|
||||||
mode: indented-text
|
Local Variables:
|
||||||
indent-tabs-mode: nil
|
mode: indented-text
|
||||||
End:
|
indent-tabs-mode: nil
|
||||||
|
End:
|
||||||
|
|
||||||
|
|
945
pep-0342.txt
945
pep-0342.txt
File diff suppressed because it is too large
Load Diff
747
pep-0344.txt
747
pep-0344.txt
|
@ -5,541 +5,560 @@ Last-Modified: $Date$
|
||||||
Author: Ka-Ping Yee
|
Author: Ka-Ping Yee
|
||||||
Status: Superseded
|
Status: Superseded
|
||||||
Type: Standards Track
|
Type: Standards Track
|
||||||
Content-Type: text/plain
|
Content-Type: text/x-rst
|
||||||
Created: 12-May-2005
|
Created: 12-May-2005
|
||||||
Python-Version: 2.5
|
Python-Version: 2.5
|
||||||
Post-History:
|
Post-History:
|
||||||
|
|
||||||
|
|
||||||
Numbering Note
|
Numbering Note
|
||||||
|
==============
|
||||||
|
|
||||||
This PEP has been renumbered to PEP 3134. The text below is the
|
This PEP has been renumbered to PEP 3134. The text below is the last version
|
||||||
last version submitted under the old number.
|
submitted under the old number.
|
||||||
|
|
||||||
|
|
||||||
Abstract
|
Abstract
|
||||||
|
========
|
||||||
|
|
||||||
This PEP proposes three standard attributes on exception instances:
|
This PEP proposes three standard attributes on exception instances: the
|
||||||
the '__context__' attribute for implicitly chained exceptions, the
|
``__context__`` attribute for implicitly chained exceptions, the
|
||||||
'__cause__' attribute for explicitly chained exceptions, and the
|
``__cause__`` attribute for explicitly chained exceptions, and the
|
||||||
'__traceback__' attribute for the traceback. A new "raise ... from"
|
``__traceback__`` attribute for the traceback. A new ``raise ... from``
|
||||||
statement sets the '__cause__' attribute.
|
statement sets the ``__cause__`` attribute.
|
||||||
|
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
During the handling of one exception (exception A), it is possible
|
During the handling of one exception (exception A), it is possible that another
|
||||||
that another exception (exception B) may occur. In today's Python
|
exception (exception B) may occur. In today's Python (version 2.4), if this
|
||||||
(version 2.4), if this happens, exception B is propagated outward
|
happens, exception B is propagated outward and exception A is lost. In order
|
||||||
and exception A is lost. In order to debug the problem, it is
|
to debug the problem, it is useful to know about both exceptions. The
|
||||||
useful to know about both exceptions. The '__context__' attribute
|
``__context__`` attribute retains this information automatically.
|
||||||
retains this information automatically.
|
|
||||||
|
|
||||||
Sometimes it can be useful for an exception handler to intentionally
|
Sometimes it can be useful for an exception handler to intentionally re-raise
|
||||||
re-raise an exception, either to provide extra information or to
|
an exception, either to provide extra information or to translate an exception
|
||||||
translate an exception to another type. The '__cause__' attribute
|
to another type. The ``__cause__`` attribute provides an explicit way to
|
||||||
provides an explicit way to record the direct cause of an exception.
|
record the direct cause of an exception.
|
||||||
|
|
||||||
In today's Python implementation, exceptions are composed of three
|
In today's Python implementation, exceptions are composed of three parts: the
|
||||||
parts: the type, the value, and the traceback. The 'sys' module,
|
type, the value, and the traceback. The ``sys`` module, exposes the current
|
||||||
exposes the current exception in three parallel variables, exc_type,
|
exception in three parallel variables, ``exc_type``, ``exc_value``, and
|
||||||
exc_value, and exc_traceback, the sys.exc_info() function returns a
|
``exc_traceback``, the ``sys.exc_info()`` function returns a tuple of these
|
||||||
tuple of these three parts, and the 'raise' statement has a
|
three parts, and the ``raise`` statement has a three-argument form accepting
|
||||||
three-argument form accepting these three parts. Manipulating
|
these three parts. Manipulating exceptions often requires passing these three
|
||||||
exceptions often requires passing these three things in parallel,
|
things in parallel, which can be tedious and error-prone. Additionally, the
|
||||||
which can be tedious and error-prone. Additionally, the 'except'
|
``except`` statement can only provide access to the value, not the traceback.
|
||||||
statement can only provide access to the value, not the traceback.
|
Adding the ``__traceback__`` attribute to exception values makes all the
|
||||||
Adding the '__traceback__' attribute to exception values makes all
|
exception information accessible from a single place.
|
||||||
the exception information accessible from a single place.
|
|
||||||
|
|
||||||
|
|
||||||
History
|
History
|
||||||
|
=======
|
||||||
|
|
||||||
Raymond Hettinger [1] raised the issue of masked exceptions on
|
Raymond Hettinger [1]_ raised the issue of masked exceptions on Python-Dev in
|
||||||
Python-Dev in January 2003 and proposed a PyErr_FormatAppend()
|
January 2003 and proposed a ``PyErr_FormatAppend()`` function that C modules
|
||||||
function that C modules could use to augment the currently active
|
could use to augment the currently active exception with more information.
|
||||||
exception with more information. Brett Cannon [2] brought up
|
Brett Cannon [2]_ brought up chained exceptions again in June 2003, prompting
|
||||||
chained exceptions again in June 2003, prompting a long discussion.
|
a long discussion.
|
||||||
|
|
||||||
Greg Ewing [3] identified the case of an exception occurring in a
|
Greg Ewing [3]_ identified the case of an exception occurring in a ``finally``
|
||||||
'finally' block during unwinding triggered by an original exception,
|
block during unwinding triggered by an original exception, as distinct from
|
||||||
as distinct from the case of an exception occurring in an 'except'
|
the case of an exception occurring in an ``except`` block that is handling the
|
||||||
block that is handling the original exception.
|
original exception.
|
||||||
|
|
||||||
Greg Ewing [4] and Guido van Rossum [5], and probably others, have
|
Greg Ewing [4]_ and Guido van Rossum [5]_, and probably others, have
|
||||||
previously mentioned adding a traceback attribute to Exception
|
previously mentioned adding a traceback attribute to ``Exception`` instances.
|
||||||
instances. This is noted in PEP 3000.
|
This is noted in PEP 3000.
|
||||||
|
|
||||||
This PEP was motivated by yet another recent Python-Dev reposting
|
This PEP was motivated by yet another recent Python-Dev reposting of the same
|
||||||
of the same ideas [6] [7].
|
ideas [6]_ [7]_.
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
The Python-Dev discussions revealed interest in exception chaining
|
The Python-Dev discussions revealed interest in exception chaining for two
|
||||||
for two quite different purposes. To handle the unexpected raising
|
quite different purposes. To handle the unexpected raising of a secondary
|
||||||
of a secondary exception, the exception must be retained implicitly.
|
exception, the exception must be retained implicitly. To support intentional
|
||||||
To support intentional translation of an exception, there must be a
|
translation of an exception, there must be a way to chain exceptions
|
||||||
way to chain exceptions explicitly. This PEP addresses both.
|
explicitly. This PEP addresses both.
|
||||||
|
|
||||||
Several attribute names for chained exceptions have been suggested
|
Several attribute names for chained exceptions have been suggested on Python-
|
||||||
on Python-Dev [2], including 'cause', 'antecedent', 'reason',
|
Dev [2]_, including ``cause``, ``antecedent``, ``reason``, ``original``,
|
||||||
'original', 'chain', 'chainedexc', 'exc_chain', 'excprev',
|
``chain``, ``chainedexc``, ``xc_chain``, ``excprev``, ``previous`` and
|
||||||
'previous', and 'precursor'. For an explicitly chained exception,
|
``precursor``. For an explicitly chained exception, this PEP suggests
|
||||||
this PEP suggests '__cause__' because of its specific meaning. For
|
``__cause__`` because of its specific meaning. For an implicitly chained
|
||||||
an implicitly chained exception, this PEP proposes the name
|
exception, this PEP proposes the name ``__context__`` because the intended
|
||||||
'__context__' because the intended meaning is more specific than
|
meaning is more specific than temporal precedence but less specific than
|
||||||
temporal precedence but less specific than causation: an exception
|
causation: an exception occurs in the context of handling another exception.
|
||||||
occurs in the context of handling another exception.
|
|
||||||
|
|
||||||
This PEP suggests names with leading and trailing double-underscores
|
This PEP suggests names with leading and trailing double-underscores for these
|
||||||
for these three attributes because they are set by the Python VM.
|
three attributes because they are set by the Python VM. Only in very special
|
||||||
Only in very special cases should they be set by normal assignment.
|
cases should they be set by normal assignment.
|
||||||
|
|
||||||
This PEP handles exceptions that occur during 'except' blocks and
|
This PEP handles exceptions that occur during ``except`` blocks and
|
||||||
'finally' blocks in the same way. Reading the traceback makes it
|
``finally`` blocks in the same way. Reading the traceback makes it clear
|
||||||
clear where the exceptions occurred, so additional mechanisms for
|
where the exceptions occurred, so additional mechanisms for distinguishing
|
||||||
distinguishing the two cases would only add unnecessary complexity.
|
the two cases would only add unnecessary complexity.
|
||||||
|
|
||||||
This PEP proposes that the outermost exception object (the one
|
This PEP proposes that the outermost exception object (the one exposed for
|
||||||
exposed for matching by 'except' clauses) be the most recently
|
matching by ``except`` clauses) be the most recently raised exception for
|
||||||
raised exception for compatibility with current behaviour.
|
compatibility with current behaviour.
|
||||||
|
|
||||||
This PEP proposes that tracebacks display the outermost exception
|
This PEP proposes that tracebacks display the outermost exception last,
|
||||||
last, because this would be consistent with the chronological order
|
because this would be consistent with the chronological order of tracebacks
|
||||||
of tracebacks (from oldest to most recent frame) and because the
|
(from oldest to most recent frame) and because the actual thrown exception is
|
||||||
actual thrown exception is easier to find on the last line.
|
easier to find on the last line.
|
||||||
|
|
||||||
To keep things simpler, the C API calls for setting an exception
|
To keep things simpler, the C API calls for setting an exception will not
|
||||||
will not automatically set the exception's '__context__'. Guido
|
automatically set the exception's ``__context__``. Guido van Rossum has
|
||||||
van Rossum has expressed concerns with making such changes [8].
|
expressed concerns with making such changes [8]_.
|
||||||
|
|
||||||
As for other languages, Java and Ruby both discard the original
|
As for other languages, Java and Ruby both discard the original exception when
|
||||||
exception when another exception occurs in a 'catch'/'rescue' or
|
another exception occurs in a ``catch/rescue`` or ``finally/ensure`` clause.
|
||||||
'finally'/'ensure' clause. Perl 5 lacks built-in structured
|
Perl 5 lacks built-in structured exception handling. For Perl 6, RFC number
|
||||||
exception handling. For Perl 6, RFC number 88 [9] proposes an exception
|
88 [9]_ proposes an exception mechanism that implicitly retains chained
|
||||||
mechanism that implicitly retains chained exceptions in an array
|
exceptions in an array named ``@@``. In that RFC, the most recently raised
|
||||||
named @@. In that RFC, the most recently raised exception is
|
exception is exposed for matching, as in this PEP; also, arbitrary expressions
|
||||||
exposed for matching, as in this PEP; also, arbitrary expressions
|
(possibly involving ``@@``) can be evaluated for exception matching.
|
||||||
(possibly involving @@) can be evaluated for exception matching.
|
|
||||||
|
|
||||||
Exceptions in C# contain a read-only 'InnerException' property that
|
Exceptions in C# contain a read-only ``InnerException`` property that may
|
||||||
may point to another exception. Its documentation [10] says that
|
point to another exception. Its documentation [10]_ says that "When an
|
||||||
"When an exception X is thrown as a direct result of a previous
|
exception X is thrown as a direct result of a previous exception Y, the
|
||||||
exception Y, the InnerException property of X should contain a
|
``InnerException`` property of X should contain a reference to Y." This
|
||||||
reference to Y." This property is not set by the VM automatically;
|
property is not set by the VM automatically; rather, all exception
|
||||||
rather, all exception constructors take an optional 'innerException'
|
constructors take an optional ``innerException`` argument to set it
|
||||||
argument to set it explicitly. The '__cause__' attribute fulfills
|
explicitly. The ``__cause__`` attribute fulfills the same purpose as
|
||||||
the same purpose as InnerException, but this PEP proposes a new form
|
``InnerException``, but this PEP proposes a new form of ``raise`` rather than
|
||||||
of 'raise' rather than extending the constructors of all exceptions.
|
extending the constructors of all exceptions. C# also provides a
|
||||||
C# also provides a GetBaseException method that jumps directly to
|
``GetBaseException`` method that jumps directly to the end of the
|
||||||
the end of the InnerException chain; this PEP proposes no analog.
|
``InnerException`` chain; this PEP proposes no analog.
|
||||||
|
|
||||||
The reason all three of these attributes are presented together in
|
The reason all three of these attributes are presented together in one proposal
|
||||||
one proposal is that the '__traceback__' attribute provides
|
is that the ``__traceback__`` attribute provides convenient access to the
|
||||||
convenient access to the traceback on chained exceptions.
|
traceback on chained exceptions.
|
||||||
|
|
||||||
|
|
||||||
Implicit Exception Chaining
|
Implicit Exception Chaining
|
||||||
|
===========================
|
||||||
|
|
||||||
Here is an example to illustrate the '__context__' attribute.
|
Here is an example to illustrate the ``__context__`` attribute::
|
||||||
|
|
||||||
def compute(a, b):
|
def compute(a, b):
|
||||||
|
try:
|
||||||
|
a/b
|
||||||
|
except Exception, exc:
|
||||||
|
log(exc)
|
||||||
|
|
||||||
|
def log(exc):
|
||||||
|
file = open('logfile.txt') # oops, forgot the 'w'
|
||||||
|
print >>file, exc
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
Calling ``compute(0, 0)`` causes a ``ZeroDivisionError``. The ``compute()``
|
||||||
|
function catches this exception and calls ``log(exc)``, but the ``log()``
|
||||||
|
function also raises an exception when it tries to write to a file that wasn't
|
||||||
|
opened for writing.
|
||||||
|
|
||||||
|
In today's Python, the caller of ``compute()`` gets thrown an ``IOError``. The
|
||||||
|
``ZeroDivisionError`` is lost. With the proposed change, the instance of
|
||||||
|
``IOError`` has an additional ``__context__`` attribute that retains the
|
||||||
|
``ZeroDivisionError``.
|
||||||
|
|
||||||
|
The following more elaborate example demonstrates the handling of a mixture of
|
||||||
|
``finally`` and ``except`` clauses::
|
||||||
|
|
||||||
|
def main(filename):
|
||||||
|
file = open(filename) # oops, forgot the 'w'
|
||||||
|
try:
|
||||||
try:
|
try:
|
||||||
a/b
|
compute()
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
log(exc)
|
log(file, exc)
|
||||||
|
|
||||||
def log(exc):
|
|
||||||
file = open('logfile.txt') # oops, forgot the 'w'
|
|
||||||
print >>file, exc
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
Calling compute(0, 0) causes a ZeroDivisionError. The compute()
|
|
||||||
function catches this exception and calls log(exc), but the log()
|
|
||||||
function also raises an exception when it tries to write to a
|
|
||||||
file that wasn't opened for writing.
|
|
||||||
|
|
||||||
In today's Python, the caller of compute() gets thrown an IOError.
|
|
||||||
The ZeroDivisionError is lost. With the proposed change, the
|
|
||||||
instance of IOError has an additional '__context__' attribute that
|
|
||||||
retains the ZeroDivisionError.
|
|
||||||
|
|
||||||
The following more elaborate example demonstrates the handling of a
|
|
||||||
mixture of 'finally' and 'except' clauses:
|
|
||||||
|
|
||||||
def main(filename):
|
|
||||||
file = open(filename) # oops, forgot the 'w'
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
compute()
|
|
||||||
except Exception, exc:
|
|
||||||
log(file, exc)
|
|
||||||
finally:
|
finally:
|
||||||
file.clos() # oops, misspelled 'close'
|
file.clos() # oops, misspelled 'close'
|
||||||
|
|
||||||
def compute():
|
def compute():
|
||||||
1/0
|
1/0
|
||||||
|
|
||||||
def log(file, exc):
|
def log(file, exc):
|
||||||
try:
|
try:
|
||||||
print >>file, exc # oops, file is not writable
|
print >>file, exc # oops, file is not writable
|
||||||
except:
|
except:
|
||||||
display(exc)
|
display(exc)
|
||||||
|
|
||||||
def display(exc):
|
def display(exc):
|
||||||
print ex # oops, misspelled 'exc'
|
print ex # oops, misspelled 'exc'
|
||||||
|
|
||||||
Calling main() with the name of an existing file will trigger four
|
Calling ``main()`` with the name of an existing file will trigger four
|
||||||
exceptions. The ultimate result will be an AttributeError due to
|
exceptions. The ultimate result will be an ``AttributeError`` due to the
|
||||||
the misspelling of 'clos', whose __context__ points to a NameError
|
misspelling of ``clos``, whose ``__context__`` points to a ``NameError`` due
|
||||||
due to the misspelling of 'ex', whose __context__ points to an
|
to the misspelling of ``ex``, whose ``__context__`` points to an ``IOError``
|
||||||
IOError due to the file being read-only, whose __context__ points to
|
due to the file being read-only, whose ``__context__`` points to a
|
||||||
a ZeroDivisionError, whose __context__ attribute is None.
|
``ZeroDivisionError``, whose ``__context__`` attribute is ``None``.
|
||||||
|
|
||||||
The proposed semantics are as follows:
|
The proposed semantics are as follows:
|
||||||
|
|
||||||
1. Each thread has an exception context initially set to None.
|
1. Each thread has an exception context initially set to ``None``.
|
||||||
|
|
||||||
2. Whenever an exception is raised, if the exception instance does
|
2. Whenever an exception is raised, if the exception instance does not
|
||||||
not already have a '__context__' attribute, the interpreter sets
|
already have a ``__context__`` attribute, the interpreter sets it equal to
|
||||||
it equal to the thread's exception context.
|
the thread's exception context.
|
||||||
|
|
||||||
3. Immediately after an exception is raised, the thread's exception
|
3. Immediately after an exception is raised, the thread's exception context is
|
||||||
context is set to the exception.
|
set to the exception.
|
||||||
|
|
||||||
4. Whenever the interpreter exits an 'except' block by reaching the
|
4. Whenever the interpreter exits an ``except`` block by reaching the end or
|
||||||
end or executing a 'return', 'yield', 'continue', or 'break'
|
executing a ``return``, ``yield``, ``continue``, or ``break`` statement,
|
||||||
statement, the thread's exception context is set to None.
|
the thread's exception context is set to ``None``.
|
||||||
|
|
||||||
|
|
||||||
Explicit Exception Chaining
|
Explicit Exception Chaining
|
||||||
|
===========================
|
||||||
|
|
||||||
The '__cause__' attribute on exception objects is always initialized
|
The ``__cause__`` attribute on exception objects is always initialized to
|
||||||
to None. It is set by a new form of the 'raise' statement:
|
``None``. It is set by a new form of the ``raise`` statement::
|
||||||
|
|
||||||
raise EXCEPTION from CAUSE
|
raise EXCEPTION from CAUSE
|
||||||
|
|
||||||
which is equivalent to:
|
which is equivalent to::
|
||||||
|
|
||||||
exc = EXCEPTION
|
exc = EXCEPTION
|
||||||
exc.__cause__ = CAUSE
|
exc.__cause__ = CAUSE
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
In the following example, a database provides implementations for a
|
In the following example, a database provides implementations for a few
|
||||||
few different kinds of storage, with file storage as one kind. The
|
different kinds of storage, with file storage as one kind. The database
|
||||||
database designer wants errors to propagate as DatabaseError objects
|
designer wants errors to propagate as ``DatabaseError`` objects so that the
|
||||||
so that the client doesn't have to be aware of the storage-specific
|
client doesn't have to be aware of the storage-specific details, but doesn't
|
||||||
details, but doesn't want to lose the underlying error information.
|
want to lose the underlying error information::
|
||||||
|
|
||||||
class DatabaseError(StandardError):
|
class DatabaseError(StandardError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class FileDatabase(Database):
|
class FileDatabase(Database):
|
||||||
def __init__(self, filename):
|
def __init__(self, filename):
|
||||||
try:
|
try:
|
||||||
self.file = open(filename)
|
self.file = open(filename)
|
||||||
except IOError, exc:
|
except IOError, exc:
|
||||||
raise DatabaseError('failed to open') from exc
|
raise DatabaseError('failed to open') from exc
|
||||||
|
|
||||||
If the call to open() raises an exception, the problem will be
|
If the call to ``open()`` raises an exception, the problem will be reported as
|
||||||
reported as a DatabaseError, with a __cause__ attribute that reveals
|
a ``DatabaseError``, with a ``__cause__`` attribute that reveals the
|
||||||
the IOError as the original cause.
|
``IOError`` as the original cause.
|
||||||
|
|
||||||
|
|
||||||
Traceback Attribute
|
Traceback Attribute
|
||||||
|
===================
|
||||||
|
|
||||||
The following example illustrates the '__traceback__' attribute.
|
The following example illustrates the ``__traceback__`` attribute::
|
||||||
|
|
||||||
def do_logged(file, work):
|
def do_logged(file, work):
|
||||||
try:
|
try:
|
||||||
work()
|
work()
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
write_exception(file, exc)
|
write_exception(file, exc)
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
from traceback import format_tb
|
from traceback import format_tb
|
||||||
|
|
||||||
def write_exception(file, exc):
|
def write_exception(file, exc):
|
||||||
...
|
...
|
||||||
type = exc.__class__
|
type = exc.__class__
|
||||||
message = str(exc)
|
message = str(exc)
|
||||||
lines = format_tb(exc.__traceback__)
|
lines = format_tb(exc.__traceback__)
|
||||||
file.write(... type ... message ... lines ...)
|
file.write(... type ... message ... lines ...)
|
||||||
...
|
...
|
||||||
|
|
||||||
In today's Python, the do_logged() function would have to extract
|
In today's Python, the ``do_logged()`` function would have to extract the
|
||||||
the traceback from sys.exc_traceback or sys.exc_info()[2] and pass
|
traceback from ``sys.exc_traceback`` or ``sys.exc_info()`` [2]_ and pass both
|
||||||
both the value and the traceback to write_exception(). With the
|
the value and the traceback to ``write_exception()``. With the proposed
|
||||||
proposed change, write_exception() simply gets one argument and
|
change, ``write_exception()`` simply gets one argument and obtains the
|
||||||
obtains the exception using the '__traceback__' attribute.
|
exception using the ``__traceback__`` attribute.
|
||||||
|
|
||||||
The proposed semantics are as follows:
|
The proposed semantics are as follows:
|
||||||
|
|
||||||
1. Whenever an exception is caught, if the exception instance does
|
1. Whenever an exception is caught, if the exception instance does not already
|
||||||
not already have a '__traceback__' attribute, the interpreter
|
have a ``__traceback__`` attribute, the interpreter sets it to the newly
|
||||||
sets it to the newly caught traceback.
|
caught traceback.
|
||||||
|
|
||||||
|
|
||||||
Enhanced Reporting
|
Enhanced Reporting
|
||||||
|
==================
|
||||||
|
|
||||||
The default exception handler will be modified to report chained
|
The default exception handler will be modified to report chained exceptions.
|
||||||
exceptions. The chain of exceptions is traversed by following the
|
The chain of exceptions is traversed by following the ``__cause__`` and
|
||||||
'__cause__' and '__context__' attributes, with '__cause__' taking
|
``__context__`` attributes, with ``__cause__`` taking priority. In keeping
|
||||||
priority. In keeping with the chronological order of tracebacks,
|
with the chronological order of tracebacks, the most recently raised exception
|
||||||
the most recently raised exception is displayed last; that is, the
|
is displayed last; that is, the display begins with the description of the
|
||||||
display begins with the description of the innermost exception and
|
innermost exception and backs up the chain to the outermost exception. The
|
||||||
backs up the chain to the outermost exception. The tracebacks are
|
tracebacks are formatted as usual, with one of the lines::
|
||||||
formatted as usual, with one of the lines:
|
|
||||||
|
|
||||||
The above exception was the direct cause of the following exception:
|
The above exception was the direct cause of the following exception:
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
During handling of the above exception, another exception occurred:
|
::
|
||||||
|
|
||||||
between tracebacks, depending whether they are linked by __cause__
|
During handling of the above exception, another exception occurred:
|
||||||
or __context__ respectively. Here is a sketch of the procedure:
|
|
||||||
|
|
||||||
def print_chain(exc):
|
between tracebacks, depending whether they are linked by ``__cause__`` or
|
||||||
if exc.__cause__:
|
``__context__`` respectively. Here is a sketch of the procedure::
|
||||||
print_chain(exc.__cause__)
|
|
||||||
print '\nThe above exception was the direct cause...'
|
|
||||||
elif exc.__context__:
|
|
||||||
print_chain(exc.__context__)
|
|
||||||
print '\nDuring handling of the above exception, ...'
|
|
||||||
print_exc(exc)
|
|
||||||
|
|
||||||
In the 'traceback' module, the format_exception, print_exception,
|
def print_chain(exc):
|
||||||
print_exc, and print_last functions will be updated to accept an
|
if exc.__cause__:
|
||||||
optional 'chain' argument, True by default. When this argument is
|
print_chain(exc.__cause__)
|
||||||
True, these functions will format or display the entire chain of
|
print '\nThe above exception was the direct cause...'
|
||||||
exceptions as just described. When it is False, these functions
|
elif exc.__context__:
|
||||||
will format or display only the outermost exception.
|
print_chain(exc.__context__)
|
||||||
|
print '\nDuring handling of the above exception, ...'
|
||||||
|
print_exc(exc)
|
||||||
|
|
||||||
The 'cgitb' module should also be updated to display the entire
|
In the ``traceback`` module, the ``format_exception``, ``print_exception``,
|
||||||
chain of exceptions.
|
``print_exc``, and ``print_last functions`` will be updated to accept an
|
||||||
|
optional ``chain`` argument, ``True`` by default. When this argument is
|
||||||
|
``True``, these functions will format or display the entire chain of
|
||||||
|
exceptions as just described. When it is ``False``, these functions will
|
||||||
|
format or display only the outermost exception.
|
||||||
|
|
||||||
|
The ``cgitb`` module should also be updated to display the entire chain of
|
||||||
|
exceptions.
|
||||||
|
|
||||||
|
|
||||||
C API
|
C API
|
||||||
|
=====
|
||||||
|
|
||||||
The PyErr_Set* calls for setting exceptions will not set the
|
The ``PyErr_Set*`` calls for setting exceptions will not set the
|
||||||
'__context__' attribute on exceptions. PyErr_NormalizeException
|
``__context__`` attribute on exceptions. ``PyErr_NormalizeException`` will
|
||||||
will always set the 'traceback' attribute to its 'tb' argument and
|
always set the ``traceback`` attribute to its ``tb`` argument and the
|
||||||
the '__context__' and '__cause__' attributes to None.
|
``__context__`` and ``__cause__`` attributes to ``None``.
|
||||||
|
|
||||||
A new API function, PyErr_SetContext(context), will help C
|
A new API function, ``PyErr_SetContext(context)``, will help C programmers
|
||||||
programmers provide chained exception information. This function
|
provide chained exception information. This function will first normalize the
|
||||||
will first normalize the current exception so it is an instance,
|
current exception so it is an instance, then set its ``__context__``
|
||||||
then set its '__context__' attribute. A similar API function,
|
attribute. A similar API function, ``PyErr_SetCause(cause)``, will set the
|
||||||
PyErr_SetCause(cause), will set the '__cause__' attribute.
|
``__cause__`` attribute.
|
||||||
|
|
||||||
|
|
||||||
Compatibility
|
Compatibility
|
||||||
|
=============
|
||||||
|
|
||||||
Chained exceptions expose the type of the most recent exception, so
|
Chained exceptions expose the type of the most recent exception, so they will
|
||||||
they will still match the same 'except' clauses as they do now.
|
still match the same ``except`` clauses as they do now.
|
||||||
|
|
||||||
The proposed changes should not break any code unless it sets or
|
The proposed changes should not break any code unless it sets or uses
|
||||||
uses attributes named '__context__', '__cause__', or '__traceback__'
|
attributes named ``__context__``, ``__cause__``, or ``__traceback__`` on
|
||||||
on exception instances. As of 2005-05-12, the Python standard
|
exception instances. As of 2005-05-12, the Python standard library contains
|
||||||
library contains no mention of such attributes.
|
no mention of such attributes.
|
||||||
|
|
||||||
|
|
||||||
Open Issue: Extra Information
|
Open Issue: Extra Information
|
||||||
|
==============================
|
||||||
|
|
||||||
Walter Dörwald [11] expressed a desire to attach extra information
|
Walter Dörwald [11]_ expressed a desire to attach extra information to an
|
||||||
to an exception during its upward propagation without changing its
|
exception during its upward propagation without changing its type. This could
|
||||||
type. This could be a useful feature, but it is not addressed by
|
be a useful feature, but it is not addressed by this PEP. It could
|
||||||
this PEP. It could conceivably be addressed by a separate PEP
|
conceivably be addressed by a separate PEP establishing conventions for other
|
||||||
establishing conventions for other informational attributes on
|
informational attributes on exceptions.
|
||||||
exceptions.
|
|
||||||
|
|
||||||
|
|
||||||
Open Issue: Suppressing Context
|
Open Issue: Suppressing Context
|
||||||
|
================================
|
||||||
|
|
||||||
As written, this PEP makes it impossible to suppress '__context__',
|
As written, this PEP makes it impossible to suppress ``__context__``, since
|
||||||
since setting exc.__context__ to None in an 'except' or 'finally'
|
setting ``exc.__context__`` to ``None`` in an ``except`` or ``finally`` clause
|
||||||
clause will only result in it being set again when exc is raised.
|
will only result in it being set again when ``exc`` is raised.
|
||||||
|
|
||||||
|
|
||||||
Open Issue: Limiting Exception Types
|
Open Issue: Limiting Exception Types
|
||||||
|
=====================================
|
||||||
|
|
||||||
To improve encapsulation, library implementors may want to wrap all
|
To improve encapsulation, library implementors may want to wrap all
|
||||||
implementation-level exceptions with an application-level exception.
|
implementation-level exceptions with an application-level exception. One could
|
||||||
One could try to wrap exceptions by writing this:
|
try to wrap exceptions by writing this::
|
||||||
|
|
||||||
try:
|
try:
|
||||||
... implementation may raise an exception ...
|
... implementation may raise an exception ...
|
||||||
except:
|
except:
|
||||||
import sys
|
import sys
|
||||||
raise ApplicationError from sys.exc_value
|
raise ApplicationError from sys.exc_value
|
||||||
|
|
||||||
or this:
|
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
|
try:
|
||||||
the current exception in a catch-all 'except' clause, but that isn't
|
... implementation may raise an exception ...
|
||||||
addressed here. Such a feature would allow something like this:
|
except Exception, exc:
|
||||||
|
raise ApplicationError from exc
|
||||||
|
|
||||||
try:
|
but both are somewhat flawed. It would be nice to be able to name the current
|
||||||
... implementation may raise an exception ...
|
exception in a catch-all ``except`` clause, but that isn't addressed here.
|
||||||
except *, exc:
|
Such a feature would allow something like this::
|
||||||
raise ApplicationError from exc
|
|
||||||
|
try:
|
||||||
|
... implementation may raise an exception ...
|
||||||
|
except *, exc:
|
||||||
|
raise ApplicationError from exc
|
||||||
|
|
||||||
|
|
||||||
Open Issue: yield
|
Open Issue: yield
|
||||||
|
==================
|
||||||
|
|
||||||
The exception context is lost when a 'yield' statement is executed;
|
The exception context is lost when a ``yield`` statement is executed; resuming
|
||||||
resuming the frame after the 'yield' does not restore the context.
|
the frame after the ``yield`` does not restore the context. Addressing this
|
||||||
Addressing this problem is out of the scope of this PEP; it is not a
|
problem is out of the scope of this PEP; it is not a new problem, as
|
||||||
new problem, as demonstrated by the following example:
|
demonstrated by the following example::
|
||||||
|
|
||||||
>>> def gen():
|
>>> def gen():
|
||||||
... try:
|
... try:
|
||||||
... 1/0
|
... 1/0
|
||||||
... except:
|
... except:
|
||||||
... yield 3
|
... yield 3
|
||||||
... raise
|
... raise
|
||||||
...
|
...
|
||||||
>>> g = gen()
|
>>> g = gen()
|
||||||
>>> g.next()
|
>>> g.next()
|
||||||
3
|
3
|
||||||
>>> g.next()
|
>>> g.next()
|
||||||
TypeError: exceptions must be classes, instances, or strings
|
TypeError: exceptions must be classes, instances, or strings
|
||||||
(deprecated), not NoneType
|
(deprecated), not NoneType
|
||||||
|
|
||||||
|
|
||||||
Open Issue: Garbage Collection
|
Open Issue: Garbage Collection
|
||||||
|
===============================
|
||||||
|
|
||||||
The strongest objection to this proposal has been that it creates
|
The strongest objection to this proposal has been that it creates cycles
|
||||||
cycles between exceptions and stack frames [12]. Collection of
|
between exceptions and stack frames [12]_. Collection of cyclic garbage (and
|
||||||
cyclic garbage (and therefore resource release) can be greatly
|
therefore resource release) can be greatly delayed::
|
||||||
delayed.
|
|
||||||
|
|
||||||
>>> try:
|
>>> try:
|
||||||
>>> 1/0
|
>>> 1/0
|
||||||
>>> except Exception, err:
|
>>> except Exception, err:
|
||||||
>>> pass
|
>>> pass
|
||||||
|
|
||||||
will introduce a cycle from err -> traceback -> stack frame -> err,
|
will introduce a cycle from err -> traceback -> stack frame -> err, keeping
|
||||||
keeping all locals in the same scope alive until the next GC happens.
|
all locals in the same scope alive until the next GC happens.
|
||||||
|
|
||||||
Today, these locals would go out of scope. There is lots of code
|
Today, these locals would go out of scope. There is lots of code which
|
||||||
which assumes that "local" resources -- particularly open files -- will
|
assumes that "local" resources -- particularly open files -- will be closed
|
||||||
be closed quickly. If closure has to wait for the next GC, a program
|
quickly. If closure has to wait for the next GC, a program (which runs fine
|
||||||
(which runs fine today) may run out of file handles.
|
today) may run out of file handles.
|
||||||
|
|
||||||
Making the __traceback__ attribute a weak reference would avoid the
|
Making the ``__traceback__`` attribute a weak reference would avoid the
|
||||||
problems with cyclic garbage. Unfortunately, it would make saving
|
problems with cyclic garbage. Unfortunately, it would make saving the
|
||||||
the Exception for later (as unittest does) more awkward, and it would
|
``Exception`` for later (as ``unittest`` does) more awkward, and it would not
|
||||||
not allow as much cleanup of the sys module.
|
allow as much cleanup of the ``sys`` module.
|
||||||
|
|
||||||
A possible alternate solution, suggested by Adam Olsen, would be to
|
A possible alternate solution, suggested by Adam Olsen, would be to instead
|
||||||
instead turn the reference from the stack frame to the 'err' variable
|
turn the reference from the stack frame to the ``err`` variable into a weak
|
||||||
into a weak reference when the variable goes out of scope [13].
|
reference when the variable goes out of scope [13]_.
|
||||||
|
|
||||||
|
|
||||||
Possible Future Compatible Changes
|
Possible Future Compatible Changes
|
||||||
|
==================================
|
||||||
|
|
||||||
These changes are consistent with the appearance of exceptions as
|
These changes are consistent with the appearance of exceptions as a single
|
||||||
a single object rather than a triple at the interpreter level.
|
object rather than a triple at the interpreter level.
|
||||||
|
|
||||||
- If PEP 340 or PEP 343 is accepted, replace the three (type, value,
|
- If PEP 340 or PEP 343 is accepted, replace the three (``type``, ``value``,
|
||||||
traceback) arguments to __exit__ with a single exception argument.
|
``traceback``) arguments to ``__exit__`` with a single exception argument.
|
||||||
|
|
||||||
- Deprecate sys.exc_type, sys.exc_value, sys.exc_traceback, and
|
- Deprecate ``sys.exc_type``, ``sys.exc_value``, ``sys.exc_traceback``, and
|
||||||
sys.exc_info() in favour of a single member, sys.exception.
|
``sys.exc_info()`` in favour of a single member, ``sys.exception``.
|
||||||
|
|
||||||
- Deprecate sys.last_type, sys.last_value, and sys.last_traceback
|
- Deprecate ``sys.last_type``, ``sys.last_value``, and ``sys.last_traceback``
|
||||||
in favour of a single member, sys.last_exception.
|
in favour of a single member, ``sys.last_exception``.
|
||||||
|
|
||||||
- Deprecate the three-argument form of the 'raise' statement in
|
- Deprecate the three-argument form of the ``raise`` statement in favour of
|
||||||
favour of the one-argument form.
|
the one-argument form.
|
||||||
|
|
||||||
- Upgrade cgitb.html() to accept a single value as its first
|
- Upgrade ``cgitb.html()`` to accept a single value as its first argument as
|
||||||
argument as an alternative to a (type, value, traceback) tuple.
|
an alternative to a ``(type, value, traceback)`` tuple.
|
||||||
|
|
||||||
|
|
||||||
Possible Future Incompatible Changes
|
Possible Future Incompatible Changes
|
||||||
|
====================================
|
||||||
|
|
||||||
These changes might be worth considering for Python 3000.
|
These changes might be worth considering for Python 3000.
|
||||||
|
|
||||||
- Remove sys.exc_type, sys.exc_value, sys.exc_traceback, and
|
- Remove ``sys.exc_type``, ``sys.exc_value``, ``sys.exc_traceback``, and
|
||||||
sys.exc_info().
|
``sys.exc_info()``.
|
||||||
|
|
||||||
- Remove sys.last_type, sys.last_value, and sys.last_traceback.
|
- Remove ``sys.last_type``, ``sys.last_value``, and ``sys.last_traceback``.
|
||||||
|
|
||||||
- Replace the three-argument sys.excepthook with a one-argument
|
- Replace the three-argument ``sys.excepthook`` with a one-argument API, and
|
||||||
API, and changing the 'cgitb' module to match.
|
changing the ``cgitb`` module to match.
|
||||||
|
|
||||||
- Remove the three-argument form of the 'raise' statement.
|
- Remove the three-argument form of the ``raise`` statement.
|
||||||
|
|
||||||
- Upgrade traceback.print_exception to accept an 'exception'
|
- Upgrade ``traceback.print_exception`` to accept an ``exception`` argument
|
||||||
argument instead of the type, value, and traceback arguments.
|
instead of the ``type``, ``value``, and ``traceback`` arguments.
|
||||||
|
|
||||||
|
|
||||||
Acknowledgements
|
Acknowledgements
|
||||||
|
================
|
||||||
|
|
||||||
Brett Cannon, Greg Ewing, Guido van Rossum, Jeremy Hylton, Phillip
|
Brett Cannon, Greg Ewing, Guido van Rossum, Jeremy Hylton, Phillip J. Eby,
|
||||||
J. Eby, Raymond Hettinger, Walter Dörwald, and others.
|
Raymond Hettinger, Walter Dörwald, and others.
|
||||||
|
|
||||||
|
|
||||||
References
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
[1] Raymond Hettinger, "Idea for avoiding exception masking"
|
.. [1] Raymond Hettinger, "Idea for avoiding exception masking"
|
||||||
http://mail.python.org/pipermail/python-dev/2003-January/032492.html
|
http://mail.python.org/pipermail/python-dev/2003-January/032492.html
|
||||||
|
|
||||||
[2] Brett Cannon explains chained exceptions
|
.. [2] Brett Cannon explains chained exceptions
|
||||||
http://mail.python.org/pipermail/python-dev/2003-June/036063.html
|
http://mail.python.org/pipermail/python-dev/2003-June/036063.html
|
||||||
|
|
||||||
[3] Greg Ewing points out masking caused by exceptions during finally
|
.. [3] Greg Ewing points out masking caused by exceptions during finally
|
||||||
http://mail.python.org/pipermail/python-dev/2003-June/036290.html
|
http://mail.python.org/pipermail/python-dev/2003-June/036290.html
|
||||||
|
|
||||||
[4] Greg Ewing suggests storing the traceback in the exception object
|
.. [4] Greg Ewing suggests storing the traceback in the exception object
|
||||||
http://mail.python.org/pipermail/python-dev/2003-June/036092.html
|
http://mail.python.org/pipermail/python-dev/2003-June/036092.html
|
||||||
|
|
||||||
[5] Guido van Rossum mentions exceptions having a traceback attribute
|
.. [5] Guido van Rossum mentions exceptions having a traceback attribute
|
||||||
http://mail.python.org/pipermail/python-dev/2005-April/053060.html
|
http://mail.python.org/pipermail/python-dev/2005-April/053060.html
|
||||||
|
|
||||||
[6] Ka-Ping Yee, "Tidier Exceptions"
|
.. [6] Ka-Ping Yee, "Tidier Exceptions"
|
||||||
http://mail.python.org/pipermail/python-dev/2005-May/053671.html
|
http://mail.python.org/pipermail/python-dev/2005-May/053671.html
|
||||||
|
|
||||||
[7] Ka-Ping Yee, "Chained Exceptions"
|
.. [7] Ka-Ping Yee, "Chained Exceptions"
|
||||||
http://mail.python.org/pipermail/python-dev/2005-May/053672.html
|
http://mail.python.org/pipermail/python-dev/2005-May/053672.html
|
||||||
|
|
||||||
[8] Guido van Rossum discusses automatic chaining in PyErr_Set*
|
.. [8] Guido van Rossum discusses automatic chaining in ``PyErr_Set*``
|
||||||
http://mail.python.org/pipermail/python-dev/2003-June/036180.html
|
http://mail.python.org/pipermail/python-dev/2003-June/036180.html
|
||||||
|
|
||||||
[9] Tony Olensky, "Omnibus Structured Exception/Error Handling Mechanism"
|
.. [9] Tony Olensky, "Omnibus Structured Exception/Error Handling Mechanism"
|
||||||
http://dev.perl.org/perl6/rfc/88.html
|
http://dev.perl.org/perl6/rfc/88.html
|
||||||
|
|
||||||
[10] 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
|
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemexceptionclassinnerexceptiontopic.asp
|
||||||
|
|
||||||
[11] 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
|
http://mail.python.org/pipermail/python-dev/2003-June/036148.html
|
||||||
|
|
||||||
[12] Guido van Rossum restates the objection to cyclic trash
|
.. [12] Guido van Rossum restates the objection to cyclic trash
|
||||||
http://mail.python.org/pipermail/python-3000/2007-January/005322.html
|
http://mail.python.org/pipermail/python-3000/2007-January/005322.html
|
||||||
|
|
||||||
[13] Adam Olsen suggests using a weakref from stack frame to exception
|
.. [13] Adam Olsen suggests using a weakref from stack frame to exception
|
||||||
http://mail.python.org/pipermail/python-3000/2007-January/005363.html
|
http://mail.python.org/pipermail/python-3000/2007-January/005363.html
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
This document has been placed in the public domain.
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
Local Variables:
|
..
|
||||||
mode: indented-text
|
Local Variables:
|
||||||
indent-tabs-mode: nil
|
mode: indented-text
|
||||||
sentence-end-double-space: t
|
indent-tabs-mode: nil
|
||||||
fill-column: 70
|
sentence-end-double-space: t
|
||||||
coding: utf-8
|
fill-column: 70
|
||||||
End:
|
coding: utf-8
|
||||||
|
End:
|
||||||
|
|
742
pep-3134.txt
742
pep-3134.txt
|
@ -5,550 +5,574 @@ Last-Modified: $Date$
|
||||||
Author: Ka-Ping Yee
|
Author: Ka-Ping Yee
|
||||||
Status: Final
|
Status: Final
|
||||||
Type: Standards Track
|
Type: Standards Track
|
||||||
Content-Type: text/plain
|
Content-Type: text/x-rst
|
||||||
Created: 12-May-2005
|
Created: 12-May-2005
|
||||||
Python-Version: 3.0
|
Python-Version: 3.0
|
||||||
Post-History:
|
Post-History:
|
||||||
|
|
||||||
|
|
||||||
Numbering Note
|
Numbering Note
|
||||||
|
==============
|
||||||
|
|
||||||
This PEP started its life as PEP 344. Since it is now targeted
|
This PEP started its life as PEP 344. Since it is now targeted for Python
|
||||||
for Python 3000, it has been moved into the 3xxx space.
|
3000, it has been moved into the 3xxx space.
|
||||||
|
|
||||||
|
|
||||||
Abstract
|
Abstract
|
||||||
|
========
|
||||||
|
|
||||||
This PEP proposes three standard attributes on exception instances:
|
This PEP proposes three standard attributes on exception instances: the
|
||||||
the '__context__' attribute for implicitly chained exceptions, the
|
``__context__`` attribute for implicitly chained exceptions, the ``__cause__``
|
||||||
'__cause__' attribute for explicitly chained exceptions, and the
|
attribute for explicitly chained exceptions, and the ``__traceback__``
|
||||||
'__traceback__' attribute for the traceback. A new "raise ... from"
|
attribute for the traceback. A new ``raise ... from`` statement sets the
|
||||||
statement sets the '__cause__' attribute.
|
``__cause__`` attribute.
|
||||||
|
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
During the handling of one exception (exception A), it is possible
|
During the handling of one exception (exception A), it is possible that another
|
||||||
that another exception (exception B) may occur. In today's Python
|
exception (exception B) may occur. In today's Python (version 2.4), if this
|
||||||
(version 2.4), if this happens, exception B is propagated outward
|
happens, exception B is propagated outward and exception A is lost. In order
|
||||||
and exception A is lost. In order to debug the problem, it is
|
to debug the problem, it is useful to know about both exceptions. The
|
||||||
useful to know about both exceptions. The '__context__' attribute
|
``__context__`` attribute retains this information automatically.
|
||||||
retains this information automatically.
|
|
||||||
|
|
||||||
Sometimes it can be useful for an exception handler to intentionally
|
Sometimes it can be useful for an exception handler to intentionally re-raise
|
||||||
re-raise an exception, either to provide extra information or to
|
an exception, either to provide extra information or to translate an exception
|
||||||
translate an exception to another type. The '__cause__' attribute
|
to another type. The ``__cause__`` attribute provides an explicit way to
|
||||||
provides an explicit way to record the direct cause of an exception.
|
record the direct cause of an exception.
|
||||||
|
|
||||||
In today's Python implementation, exceptions are composed of three
|
In today's Python implementation, exceptions are composed of three parts: the
|
||||||
parts: the type, the value, and the traceback. The 'sys' module,
|
type, the value, and the traceback. The ``sys`` module, exposes the current
|
||||||
exposes the current exception in three parallel variables, exc_type,
|
exception in three parallel variables, ``exc_type``, ``exc_value``, and
|
||||||
exc_value, and exc_traceback, the sys.exc_info() function returns a
|
``exc_traceback``, the ``sys.exc_info()`` function returns a tuple of these
|
||||||
tuple of these three parts, and the 'raise' statement has a
|
three parts, and the ``raise`` statement has a three-argument form accepting
|
||||||
three-argument form accepting these three parts. Manipulating
|
these three parts. Manipulating exceptions often requires passing these three
|
||||||
exceptions often requires passing these three things in parallel,
|
things in parallel, which can be tedious and error-prone. Additionally, the
|
||||||
which can be tedious and error-prone. Additionally, the 'except'
|
``except`` statement can only provide access to the value, not the traceback.
|
||||||
statement can only provide access to the value, not the traceback.
|
Adding the ``__traceback__`` attribute to exception values makes all the
|
||||||
Adding the '__traceback__' attribute to exception values makes all
|
exception information accessible from a single place.
|
||||||
the exception information accessible from a single place.
|
|
||||||
|
|
||||||
|
|
||||||
History
|
History
|
||||||
|
=======
|
||||||
|
|
||||||
Raymond Hettinger [1] raised the issue of masked exceptions on
|
Raymond Hettinger [1]_ raised the issue of masked exceptions on Python-Dev in
|
||||||
Python-Dev in January 2003 and proposed a PyErr_FormatAppend()
|
January 2003 and proposed a ``PyErr_FormatAppend()`` function that C modules
|
||||||
function that C modules could use to augment the currently active
|
could use to augment the currently active exception with more information.
|
||||||
exception with more information. Brett Cannon [2] brought up
|
Brett Cannon [2]_ brought up chained exceptions again in June 2003, prompting
|
||||||
chained exceptions again in June 2003, prompting a long discussion.
|
a long discussion.
|
||||||
|
|
||||||
Greg Ewing [3] identified the case of an exception occurring in a
|
Greg Ewing [3]_ identified the case of an exception occurring in a ``finally``
|
||||||
'finally' block during unwinding triggered by an original exception,
|
block during unwinding triggered by an original exception, as distinct from
|
||||||
as distinct from the case of an exception occurring in an 'except'
|
the case of an exception occurring in an ``except`` block that is handling the
|
||||||
block that is handling the original exception.
|
original exception.
|
||||||
|
|
||||||
Greg Ewing [4] and Guido van Rossum [5], and probably others, have
|
Greg Ewing [4]_ and Guido van Rossum [5]_, and probably others, have
|
||||||
previously mentioned adding a traceback attribute to Exception
|
previously mentioned adding a traceback attribute to Exception instances.
|
||||||
instances. This is noted in PEP 3000.
|
This is noted in PEP 3000.
|
||||||
|
|
||||||
This PEP was motivated by yet another recent Python-Dev reposting
|
This PEP was motivated by yet another recent Python-Dev reposting of the same
|
||||||
of the same ideas [6] [7].
|
ideas [6]_ [7]_.
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
The Python-Dev discussions revealed interest in exception chaining
|
The Python-Dev discussions revealed interest in exception chaining for two
|
||||||
for two quite different purposes. To handle the unexpected raising
|
quite different purposes. To handle the unexpected raising of a secondary
|
||||||
of a secondary exception, the exception must be retained implicitly.
|
exception, the exception must be retained implicitly. To support intentional
|
||||||
To support intentional translation of an exception, there must be a
|
translation of an exception, there must be a way to chain exceptions
|
||||||
way to chain exceptions explicitly. This PEP addresses both.
|
explicitly. This PEP addresses both.
|
||||||
|
|
||||||
Several attribute names for chained exceptions have been suggested
|
Several attribute names for chained exceptions have been suggested on
|
||||||
on Python-Dev [2], including 'cause', 'antecedent', 'reason',
|
Python-Dev [2]_, including ``cause``, ``antecedent``, ``reason``, ``original``,
|
||||||
'original', 'chain', 'chainedexc', 'exc_chain', 'excprev',
|
``chain``, ``chainedexc``, ``exc_chain``, ``excprev``, ``previous``, and
|
||||||
'previous', and 'precursor'. For an explicitly chained exception,
|
``precursor``. For an explicitly chained exception, this PEP suggests
|
||||||
this PEP suggests '__cause__' because of its specific meaning. For
|
``__cause__`` because of its specific meaning. For an implicitly chained
|
||||||
an implicitly chained exception, this PEP proposes the name
|
exception, this PEP proposes the name ``__context__`` because the intended
|
||||||
'__context__' because the intended meaning is more specific than
|
meaning is more specific than temporal precedence but less specific than
|
||||||
temporal precedence but less specific than causation: an exception
|
causation: an exception occurs in the context of handling another exception.
|
||||||
occurs in the context of handling another exception.
|
|
||||||
|
|
||||||
This PEP suggests names with leading and trailing double-underscores
|
This PEP suggests names with leading and trailing double-underscores for these
|
||||||
for these three attributes because they are set by the Python VM.
|
three attributes because they are set by the Python VM. Only in very special
|
||||||
Only in very special cases should they be set by normal assignment.
|
cases should they be set by normal assignment.
|
||||||
|
|
||||||
This PEP handles exceptions that occur during 'except' blocks and
|
This PEP handles exceptions that occur during ``except`` blocks and ``finally``
|
||||||
'finally' blocks in the same way. Reading the traceback makes it
|
blocks in the same way. Reading the traceback makes it clear where the
|
||||||
clear where the exceptions occurred, so additional mechanisms for
|
exceptions occurred, so additional mechanisms for distinguishing the two cases
|
||||||
distinguishing the two cases would only add unnecessary complexity.
|
would only add unnecessary complexity.
|
||||||
|
|
||||||
This PEP proposes that the outermost exception object (the one
|
This PEP proposes that the outermost exception object (the one exposed for
|
||||||
exposed for matching by 'except' clauses) be the most recently
|
matching by ``except`` clauses) be the most recently raised exception for
|
||||||
raised exception for compatibility with current behaviour.
|
compatibility with current behaviour.
|
||||||
|
|
||||||
This PEP proposes that tracebacks display the outermost exception
|
This PEP proposes that tracebacks display the outermost exception last, because
|
||||||
last, because this would be consistent with the chronological order
|
this would be consistent with the chronological order of tracebacks (from
|
||||||
of tracebacks (from oldest to most recent frame) and because the
|
oldest to most recent frame) and because the actual thrown exception is easier
|
||||||
actual thrown exception is easier to find on the last line.
|
to find on the last line.
|
||||||
|
|
||||||
To keep things simpler, the C API calls for setting an exception
|
To keep things simpler, the C API calls for setting an exception will not
|
||||||
will not automatically set the exception's '__context__'. Guido
|
automatically set the exception's ``__context__``. Guido van Rossum has
|
||||||
van Rossum has expressed concerns with making such changes [8].
|
expressed concerns with making such changes [8]_.
|
||||||
|
|
||||||
As for other languages, Java and Ruby both discard the original
|
As for other languages, Java and Ruby both discard the original exception when
|
||||||
exception when another exception occurs in a 'catch'/'rescue' or
|
another exception occurs in a ``catch``/``rescue`` or ``finally``/``ensure``
|
||||||
'finally'/'ensure' clause. Perl 5 lacks built-in structured
|
clause. Perl 5 lacks built-in structured exception handling. For Perl 6, RFC
|
||||||
exception handling. For Perl 6, RFC number 88 [9] proposes an exception
|
number 88 [9]_ proposes an exception mechanism that implicitly retains chained
|
||||||
mechanism that implicitly retains chained exceptions in an array
|
exceptions in an array named ``@@``. In that RFC, the most recently raised
|
||||||
named @@. In that RFC, the most recently raised exception is
|
exception is exposed for matching, as in this PEP; also, arbitrary expressions
|
||||||
exposed for matching, as in this PEP; also, arbitrary expressions
|
(possibly involving ``@@``) can be evaluated for exception matching.
|
||||||
(possibly involving @@) can be evaluated for exception matching.
|
|
||||||
|
|
||||||
Exceptions in C# contain a read-only 'InnerException' property that
|
Exceptions in C# contain a read-only ``InnerException`` property that may point
|
||||||
may point to another exception. Its documentation [10] says that
|
to another exception. Its documentation [10]_ says that "When an exception X
|
||||||
"When an exception X is thrown as a direct result of a previous
|
is thrown as a direct result of a previous exception Y, the ``InnerException``
|
||||||
exception Y, the InnerException property of X should contain a
|
property of X should contain a reference to Y." This property is not set by
|
||||||
reference to Y." This property is not set by the VM automatically;
|
the VM automatically; rather, all exception constructors take an optional
|
||||||
rather, all exception constructors take an optional 'innerException'
|
``innerException`` argument to set it explicitly. The ``__cause__`` attribute
|
||||||
argument to set it explicitly. The '__cause__' attribute fulfills
|
fulfills the same purpose as ``InnerException``, but this PEP proposes a new
|
||||||
the same purpose as InnerException, but this PEP proposes a new form
|
form of ``raise`` rather than extending the constructors of all exceptions. C#
|
||||||
of 'raise' rather than extending the constructors of all exceptions.
|
also provides a ``GetBaseException`` method that jumps directly to the end of
|
||||||
C# also provides a GetBaseException method that jumps directly to
|
the ``InnerException`` chain; this PEP proposes no analog.
|
||||||
the end of the InnerException chain; this PEP proposes no analog.
|
|
||||||
|
|
||||||
The reason all three of these attributes are presented together in
|
The reason all three of these attributes are presented together in one proposal
|
||||||
one proposal is that the '__traceback__' attribute provides
|
is that the ``__traceback__`` attribute provides convenient access to the
|
||||||
convenient access to the traceback on chained exceptions.
|
traceback on chained exceptions.
|
||||||
|
|
||||||
|
|
||||||
Implicit Exception Chaining
|
Implicit Exception Chaining
|
||||||
|
===========================
|
||||||
|
|
||||||
Here is an example to illustrate the '__context__' attribute.
|
Here is an example to illustrate the ``__context__`` attribute::
|
||||||
|
|
||||||
def compute(a, b):
|
def compute(a, b):
|
||||||
try:
|
try:
|
||||||
a/b
|
a/b
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
log(exc)
|
log(exc)
|
||||||
|
|
||||||
def log(exc):
|
def log(exc):
|
||||||
file = open('logfile.txt') # oops, forgot the 'w'
|
file = open('logfile.txt') # oops, forgot the 'w'
|
||||||
print >>file, exc
|
print >>file, exc
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
Calling compute(0, 0) causes a ZeroDivisionError. The compute()
|
Calling ``compute(0, 0)`` causes a ``ZeroDivisionError``. The ``compute()``
|
||||||
function catches this exception and calls log(exc), but the log()
|
function catches this exception and calls ``log(exc)``, but the ``log()``
|
||||||
function also raises an exception when it tries to write to a
|
function also raises an exception when it tries to write to a file that wasn't
|
||||||
file that wasn't opened for writing.
|
opened for writing.
|
||||||
|
|
||||||
In today's Python, the caller of compute() gets thrown an IOError.
|
In today's Python, the caller of ``compute()`` gets thrown an ``IOError``. The
|
||||||
The ZeroDivisionError is lost. With the proposed change, the
|
``ZeroDivisionError`` is lost. With the proposed change, the instance of
|
||||||
instance of IOError has an additional '__context__' attribute that
|
``IOError`` has an additional ``__context__`` attribute that retains the
|
||||||
retains the ZeroDivisionError.
|
``ZeroDivisionError``.
|
||||||
|
|
||||||
The following more elaborate example demonstrates the handling of a
|
The following more elaborate example demonstrates the handling of a mixture of
|
||||||
mixture of 'finally' and 'except' clauses:
|
``finally`` and ``except`` clauses::
|
||||||
|
|
||||||
def main(filename):
|
def main(filename):
|
||||||
file = open(filename) # oops, forgot the 'w'
|
file = open(filename) # oops, forgot the 'w'
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
compute()
|
compute()
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
log(file, exc)
|
log(file, exc)
|
||||||
finally:
|
finally:
|
||||||
file.clos() # oops, misspelled 'close'
|
file.clos() # oops, misspelled 'close'
|
||||||
|
|
||||||
def compute():
|
def compute():
|
||||||
1/0
|
1/0
|
||||||
|
|
||||||
def log(file, exc):
|
def log(file, exc):
|
||||||
try:
|
try:
|
||||||
print >>file, exc # oops, file is not writable
|
print >>file, exc # oops, file is not writable
|
||||||
except:
|
except:
|
||||||
display(exc)
|
display(exc)
|
||||||
|
|
||||||
def display(exc):
|
def display(exc):
|
||||||
print ex # oops, misspelled 'exc'
|
print ex # oops, misspelled 'exc'
|
||||||
|
|
||||||
Calling main() with the name of an existing file will trigger four
|
Calling ``main()`` with the name of an existing file will trigger four
|
||||||
exceptions. The ultimate result will be an AttributeError due to
|
exceptions. The ultimate result will be an ``AttributeError`` due to the
|
||||||
the misspelling of 'clos', whose __context__ points to a NameError
|
misspelling of ``clos``, whose ``__context__`` points to a ``NameError`` due
|
||||||
due to the misspelling of 'ex', whose __context__ points to an
|
to the misspelling of ``ex``, whose ``__context__`` points to an ``IOError``
|
||||||
IOError due to the file being read-only, whose __context__ points to
|
due to the file being read-only, whose ``__context__`` points to a
|
||||||
a ZeroDivisionError, whose __context__ attribute is None.
|
``ZeroDivisionError``, whose ``__context__`` attribute is ``None``.
|
||||||
|
|
||||||
The proposed semantics are as follows:
|
The proposed semantics are as follows:
|
||||||
|
|
||||||
1. Each thread has an exception context initially set to None.
|
1. Each thread has an exception context initially set to ``None``.
|
||||||
|
|
||||||
2. Whenever an exception is raised, if the exception instance does
|
2. Whenever an exception is raised, if the exception instance does not already
|
||||||
not already have a '__context__' attribute, the interpreter sets
|
have a ``__context__`` attribute, the interpreter sets it equal to the
|
||||||
it equal to the thread's exception context.
|
thread's exception context.
|
||||||
|
|
||||||
3. Immediately after an exception is raised, the thread's exception
|
3. Immediately after an exception is raised, the thread's exception context is
|
||||||
context is set to the exception.
|
set to the exception.
|
||||||
|
|
||||||
4. Whenever the interpreter exits an 'except' block by reaching the
|
4. Whenever the interpreter exits an ``except`` block by reaching the end or
|
||||||
end or executing a 'return', 'yield', 'continue', or 'break'
|
executing a ``return``, ``yield``, ``continue``, or ``break`` statement, the
|
||||||
statement, the thread's exception context is set to None.
|
thread's exception context is set to ``None``.
|
||||||
|
|
||||||
|
|
||||||
Explicit Exception Chaining
|
Explicit Exception Chaining
|
||||||
|
===========================
|
||||||
|
|
||||||
The '__cause__' attribute on exception objects is always initialized
|
The ``__cause__`` attribute on exception objects is always initialized to
|
||||||
to None. It is set by a new form of the 'raise' statement:
|
``None``. It is set by a new form of the ``raise`` statement::
|
||||||
|
|
||||||
raise EXCEPTION from CAUSE
|
raise EXCEPTION from CAUSE
|
||||||
|
|
||||||
which is equivalent to:
|
which is equivalent to::
|
||||||
|
|
||||||
exc = EXCEPTION
|
exc = EXCEPTION
|
||||||
exc.__cause__ = CAUSE
|
exc.__cause__ = CAUSE
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
In the following example, a database provides implementations for a
|
In the following example, a database provides implementations for a few
|
||||||
few different kinds of storage, with file storage as one kind. The
|
different kinds of storage, with file storage as one kind. The database
|
||||||
database designer wants errors to propagate as DatabaseError objects
|
designer wants errors to propagate as ``DatabaseError`` objects so that the
|
||||||
so that the client doesn't have to be aware of the storage-specific
|
client doesn't have to be aware of the storage-specific details, but doesn't
|
||||||
details, but doesn't want to lose the underlying error information.
|
want to lose the underlying error information.
|
||||||
|
|
||||||
class DatabaseError(Exception):
|
::
|
||||||
pass
|
|
||||||
|
|
||||||
class FileDatabase(Database):
|
class DatabaseError(Exception):
|
||||||
def __init__(self, filename):
|
pass
|
||||||
try:
|
|
||||||
self.file = open(filename)
|
|
||||||
except IOError, exc:
|
|
||||||
raise DatabaseError('failed to open') from exc
|
|
||||||
|
|
||||||
If the call to open() raises an exception, the problem will be
|
class FileDatabase(Database):
|
||||||
reported as a DatabaseError, with a __cause__ attribute that reveals
|
def __init__(self, filename):
|
||||||
the IOError as the original cause.
|
try:
|
||||||
|
self.file = open(filename)
|
||||||
|
except IOError, 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
|
Traceback Attribute
|
||||||
|
===================
|
||||||
|
|
||||||
The following example illustrates the '__traceback__' attribute.
|
The following example illustrates the ``__traceback__`` attribute.
|
||||||
|
|
||||||
def do_logged(file, work):
|
::
|
||||||
try:
|
|
||||||
work()
|
|
||||||
except Exception, exc:
|
|
||||||
write_exception(file, exc)
|
|
||||||
raise exc
|
|
||||||
|
|
||||||
from traceback import format_tb
|
def do_logged(file, work):
|
||||||
|
try:
|
||||||
|
work()
|
||||||
|
except Exception, exc:
|
||||||
|
write_exception(file, exc)
|
||||||
|
raise exc
|
||||||
|
|
||||||
def write_exception(file, exc):
|
from traceback import format_tb
|
||||||
...
|
|
||||||
type = exc.__class__
|
|
||||||
message = str(exc)
|
|
||||||
lines = format_tb(exc.__traceback__)
|
|
||||||
file.write(... type ... message ... lines ...)
|
|
||||||
...
|
|
||||||
|
|
||||||
In today's Python, the do_logged() function would have to extract
|
def write_exception(file, exc):
|
||||||
the traceback from sys.exc_traceback or sys.exc_info()[2] and pass
|
...
|
||||||
both the value and the traceback to write_exception(). With the
|
type = exc.__class__
|
||||||
proposed change, write_exception() simply gets one argument and
|
message = str(exc)
|
||||||
obtains the exception using the '__traceback__' attribute.
|
lines = format_tb(exc.__traceback__)
|
||||||
|
file.write(... type ... message ... lines ...)
|
||||||
|
...
|
||||||
|
|
||||||
The proposed semantics are as follows:
|
In today's Python, the ``do_logged()`` function would have to extract the
|
||||||
|
traceback from ``sys.exc_traceback`` or ``sys.exc_info()`` [2]_ and pass both
|
||||||
|
the value and the traceback to ``write_exception()``. With the proposed
|
||||||
|
change, ``write_exception()`` simply gets one argument and obtains the
|
||||||
|
exception using the ``__traceback__`` attribute.
|
||||||
|
|
||||||
1. Whenever an exception is caught, if the exception instance does
|
The proposed semantics are as follows:
|
||||||
not already have a '__traceback__' attribute, the interpreter
|
|
||||||
sets it to the newly caught traceback.
|
1. Whenever an exception is caught, if the exception instance does not already
|
||||||
|
have a ``__traceback__`` attribute, the interpreter sets it to the newly
|
||||||
|
caught traceback.
|
||||||
|
|
||||||
|
|
||||||
Enhanced Reporting
|
Enhanced Reporting
|
||||||
|
==================
|
||||||
|
|
||||||
The default exception handler will be modified to report chained
|
The default exception handler will be modified to report chained exceptions.
|
||||||
exceptions. The chain of exceptions is traversed by following the
|
The chain of exceptions is traversed by following the ``__cause__`` and
|
||||||
'__cause__' and '__context__' attributes, with '__cause__' taking
|
``__context__`` attributes, with ``__cause__`` taking priority. In keeping
|
||||||
priority. In keeping with the chronological order of tracebacks,
|
with the chronological order of tracebacks, the most recently raised exception
|
||||||
the most recently raised exception is displayed last; that is, the
|
is displayed last; that is, the display begins with the description of the
|
||||||
display begins with the description of the innermost exception and
|
innermost exception and backs up the chain to the outermost exception. The
|
||||||
backs up the chain to the outermost exception. The tracebacks are
|
tracebacks are formatted as usual, with one of the lines::
|
||||||
formatted as usual, with one of the lines:
|
|
||||||
|
|
||||||
The above exception was the direct cause of the following exception:
|
The above exception was the direct cause of the following exception:
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
During handling of the above exception, another exception occurred:
|
::
|
||||||
|
|
||||||
between tracebacks, depending whether they are linked by __cause__
|
During handling of the above exception, another exception occurred:
|
||||||
or __context__ respectively. Here is a sketch of the procedure:
|
|
||||||
|
|
||||||
def print_chain(exc):
|
between tracebacks, depending whether they are linked by ``__cause__`` or
|
||||||
if exc.__cause__:
|
``__context__`` respectively. Here is a sketch of the procedure::
|
||||||
print_chain(exc.__cause__)
|
|
||||||
print '\nThe above exception was the direct cause...'
|
|
||||||
elif exc.__context__:
|
|
||||||
print_chain(exc.__context__)
|
|
||||||
print '\nDuring handling of the above exception, ...'
|
|
||||||
print_exc(exc)
|
|
||||||
|
|
||||||
In the 'traceback' module, the format_exception, print_exception,
|
def print_chain(exc):
|
||||||
print_exc, and print_last functions will be updated to accept an
|
if exc.__cause__:
|
||||||
optional 'chain' argument, True by default. When this argument is
|
print_chain(exc.__cause__)
|
||||||
True, these functions will format or display the entire chain of
|
print '\nThe above exception was the direct cause...'
|
||||||
exceptions as just described. When it is False, these functions
|
elif exc.__context__:
|
||||||
will format or display only the outermost exception.
|
print_chain(exc.__context__)
|
||||||
|
print '\nDuring handling of the above exception, ...'
|
||||||
|
print_exc(exc)
|
||||||
|
|
||||||
The 'cgitb' module should also be updated to display the entire
|
In the ``traceback`` module, the ``format_exception``, ``print_exception``,
|
||||||
chain of exceptions.
|
``print_exc``, and ``print_last`` functions will be updated to accept an
|
||||||
|
optional ``chain`` argument, ``True`` by default. When this argument is
|
||||||
|
``True``, these functions will format or display the entire chain of exceptions
|
||||||
|
as just described. When it is ``False``, these functions will format or
|
||||||
|
display only the outermost exception.
|
||||||
|
|
||||||
|
The ``cgitb`` module should also be updated to display the entire chain of
|
||||||
|
exceptions.
|
||||||
|
|
||||||
|
|
||||||
C API
|
C API
|
||||||
|
=====
|
||||||
|
|
||||||
The PyErr_Set* calls for setting exceptions will not set the
|
The ``PyErr_Set*`` calls for setting exceptions will not set the
|
||||||
'__context__' attribute on exceptions. PyErr_NormalizeException
|
``__context__`` attribute on exceptions. ``PyErr_NormalizeException`` will
|
||||||
will always set the 'traceback' attribute to its 'tb' argument and
|
always set the ``traceback`` attribute to its ``tb`` argument and the
|
||||||
the '__context__' and '__cause__' attributes to None.
|
``__context__`` and ``__cause__`` attributes to ``None``.
|
||||||
|
|
||||||
A new API function, PyErr_SetContext(context), will help C
|
A new API function, ``PyErr_SetContext(context)``, will help C programmers
|
||||||
programmers provide chained exception information. This function
|
provide chained exception information. This function will first normalize the
|
||||||
will first normalize the current exception so it is an instance,
|
current exception so it is an instance, then set its ``__context__`` attribute.
|
||||||
then set its '__context__' attribute. A similar API function,
|
A similar API function, ``PyErr_SetCause(cause)``, will set the ``__cause__``
|
||||||
PyErr_SetCause(cause), will set the '__cause__' attribute.
|
attribute.
|
||||||
|
|
||||||
|
|
||||||
Compatibility
|
Compatibility
|
||||||
|
=============
|
||||||
|
|
||||||
Chained exceptions expose the type of the most recent exception, so
|
Chained exceptions expose the type of the most recent exception, so they will
|
||||||
they will still match the same 'except' clauses as they do now.
|
still match the same ``except`` clauses as they do now.
|
||||||
|
|
||||||
The proposed changes should not break any code unless it sets or
|
The proposed changes should not break any code unless it sets or uses
|
||||||
uses attributes named '__context__', '__cause__', or '__traceback__'
|
attributes named ``__context__``, ``__cause__``, or ``__traceback__`` on
|
||||||
on exception instances. As of 2005-05-12, the Python standard
|
exception instances. As of 2005-05-12, the Python standard library contains no
|
||||||
library contains no mention of such attributes.
|
mention of such attributes.
|
||||||
|
|
||||||
|
|
||||||
Open Issue: Extra Information
|
Open Issue: Extra Information
|
||||||
|
==============================
|
||||||
|
|
||||||
Walter Dörwald [11] expressed a desire to attach extra information
|
Walter Dörwald [11]_ expressed a desire to attach extra information to an
|
||||||
to an exception during its upward propagation without changing its
|
exception during its upward propagation without changing its type. This could
|
||||||
type. This could be a useful feature, but it is not addressed by
|
be a useful feature, but it is not addressed by this PEP. It could conceivably
|
||||||
this PEP. It could conceivably be addressed by a separate PEP
|
be addressed by a separate PEP establishing conventions for other informational
|
||||||
establishing conventions for other informational attributes on
|
attributes on exceptions.
|
||||||
exceptions.
|
|
||||||
|
|
||||||
|
|
||||||
Open Issue: Suppressing Context
|
Open Issue: Suppressing Context
|
||||||
|
================================
|
||||||
|
|
||||||
As written, this PEP makes it impossible to suppress '__context__',
|
As written, this PEP makes it impossible to suppress ``__context__``, since
|
||||||
since setting exc.__context__ to None in an 'except' or 'finally'
|
setting ``exc.__context__`` to ``None`` in an ``except`` or ``finally`` clause
|
||||||
clause will only result in it being set again when exc is raised.
|
will only result in it being set again when ``exc`` is raised.
|
||||||
|
|
||||||
|
|
||||||
Open Issue: Limiting Exception Types
|
Open Issue: Limiting Exception Types
|
||||||
|
=====================================
|
||||||
|
|
||||||
To improve encapsulation, library implementors may want to wrap all
|
To improve encapsulation, library implementors may want to wrap all
|
||||||
implementation-level exceptions with an application-level exception.
|
implementation-level exceptions with an application-level exception. One could
|
||||||
One could try to wrap exceptions by writing this:
|
try to wrap exceptions by writing this::
|
||||||
|
|
||||||
try:
|
try:
|
||||||
... implementation may raise an exception ...
|
... implementation may raise an exception ...
|
||||||
except:
|
except:
|
||||||
import sys
|
import sys
|
||||||
raise ApplicationError from sys.exc_value
|
raise ApplicationError from sys.exc_value
|
||||||
|
|
||||||
or this:
|
or this::
|
||||||
|
|
||||||
try:
|
try:
|
||||||
... implementation may raise an exception ...
|
... implementation may raise an exception ...
|
||||||
except Exception, exc:
|
except Exception, exc:
|
||||||
raise ApplicationError from exc
|
raise ApplicationError from exc
|
||||||
|
|
||||||
but both are somewhat flawed. It would be nice to be able to name
|
but both are somewhat flawed. It would be nice to be able to name the current
|
||||||
the current exception in a catch-all 'except' clause, but that isn't
|
exception in a catch-all ``except`` clause, but that isn't addressed here.
|
||||||
addressed here. Such a feature would allow something like this:
|
Such a feature would allow something like this::
|
||||||
|
|
||||||
try:
|
try:
|
||||||
... implementation may raise an exception ...
|
... implementation may raise an exception ...
|
||||||
except *, exc:
|
except *, exc:
|
||||||
raise ApplicationError from exc
|
raise ApplicationError from exc
|
||||||
|
|
||||||
|
|
||||||
Open Issue: yield
|
Open Issue: yield
|
||||||
|
==================
|
||||||
|
|
||||||
The exception context is lost when a 'yield' statement is executed;
|
The exception context is lost when a ``yield`` statement is executed; resuming
|
||||||
resuming the frame after the 'yield' does not restore the context.
|
the frame after the ``yield`` does not restore the context. Addressing this
|
||||||
Addressing this problem is out of the scope of this PEP; it is not a
|
problem is out of the scope of this PEP; it is not a new problem, as
|
||||||
new problem, as demonstrated by the following example:
|
demonstrated by the following example::
|
||||||
|
|
||||||
>>> def gen():
|
>>> def gen():
|
||||||
... try:
|
... try:
|
||||||
... 1/0
|
... 1/0
|
||||||
... except:
|
... except:
|
||||||
... yield 3
|
... yield 3
|
||||||
... raise
|
... raise
|
||||||
...
|
...
|
||||||
>>> g = gen()
|
>>> g = gen()
|
||||||
>>> g.next()
|
>>> g.next()
|
||||||
3
|
3
|
||||||
>>> g.next()
|
>>> g.next()
|
||||||
TypeError: exceptions must be classes, instances, or strings
|
TypeError: exceptions must be classes, instances, or strings
|
||||||
(deprecated), not NoneType
|
(deprecated), not NoneType
|
||||||
|
|
||||||
|
|
||||||
Open Issue: Garbage Collection
|
Open Issue: Garbage Collection
|
||||||
|
===============================
|
||||||
|
|
||||||
The strongest objection to this proposal has been that it creates
|
The strongest objection to this proposal has been that it creates cycles
|
||||||
cycles between exceptions and stack frames [12]. Collection of
|
between exceptions and stack frames [12]_. Collection of cyclic garbage (and
|
||||||
cyclic garbage (and therefore resource release) can be greatly
|
therefore resource release) can be greatly delayed.
|
||||||
delayed.
|
|
||||||
|
|
||||||
>>> try:
|
::
|
||||||
>>> 1/0
|
|
||||||
>>> except Exception, err:
|
|
||||||
>>> pass
|
|
||||||
|
|
||||||
will introduce a cycle from err -> traceback -> stack frame -> err,
|
>>> try:
|
||||||
keeping all locals in the same scope alive until the next GC happens.
|
>>> 1/0
|
||||||
|
>>> except Exception, err:
|
||||||
|
>>> pass
|
||||||
|
|
||||||
Today, these locals would go out of scope. There is lots of code
|
will introduce a cycle from err -> traceback -> stack frame -> err, keeping all
|
||||||
which assumes that "local" resources -- particularly open files -- will
|
locals in the same scope alive until the next GC happens.
|
||||||
be closed quickly. If closure has to wait for the next GC, a program
|
|
||||||
(which runs fine today) may run out of file handles.
|
|
||||||
|
|
||||||
Making the __traceback__ attribute a weak reference would avoid the
|
Today, these locals would go out of scope. There is lots of code which assumes
|
||||||
problems with cyclic garbage. Unfortunately, it would make saving
|
that "local" resources -- particularly open files -- will be closed quickly.
|
||||||
the Exception for later (as unittest does) more awkward, and it would
|
If closure has to wait for the next GC, a program (which runs fine today) may
|
||||||
not allow as much cleanup of the sys module.
|
run out of file handles.
|
||||||
|
|
||||||
A possible alternate solution, suggested by Adam Olsen, would be to
|
Making the ``__traceback__`` attribute a weak reference would avoid the
|
||||||
instead turn the reference from the stack frame to the 'err' variable
|
problems with cyclic garbage. Unfortunately, it would make saving the
|
||||||
into a weak reference when the variable goes out of scope [13].
|
``Exception`` for later (as ``unittest`` does) more awkward, and it would not
|
||||||
|
allow as much cleanup of the ``sys`` module.
|
||||||
|
|
||||||
|
A possible alternate solution, suggested by Adam Olsen, would be to instead
|
||||||
|
turn the reference from the stack frame to the ``err`` variable into a weak
|
||||||
|
reference when the variable goes out of scope [13]_.
|
||||||
|
|
||||||
|
|
||||||
Possible Future Compatible Changes
|
Possible Future Compatible Changes
|
||||||
|
==================================
|
||||||
|
|
||||||
These changes are consistent with the appearance of exceptions as
|
These changes are consistent with the appearance of exceptions as a single
|
||||||
a single object rather than a triple at the interpreter level.
|
object rather than a triple at the interpreter level.
|
||||||
|
|
||||||
- If PEP 340 or PEP 343 is accepted, replace the three (type, value,
|
- If PEP 340 or PEP 343 is accepted, replace the three (``type``, ``value``,
|
||||||
traceback) arguments to __exit__ with a single exception argument.
|
``traceback``) arguments to ``__exit__`` with a single exception argument.
|
||||||
|
|
||||||
- Deprecate sys.exc_type, sys.exc_value, sys.exc_traceback, and
|
- Deprecate ``sys.exc_type``, ``sys.exc_value``, ``sys.exc_traceback``, and
|
||||||
sys.exc_info() in favour of a single member, sys.exception.
|
``sys.exc_info()`` in favour of a single member, ``sys.exception``.
|
||||||
|
|
||||||
- Deprecate sys.last_type, sys.last_value, and sys.last_traceback
|
- Deprecate ``sys.last_type``, ``sys.last_value``, and ``sys.last_traceback``
|
||||||
in favour of a single member, sys.last_exception.
|
in favour of a single member, ``sys.last_exception``.
|
||||||
|
|
||||||
- Deprecate the three-argument form of the 'raise' statement in
|
- Deprecate the three-argument form of the ``raise`` statement in favour of the
|
||||||
favour of the one-argument form.
|
one-argument form.
|
||||||
|
|
||||||
- Upgrade cgitb.html() to accept a single value as its first
|
- Upgrade ``cgitb.html()`` to accept a single value as its first argument as an
|
||||||
argument as an alternative to a (type, value, traceback) tuple.
|
alternative to a ``(type, value, traceback)`` tuple.
|
||||||
|
|
||||||
|
|
||||||
Possible Future Incompatible Changes
|
Possible Future Incompatible Changes
|
||||||
|
====================================
|
||||||
|
|
||||||
These changes might be worth considering for Python 3000.
|
These changes might be worth considering for Python 3000.
|
||||||
|
|
||||||
- Remove sys.exc_type, sys.exc_value, sys.exc_traceback, and
|
- Remove ``sys.exc_type``, ``sys.exc_value``, ``sys.exc_traceback``, and
|
||||||
sys.exc_info().
|
``sys.exc_info()``.
|
||||||
|
|
||||||
- Remove sys.last_type, sys.last_value, and sys.last_traceback.
|
- Remove ``sys.last_type``, ``sys.last_value``, and ``sys.last_traceback``.
|
||||||
|
|
||||||
- Replace the three-argument sys.excepthook with a one-argument
|
- Replace the three-argument ``sys.excepthook`` with a one-argument API, and
|
||||||
API, and changing the 'cgitb' module to match.
|
changing the ``cgitb`` module to match.
|
||||||
|
|
||||||
- Remove the three-argument form of the 'raise' statement.
|
- Remove the three-argument form of the ``raise`` statement.
|
||||||
|
|
||||||
- Upgrade traceback.print_exception to accept an 'exception'
|
- Upgrade ``traceback.print_exception`` to accept an ``exception`` argument
|
||||||
argument instead of the type, value, and traceback arguments.
|
instead of the ``type``, ``value``, and ``traceback`` arguments.
|
||||||
|
|
||||||
|
|
||||||
Implementation
|
Implementation
|
||||||
|
==============
|
||||||
|
|
||||||
The __traceback__ and __cause__ attributes and the new raise syntax were
|
The ``__traceback__`` and ``__cause__`` attributes and the new raise syntax
|
||||||
implemented in revision 57783 [14].
|
were implemented in revision 57783 [14]_.
|
||||||
|
|
||||||
|
|
||||||
Acknowledgements
|
Acknowledgements
|
||||||
|
================
|
||||||
|
|
||||||
Brett Cannon, Greg Ewing, Guido van Rossum, Jeremy Hylton, Phillip
|
Brett Cannon, Greg Ewing, Guido van Rossum, Jeremy Hylton, Phillip J. Eby,
|
||||||
J. Eby, Raymond Hettinger, Walter Dörwald, and others.
|
Raymond Hettinger, Walter Dörwald, and others.
|
||||||
|
|
||||||
|
|
||||||
References
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
[1] Raymond Hettinger, "Idea for avoiding exception masking"
|
.. [1] Raymond Hettinger, "Idea for avoiding exception masking"
|
||||||
http://mail.python.org/pipermail/python-dev/2003-January/032492.html
|
http://mail.python.org/pipermail/python-dev/2003-January/032492.html
|
||||||
|
|
||||||
[2] Brett Cannon explains chained exceptions
|
.. [2] Brett Cannon explains chained exceptions
|
||||||
http://mail.python.org/pipermail/python-dev/2003-June/036063.html
|
http://mail.python.org/pipermail/python-dev/2003-June/036063.html
|
||||||
|
|
||||||
[3] Greg Ewing points out masking caused by exceptions during finally
|
.. [3] Greg Ewing points out masking caused by exceptions during finally
|
||||||
http://mail.python.org/pipermail/python-dev/2003-June/036290.html
|
http://mail.python.org/pipermail/python-dev/2003-June/036290.html
|
||||||
|
|
||||||
[4] Greg Ewing suggests storing the traceback in the exception object
|
.. [4] Greg Ewing suggests storing the traceback in the exception object
|
||||||
http://mail.python.org/pipermail/python-dev/2003-June/036092.html
|
http://mail.python.org/pipermail/python-dev/2003-June/036092.html
|
||||||
|
|
||||||
[5] Guido van Rossum mentions exceptions having a traceback attribute
|
.. [5] Guido van Rossum mentions exceptions having a traceback attribute
|
||||||
http://mail.python.org/pipermail/python-dev/2005-April/053060.html
|
http://mail.python.org/pipermail/python-dev/2005-April/053060.html
|
||||||
|
|
||||||
[6] Ka-Ping Yee, "Tidier Exceptions"
|
.. [6] Ka-Ping Yee, "Tidier Exceptions"
|
||||||
http://mail.python.org/pipermail/python-dev/2005-May/053671.html
|
http://mail.python.org/pipermail/python-dev/2005-May/053671.html
|
||||||
|
|
||||||
[7] Ka-Ping Yee, "Chained Exceptions"
|
.. [7] Ka-Ping Yee, "Chained Exceptions"
|
||||||
http://mail.python.org/pipermail/python-dev/2005-May/053672.html
|
http://mail.python.org/pipermail/python-dev/2005-May/053672.html
|
||||||
|
|
||||||
[8] Guido van Rossum discusses automatic chaining in PyErr_Set*
|
.. [8] Guido van Rossum discusses automatic chaining in ``PyErr_Set*``
|
||||||
http://mail.python.org/pipermail/python-dev/2003-June/036180.html
|
http://mail.python.org/pipermail/python-dev/2003-June/036180.html
|
||||||
|
|
||||||
[9] Tony Olensky, "Omnibus Structured Exception/Error Handling Mechanism"
|
.. [9] Tony Olensky, "Omnibus Structured Exception/Error Handling Mechanism"
|
||||||
http://dev.perl.org/perl6/rfc/88.html
|
http://dev.perl.org/perl6/rfc/88.html
|
||||||
|
|
||||||
[10] 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
|
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemexceptionclassinnerexceptiontopic.asp
|
||||||
|
|
||||||
[11] 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
|
http://mail.python.org/pipermail/python-dev/2003-June/036148.html
|
||||||
|
|
||||||
[12] Guido van Rossum restates the objection to cyclic trash
|
.. [12] Guido van Rossum restates the objection to cyclic trash
|
||||||
http://mail.python.org/pipermail/python-3000/2007-January/005322.html
|
http://mail.python.org/pipermail/python-3000/2007-January/005322.html
|
||||||
|
|
||||||
[13] Adam Olsen suggests using a weakref from stack frame to exception
|
.. [13] Adam Olsen suggests using a weakref from stack frame to exception
|
||||||
http://mail.python.org/pipermail/python-3000/2007-January/005363.html
|
http://mail.python.org/pipermail/python-3000/2007-January/005363.html
|
||||||
|
|
||||||
[14] Patch to implement the bulk of the PEP
|
.. [14] Patch to implement the bulk of the PEP
|
||||||
http://svn.python.org/view/python/branches/py3k/Include/?rev=57783&view=rev
|
http://svn.python.org/view/python/branches/py3k/Include/?rev=57783&view=rev
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
This document has been placed in the public domain.
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
Local Variables:
|
..
|
||||||
mode: indented-text
|
Local Variables:
|
||||||
indent-tabs-mode: nil
|
mode: indented-text
|
||||||
sentence-end-double-space: t
|
indent-tabs-mode: nil
|
||||||
fill-column: 70
|
sentence-end-double-space: t
|
||||||
coding: utf-8
|
fill-column: 70
|
||||||
End:
|
coding: utf-8
|
||||||
|
End:
|
||||||
|
|
Loading…
Reference in New Issue