Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 409 – Suppressing exception context

Author:
Ethan Furman <ethan at stoneleaf.us>
Status:
Final
Type:
Standards Track
Created:
26-Jan-2012
Python-Version:
3.3
Post-History:
30-Aug-2002, 01-Feb-2012, 03-Feb-2012
Superseded-By:
415
Resolution:
Python-Dev message

Table of Contents

Abstract

One of the open issues fromPEP 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)exceptException:raiseDbfError(...)

Whatever the original exception was (ValueError,TypeError, orsomething else) is irrelevant. The exception from this point on is aDbfError, 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:

  • raiseasNewException()

    Reuses theas keyword; can be confusing since we are not reallyreraising the originating exception

  • raiseNewException()fromNone

    Follows existing syntax of explicitly declaring the originatingexception

  • exc=NewException();exc.__context__=None;raiseexc

    Very verbose way of the previous method

  • raiseNewException.no_context(...)

    Make context suppression a class method.

All of the above options will require changes to the core.

Proposal

I propose going with the second option:

raiseNewExceptionfromNone

It has the advantage of using the existing pattern of explicitly settingthe cause:

raiseKeyError()fromNameError()

but because the cause isNone the previous context is not displayedby the default exception printing routines.

Implementation Discussion

Note: after acceptance of this PEP, a cleaner implementation mechanismwas proposed and accepted inPEP 415. Refer to that PEP for moredetails on the implementation actually used in Python 3.3.

Currently,None is the default for both__context__ and__cause__.In order to supportraise...fromNone (which would set__cause__ toNone) we need a different default value for__cause__. Several ideaswere put forth on how to implement this at the language level:

  • Overwrite the previous exception information (side-stepping the issue andleaving__cause__ atNone).

    Rejected as this can seriously hinder debugging due topoor error messages.

  • Use one of the boolean values in__cause__:False would be thedefault value, and would be replaced whenfrom... was used with theexplicitly chained exception orNone.

    Rejected as this encourages the use of two different objects types for__cause__ with one of them (boolean) not allowed to have the full rangeof 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 asNone,True, andFalse are.

  • UseEllipsis as the default value (the... singleton).

    Accepted.

    Ellipses are commonly used in English as place holders when words areomitted. This works in our favor here as a signal that__cause__ isomitted, 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 entireexception chain even if the default code does not.

Language Details

To supportraiseExceptionfromNone,__context__ will stay as it is,but__cause__ will start out asEllipsis and will change toNonewhen theraiseExceptionfromNone method is used.

form__context____cause__
raiseNoneEllipsis
reraiseprevious exceptionEllipsis
reraise fromNone |ChainedExceptionprevious exceptionNone | explicitly chained exception

The default exception printing routine will then:

  • If__cause__ isEllipsis the__context__ (if any) will beprinted.
  • If__cause__ isNone 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 nowEllipsis andraiseExceptionfromCause is simply syntactic sugar for:

_exc=NewException()_exc.__cause__=Cause()raise_exc

Ellipsis, as well asNone, is now allowed as a cause:

raiseExceptionfromEllipsis

Patches

There is a patch for CPython implementing this attached toIssue 6210.

References

Discussion and refinements in thisthread on python-dev.

Copyright

This document has been placed in the public domain.


Source:https://github.com/python/peps/blob/main/peps/pep-0409.rst

Last modified:2025-02-01 08:59:27 GMT


[8]ページ先頭

©2009-2025 Movatter.jp