Movatterモバイル変換
[0]ホーム
[Python-Dev] PEP 409 update [was: PEP 409 - final?]
Ethan Furmanethan at stoneleaf.us
Thu Feb 2 23:10:31 CET 2012
PEP: 409Title: Suppressing exception contextVersion: $Revision$Last-Modified: $Date$Author: Ethan Furman <ethan at stoneleaf.us>Status: DraftType: Standards TrackContent-Type: text/x-rstCreated: 26-Jan-2012Post-History: 30-Aug-2002, 01-Feb-2012, 03-Feb-2012Abstract========One of the open issues from PEP 3134 is suppressing context: currentlythere 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 becomenecessary to raise exceptions; moreover it can be useful, evennecessary, to change from one exception to another. To take an examplefrom my dbf module: try: value = int(value) except Exception: raise DbfError(...)Whatever the original exception was (/ValueError/, /TypeError/, orsomething else) is irrelevant. The exception from this point on is a/DbfError/, and the original exception is of no value. However, ifthis 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 NoneIt has the advantage of using the existing pattern of explicitly settingthe cause: raise KeyError() from NameError()but because the cause is /None/ the previous context is not displayedby 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__/. Severalideas 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.htmlCopyright=========This document has been placed in the public domain.
More information about the Python-Devmailing list
[8]ページ先頭