[Python-Dev] PEP 409 update [was: PEP 409 - final?]
Yury Selivanov
yselivanov.ml at gmail.com
Fri Feb 3 00:32:09 CET 2012
In my opinion using Ellipsis is just wrong. It is completely
non-obvious not only to a beginner, but even to an experienced
python developer. Writing 'raise Something() from None'
looks less suspicious, but still strange.
Isn't 'raise Exception().no_context()' or
'raise Exception().no_cause()' more obvious and easy to
implement? More readable, less complex and ambiguous.
On 2012-02-02, at 5:10 PM, Ethan Furman wrote:
> PEP: 409
> Title: Suppressing exception context
> Version: $Revision$
> Last-Modified: $Date$
> Author: Ethan Furman <ethan at stoneleaf.us>
> Status: Draft
> Type: Standards Track
> Content-Type: text/x-rst
> Created: 26-Jan-2012
> Post-History: 30-Aug-2002, 01-Feb-2012, 03-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 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:
>
> * 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`_.
>
> * 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).
>
> * 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.
>
> * Use /Ellipsis/ as the default value (the /.../ singleton).
>
> Accepted. There are no other possible values; it cannot be raised as
> it is not an acception; 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.
>
> ============================== ================== ==================
> form __context__ __cause__
> ============================== ================== ==================
> raise /None/ /Ellipsis/
>
> reraise previous exception /Ellipsis/
>
> reraise from previous exception /None/ |
> /None/ | /ChainedException/ explicitly chained
> exception
> ============================== ================== ==================
>
> 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 printed.
>
> * if /__cause__/ is anything else, /__cause__/ will be printed.
>
>
> Patches
> =======
>
> There is a patch for CPython implementing this attached to `Issue 6210`_.
>
>
> References
> ==========
>
> Discussion and refinements in this `thread on python-dev`_.
>
> .. _poor 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.
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/yselivanov.ml%40gmail.com
More information about the Python-Dev
mailing list