Latest update from Ethan, marking PEP 409 as accepted.

This commit is contained in:
Brett Cannon 2012-02-05 19:36:12 -05:00
parent 5b1a3f5b4e
commit 7506ff282f
1 changed files with 47 additions and 42 deletions

View File

@ -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: