PEP: 409 Title: Suppressing exception context Version: $Revision$ Last-Modified: $Date$ Author: Ethan Furman <et...@stoneleaf.us> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 26-Jan-2012 Post-History: 30-Aug-2002, 01-Feb-2012
Abstract ======== One of the open issues from PEP 3134 is suppressing context: currently there is no way to do it. This PEP proposes one. Rationale ========= There are two basic ways to generate exceptions: 1) Python does it (buggy code, missing resources, ending loops, etc.) 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:: try: value = int(value) except Exception: raise DbfError(...) Whatever the original exception was (``ValueError``, ``TypeError``, or something else) is irrelevant. The exception from this point on is a ``DbfError``, and the original exception is of no value. However, if this exception is printed, we would currently see both. Alternatives ============ Several possibilities have been put forth: * ``raise as NewException()`` Reuses the ``as`` keyword; can be confusing since we are not really reraising the originating exception * ``raise NewException() from None`` Follows existing syntax of explicitly declaring the originating exception * ``exc = NewException(); exc.__context__ = None; raise exc`` Very verbose way of the previous method * ``raise NewException.no_context(...)`` Make context suppression a class method. All of the above options will require changes to the core. Proposal ======== 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:: raise KeyError() from NameError() but because the 'cause' is ``None`` the previous context, while retained, is not displayed by the default exception printing routines. Language Details ================ Currently, ``__context__`` and ``__cause__`` start out as None, and then get set as exceptions occur. To support ``from None``, ``__context__`` will stay as it is, but ``__cause__`` will start out as ``False``, and will change to ``None`` when the ``raise ... from None`` method is used. The default exception printing routine will then: * If ``__cause__`` is ``False`` the ``__context__`` (if any) will be printed. * If ``__cause__`` is ``None`` the ``__context__`` will not be printed. * if ``__cause__`` is anything else, ``__cause__`` will be printed. This has the benefit of leaving the ``__context__`` intact for future logging, querying, etc., while suppressing its display if it is not caught. This is important for those times when trying to debug poorly written libraries with `bad error messages`_. Patches ======= There is a patch for CPython implementing this attached to `Issue 6210`_. References ========== Discussion and refinements in this `thread on python-dev`_. .. _bad error messages: http://bugs.python.org/msg152294 .. _Issue 6210: http://bugs.python.org/issue6210 .. _thread on python-dev: http://mail.python.org/pipermail/python-dev/2012-January/115838.html Copyright ========= This document has been placed in the public domain. .. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 coding: utf-8 End: _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com