2012-01-27 10:42:24 -05:00
|
|
|
|
PEP: 409
|
|
|
|
|
Title: Suppressing exception context
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Ethan Furman <ethan@stoneleaf.us>
|
2012-05-01 07:48:42 -04:00
|
|
|
|
Status: Final
|
2012-01-27 10:42:24 -05:00
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 26-Jan-2012
|
2022-08-24 18:40:18 -04:00
|
|
|
|
Python-Version: 3.3
|
2012-02-03 03:34:26 -05:00
|
|
|
|
Post-History: 30-Aug-2002, 01-Feb-2012, 03-Feb-2012
|
2012-05-15 07:53:25 -04:00
|
|
|
|
Superseded-By: 415
|
2017-06-11 15:02:39 -04:00
|
|
|
|
Resolution: https://mail.python.org/pipermail/python-dev/2012-February/116136.html
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
2022-01-21 06:03:51 -05:00
|
|
|
|
One of the open issues from :pep:`3134` is suppressing context: currently
|
2012-01-29 03:41:13 -05:00
|
|
|
|
there is no way to do it. This PEP proposes one.
|
|
|
|
|
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
Rationale
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
There are two basic ways to generate exceptions:
|
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
1) Python does it (buggy code, missing resources, ending loops, etc.)
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
2) manually (with a raise statement)
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-01-29 03:41:13 -05:00
|
|
|
|
When writing libraries, or even just custom classes, it can become
|
|
|
|
|
necessary to raise exceptions; moreover it can be useful, even
|
2012-02-05 19:36:12 -05:00
|
|
|
|
necessary, to change from one exception to another. To take an example
|
|
|
|
|
from my dbf module::
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
try:
|
|
|
|
|
value = int(value)
|
|
|
|
|
except Exception:
|
|
|
|
|
raise DbfError(...)
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
Whatever the original exception was (``ValueError``, ``TypeError``, or
|
2012-01-29 03:41:13 -05:00
|
|
|
|
something else) is irrelevant. The exception from this point on is a
|
2012-02-03 03:34:26 -05:00
|
|
|
|
``DbfError``, and the original exception is of no value. However, if
|
|
|
|
|
this exception is printed, we would currently see both.
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Alternatives
|
|
|
|
|
============
|
|
|
|
|
Several possibilities have been put forth:
|
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
* ``raise as NewException()``
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
Reuses the ``as`` keyword; can be confusing since we are not really
|
|
|
|
|
reraising the originating exception
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
* ``raise NewException() from None``
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
Follows existing syntax of explicitly declaring the originating
|
|
|
|
|
exception
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
* ``exc = NewException(); exc.__context__ = None; raise exc``
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-01-29 03:41:13 -05:00
|
|
|
|
Very verbose way of the previous method
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
* ``raise NewException.no_context(...)``
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-01-29 03:41:13 -05:00
|
|
|
|
Make context suppression a class method.
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
|
|
|
|
All of the above options will require changes to the core.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal
|
|
|
|
|
========
|
|
|
|
|
|
2013-03-25 17:27:15 -04:00
|
|
|
|
I propose going with the second option::
|
2012-01-29 03:41:13 -05:00
|
|
|
|
|
|
|
|
|
raise NewException from None
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
It has the advantage of using the existing pattern of explicitly setting
|
|
|
|
|
the cause::
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-01-29 03:41:13 -05:00
|
|
|
|
raise KeyError() from NameError()
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
but because the cause is ``None`` the previous context is not displayed
|
|
|
|
|
by the default exception printing routines.
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Implementation Discussion
|
|
|
|
|
=========================
|
|
|
|
|
|
2012-05-15 07:53:25 -04:00
|
|
|
|
Note: after acceptance of this PEP, a cleaner implementation mechanism
|
2022-01-21 06:03:51 -05:00
|
|
|
|
was proposed and accepted in :pep:`415`. Refer to that PEP for more
|
2012-05-15 07:53:25 -04:00
|
|
|
|
details on the implementation actually used in Python 3.3.
|
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
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:
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
* Overwrite the previous exception information (side-stepping the issue and
|
|
|
|
|
leaving ``__cause__`` at ``None``).
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
Rejected as this can seriously hinder debugging due to
|
|
|
|
|
`poor error messages`_.
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
* Use one of the boolean values in ``__cause__``: ``False`` would be the
|
|
|
|
|
default value, and would be replaced when ``from ...`` was used with the
|
2016-07-11 11:14:08 -04:00
|
|
|
|
explicitly chained exception or ``None``.
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
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).
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
|
|
|
|
* Create a special exception class, ``__NoException__``.
|
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
Rejected as possibly confusing, possibly being mistakenly raised by users,
|
|
|
|
|
and not being a truly unique value as ``None``, ``True``, and ``False`` are.
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
|
|
|
|
* Use ``Ellipsis`` as the default value (the ``...`` singleton).
|
|
|
|
|
|
2012-02-06 15:19:16 -05:00
|
|
|
|
Accepted.
|
|
|
|
|
|
|
|
|
|
Ellipses are commonly used in English as place holders when words are
|
|
|
|
|
omitted. This works in our favor here as a signal that ``__cause__`` is
|
|
|
|
|
omitted, so look in ``__context__`` for more details.
|
|
|
|
|
|
|
|
|
|
Ellipsis is not an exception, so cannot be raised.
|
|
|
|
|
|
|
|
|
|
There is only one Ellipsis, so no unused values.
|
|
|
|
|
|
|
|
|
|
Error information is not thrown away, so custom code can trace the entire
|
|
|
|
|
exception chain even if the default code does not.
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Language Details
|
|
|
|
|
================
|
|
|
|
|
|
2012-02-06 15:19:16 -05:00
|
|
|
|
To support ``raise Exception from None``, ``__context__`` will stay as it is,
|
|
|
|
|
but ``__cause__`` will start out as ``Ellipsis`` and will change to ``None``
|
|
|
|
|
when the ``raise Exception from None`` method is used.
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
|
|
|
|
============================================ ================== =======================================
|
|
|
|
|
form __context__ __cause__
|
|
|
|
|
============================================ ================== =======================================
|
|
|
|
|
raise ``None`` ``Ellipsis``
|
|
|
|
|
reraise previous exception ``Ellipsis``
|
|
|
|
|
reraise from ``None`` | ``ChainedException`` previous exception ``None`` | explicitly chained exception
|
|
|
|
|
============================================ ================== =======================================
|
|
|
|
|
|
|
|
|
|
The default exception printing routine will then:
|
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
* If ``__cause__`` is ``Ellipsis`` the ``__context__`` (if any) will be
|
2012-02-03 03:34:26 -05:00
|
|
|
|
printed.
|
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
* 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.
|
|
|
|
|
|
2012-02-28 10:02:09 -05:00
|
|
|
|
Because the default value for ``__cause__`` is now ``Ellipsis`` and ``raise
|
|
|
|
|
Exception from Cause`` is simply syntactic sugar for::
|
2012-02-05 19:36:12 -05:00
|
|
|
|
|
2012-02-28 10:02:09 -05:00
|
|
|
|
_exc = NewException()
|
|
|
|
|
_exc.__cause__ = Cause()
|
|
|
|
|
raise _exc
|
|
|
|
|
|
|
|
|
|
``Ellipsis``, as well as ``None``, is now allowed as a cause::
|
2012-02-05 19:36:12 -05:00
|
|
|
|
|
2012-02-28 10:02:09 -05:00
|
|
|
|
raise Exception from Ellipsis
|
2012-02-03 03:34:26 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Patches
|
|
|
|
|
=======
|
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
There is a patch for CPython implementing this attached to `Issue 6210`_.
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
|
|
|
|
|
2012-01-27 10:47:48 -05:00
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
2012-02-03 03:34:26 -05:00
|
|
|
|
Discussion and refinements in this `thread on python-dev`_.
|
|
|
|
|
|
|
|
|
|
.. _poor error messages:
|
|
|
|
|
http://bugs.python.org/msg152294
|
|
|
|
|
.. _issue 6210:
|
2012-01-27 10:47:48 -05:00
|
|
|
|
http://bugs.python.org/issue6210
|
2012-02-03 03:34:26 -05:00
|
|
|
|
.. _Thread on python-dev:
|
2017-06-11 15:02:39 -04:00
|
|
|
|
https://mail.python.org/pipermail/python-dev/2012-January/115838.html
|
2012-01-27 10:42:24 -05:00
|
|
|
|
|
2012-01-29 03:41:13 -05:00
|
|
|
|
|
2012-01-27 10:42:24 -05:00
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
2012-02-05 19:36:12 -05:00
|
|
|
|
|
2012-01-27 10:42:24 -05:00
|
|
|
|
..
|
2012-01-29 03:41:13 -05:00
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|
2012-02-05 19:36:12 -05:00
|
|
|
|
|