Latest update from Ethan, marking PEP 409 as accepted.
This commit is contained in:
parent
5b1a3f5b4e
commit
7506ff282f
89
pep-0409.txt
89
pep-0409.txt
|
@ -3,17 +3,18 @@ Title: Suppressing exception context
|
|||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Ethan Furman <ethan@stoneleaf.us>
|
||||
Status: Draft
|
||||
Status: Accepted
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 26-Jan-2012
|
||||
Post-History: 30-Aug-2002, 01-Feb-2012, 03-Feb-2012
|
||||
Resolution: http://mail.python.org/pipermail/python-dev/2012-February/116136.html
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
One of the open issues from PEP 3134 is suppressing context: currently
|
||||
One of the open issues from PEP 3134 is suppressing context: currently
|
||||
there is no way to do it. This PEP proposes one.
|
||||
|
||||
|
||||
|
@ -22,14 +23,14 @@ Rationale
|
|||
|
||||
There are two basic ways to generate exceptions:
|
||||
|
||||
1. Python does it (buggy code, missing resources, ending loops, etc.)
|
||||
1) Python does it (buggy code, missing resources, ending loops, etc.)
|
||||
|
||||
2. manually (with a raise statement)
|
||||
2) manually (with a raise statement)
|
||||
|
||||
When writing libraries, or even just custom classes, it can become
|
||||
necessary to raise exceptions; moreover it can be useful, even
|
||||
necessary, to change from one exception to another. To take an
|
||||
example from my dbf module::
|
||||
necessary, to change from one exception to another. To take an example
|
||||
from my dbf module::
|
||||
|
||||
try:
|
||||
value = int(value)
|
||||
|
@ -74,58 +75,55 @@ I proprose going with the second option::
|
|||
|
||||
raise NewException from None
|
||||
|
||||
It has the advantage of using the existing pattern of explicitly
|
||||
setting the cause::
|
||||
It has the advantage of using the existing pattern of explicitly setting
|
||||
the cause::
|
||||
|
||||
raise KeyError() from NameError()
|
||||
|
||||
but because the cause is ``None`` the previous context is not
|
||||
displayed by the default exception printing routines.
|
||||
but because the cause is ``None`` the previous context is not displayed
|
||||
by the default exception printing routines.
|
||||
|
||||
|
||||
Implementation Discussion
|
||||
=========================
|
||||
|
||||
Currently, ``None`` is the default for both ``__context__`` and
|
||||
``__cause__``. In order to support ``raise ... from None`` (which
|
||||
would set ``__cause__`` to ``None``) we need a different default value
|
||||
for ``__cause__``. Several ideas were put forth on how to implement
|
||||
this at the language level:
|
||||
Currently, ``None`` is the default for both ``__context__`` and ``__cause__``.
|
||||
In order to support ``raise ... from None`` (which would set ``__cause__`` to
|
||||
``None``) we need a different default value for ``__cause__``. Several ideas
|
||||
were put forth on how to implement this at the language level:
|
||||
|
||||
* Overwrite the previous exception information (side-stepping the
|
||||
issue and leaving ``__cause__`` at ``None``).
|
||||
* Overwrite the previous exception information (side-stepping the issue and
|
||||
leaving ``__cause__`` at ``None``).
|
||||
|
||||
Rejected as this can seriously hinder debugging due to `poor error
|
||||
messages`_.
|
||||
Rejected as this can seriously hinder debugging due to
|
||||
`poor error messages`_.
|
||||
|
||||
* Use one of the boolean values in ``__cause__``: ``False`` would be
|
||||
the default value, and would be replaced when ``from ...`` was used
|
||||
with the explicity chained exception or ``None``.
|
||||
* Use one of the boolean values in ``__cause__``: ``False`` would be the
|
||||
default value, and would be replaced when ``from ...`` was used with the
|
||||
explicity chained exception or ``None``.
|
||||
|
||||
Rejected as this encourages the use of two different objects types
|
||||
for ``__cause__`` with one of them (boolean) not allowed to have the
|
||||
full range of possible values (``True`` would never be used).
|
||||
Rejected as this encourages the use of two different objects types for
|
||||
``__cause__`` with one of them (boolean) not allowed to have the full range
|
||||
of possible values (``True`` would never be used).
|
||||
|
||||
* Create a special exception class, ``__NoException__``.
|
||||
|
||||
Rejected as possibly confusing, possibly being mistakenly raised by
|
||||
users, and not being a truly unique value as ``None``, ``True``, and
|
||||
``False`` are.
|
||||
Rejected as possibly confusing, possibly being mistakenly raised by users,
|
||||
and not being a truly unique value as ``None``, ``True``, and ``False`` are.
|
||||
|
||||
* Use ``Ellipsis`` as the default value (the ``...`` singleton).
|
||||
|
||||
Accepted. There are no other possible values; it cannot be raised
|
||||
as it is not an exception; it has the connotation of 'fill in the
|
||||
rest...' as in ``__cause__`` is not set, look in ``__context__`` for
|
||||
it.
|
||||
Accepted. There are no other possible values; it cannot be raised as it is
|
||||
not an exception; it has the connotation of 'fill in the rest...' as in
|
||||
``__cause__`` is not set, look in ``__context__`` for it.
|
||||
|
||||
|
||||
Language Details
|
||||
================
|
||||
|
||||
To support ``from None``, ``__context__`` will stay as it is, but
|
||||
``__cause__`` will start out as ``Ellipsis`` and will change to
|
||||
``None`` when the ``raise ... from None`` method is used.
|
||||
``__cause__`` will start out as ``Ellipsis`` and will change to ``None``
|
||||
when the ``raise ... from None`` method is used.
|
||||
|
||||
============================================ ================== =======================================
|
||||
form __context__ __cause__
|
||||
|
@ -137,20 +135,26 @@ reraise from ``None`` | ``ChainedException`` previous exception ``None`` | exp
|
|||
|
||||
The default exception printing routine will then:
|
||||
|
||||
* If ``__cause__`` is ``Ellipsis`` the ``__context__`` (if any) will
|
||||
be printed.
|
||||
|
||||
* If ``__cause__`` is ``None`` the ``__context__`` will not be
|
||||
* If ``__cause__`` is ``Ellipsis`` the ``__context__`` (if any) will be
|
||||
printed.
|
||||
|
||||
* If ``__cause__`` is anything else, ``__cause__`` will be printed.
|
||||
* If ``__cause__`` is ``None`` the ``__context__`` will not be printed.
|
||||
|
||||
* if ``__cause__`` is anything else, ``__cause__`` will be printed.
|
||||
|
||||
In both of the latter cases the exception chain will stop being followed.
|
||||
|
||||
Because the default value for ``__cause__`` is now ``Ellipsis``::
|
||||
|
||||
raise Exception from Ellipsis
|
||||
|
||||
is allowed and will (re)set ``__cause__`` to ``Ellipsis``.
|
||||
|
||||
|
||||
Patches
|
||||
=======
|
||||
|
||||
There is a patch for CPython implementing this attached to `Issue
|
||||
6210`_.
|
||||
There is a patch for CPython implementing this attached to `Issue 6210`_.
|
||||
|
||||
|
||||
References
|
||||
|
@ -171,7 +175,7 @@ Copyright
|
|||
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
|
@ -180,3 +184,4 @@ This document has been placed in the public domain.
|
|||
fill-column: 70
|
||||
coding: utf-8
|
||||
End:
|
||||
|
||||
|
|
Loading…
Reference in New Issue