Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 490 – Chain exceptions at C level

Author:
Victor Stinner <vstinner at python.org>
Status:
Rejected
Type:
Standards Track
Created:
25-Mar-2015
Python-Version:
3.6

Table of Contents

Abstract

Chain exceptions at C level, as already done at Python level.

Rationale

Python 3 introduced a new killer feature: exceptions are chained bydefault,PEP 3134.

Example:

try:raiseTypeError("err1")exceptTypeError:raiseValueError("err2")

Output:

Traceback(mostrecentcalllast):File"test.py",line2,in<module>raiseTypeError("err1")TypeError:err1Duringhandlingoftheaboveexception,anotherexceptionoccurred:Traceback(mostrecentcalllast):File"test.py",line4,in<module>raiseValueError("err2")ValueError:err2

Exceptions are chained by default in Python code, but not inextensions written in C.

A new private_PyErr_ChainExceptions() function was introduced inPython 3.4.3 and 3.5 to chain exceptions. Currently, it must be calledexplicitly to chain exceptions and its usage is not trivial.

Example of_PyErr_ChainExceptions() usage from thezipimportmodule to chain the previousOSError to a newZipImportErrorexception:

PyObject*exc,*val,*tb;PyErr_Fetch(&exc,&val,&tb);PyErr_Format(ZipImportError,"can't open Zip file: %R",archive);_PyErr_ChainExceptions(exc,val,tb);

This PEP proposes to also chain exceptions automatically at C level tostay consistent and give more information on failures to helpdebugging. The previous example becomes simply:

PyErr_Format(ZipImportError,"can't open Zip file: %R",archive);

Proposal

Modify PyErr_*() functions to chain exceptions

Modify C functions raising exceptions of the Python C API toautomatically chain exceptions: modifyPyErr_SetString(),PyErr_Format(),PyErr_SetNone(), etc.

Modify functions to not chain exceptions

Keeping the previous exception is not always interesting when the newexception contains information of the previous exception or even moreinformation, especially when the two exceptions have the same type.

Example of an useless exception chain withint(str):

TypeError:abytes-likeobjectisrequired,not'type'Duringhandlingoftheaboveexception,anotherexceptionoccurred:Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:int()argumentmustbeastring,abytes-likeobjectoranumber,not'type'

The newTypeError exception contains more information than theprevious exception. The previous exception should be hidden.

ThePyErr_Clear() function can be called to clear the currentexception before raising a new exception, to not chain the currentexception with a new exception.

Modify functions to chain exceptions

Some functions save and then restore the current exception. If a newexception is raised, the exception is currently displayed intosys.stderr or ignored depending on the function. Some of thesefunctions should be modified to chain exceptions instead.

Examples of function ignoring the new exception(s):

  • ptrace_enter_call(): ignore exception
  • subprocess_fork_exec(): ignore exception raised by enable_gc()
  • t_bootstrap() of the_thread module: ignore exception raisedby trying to display the bootstrap function tosys.stderr
  • PyDict_GetItem(),_PyDict_GetItem_KnownHash(): ignoreexception raised by looking for a key in the dictionary
  • _PyErr_TrySetFromCause(): ignore exception
  • PyFrame_LocalsToFast(): ignore exception raised bydict_to_map()
  • _PyObject_Dump(): ignore exception._PyObject_Dump() is usedto debug, to inspect a running process, it should not modify thePython state.
  • Py_ReprLeave(): ignore exception “because there is no way toreport them”
  • type_dealloc(): ignore exception raised byremove_all_subclasses()
  • PyObject_ClearWeakRefs(): ignore exception?
  • call_exc_trace(),call_trace_protected(): ignore exception
  • remove_importlib_frames(): ignore exception
  • do_mktuple(), helper used byPy_BuildValue() for example:ignore exception?
  • flush_io(): ignore exception
  • sys_write(),sys_format(): ignore exception
  • _PyTraceback_Add(): ignore exception
  • PyTraceBack_Print(): ignore exception

Examples of function displaying the new exception tosys.stderr:

  • atexit_callfuncs(): display exceptions withPyErr_Display() and return the latest exception, the functioncalls multiple callbacks and only returns the latest exception
  • sock_dealloc(): log theResourceWarning exception withPyErr_WriteUnraisable()
  • slot_tp_del(): display exception withPyErr_WriteUnraisable()
  • _PyGen_Finalize(): displaygen_close() exception withPyErr_WriteUnraisable()
  • slot_tp_finalize(): display exception raised by the__del__() method withPyErr_WriteUnraisable()
  • PyErr_GivenExceptionMatches(): display exception raised byPyType_IsSubtype() withPyErr_WriteUnraisable()

Backward compatibility

A side effect of chaining exceptions is that exceptions storetraceback objects which store frame objects which store localvariables. Local variables are kept alive by exceptions. A commonissue is a reference cycle between local variables and exceptions: anexception is stored in a local variable and the frame indirectlystored in the exception. The cycle only impacts applications storingexceptions.

The reference cycle can now be fixed with the newtraceback.TracebackException object introduced in Python 3.5. Itstores information required to format a full textual traceback withoutstoring local variables.

Theasyncio is impacted by the reference cycle issue. This moduleis also maintained outside Python standard library to release aversion for Python 3.3.traceback.TracebackException will maybebe backported in a privateasyncio module to fix reference cycleissues.

Alternatives

No change

A new private_PyErr_ChainExceptions() function is enough to chainmanually exceptions.

Exceptions will only be chained explicitly where it makes sense.

New helpers to chain exceptions

Functions likePyErr_SetString() don’t chain automaticallyexceptions. To make the usage of_PyErr_ChainExceptions() easier,new private functions are added:

  • _PyErr_SetStringChain(exc_type,message)
  • _PyErr_FormatChain(exc_type,format,...)
  • _PyErr_SetNoneChain(exc_type)
  • _PyErr_SetObjectChain(exc_type,exc_value)

Helper functions to raise specific exceptions like_PyErr_SetKeyError(key) orPyErr_SetImportError(message,name,path) don’t chain exceptions. The generic_PyErr_ChainExceptions(exc_type,exc_value,exc_tb) should be usedto chain exceptions with these helper functions.

Appendix

PEPs

  • PEP 3134 – Exception Chaining and Embedded Tracebacks(Python 3.0):new__context__ and__cause__ attributes for exceptions
  • PEP 415 – Implement context suppression with exception attributes(Python 3.3):raiseexcfromNone
  • PEP 409 – Suppressing exception context(superseded by thePEP 415)

Python C API

The header fileInclude/pyerror.h declares functions related toexceptions.

Functions raising exceptions:

  • PyErr_SetNone(exc_type)
  • PyErr_SetObject(exc_type,exc_value)
  • PyErr_SetString(exc_type,message)
  • PyErr_Format(exc,format,...)

Helpers to raise specific exceptions:

  • PyErr_BadArgument()
  • PyErr_BadInternalCall()
  • PyErr_NoMemory()
  • PyErr_SetFromErrno(exc)
  • PyErr_SetFromWindowsErr(err)
  • PyErr_SetImportError(message,name,path)
  • _PyErr_SetKeyError(key)
  • _PyErr_TrySetFromCause(prefix_format,...)

Manage the current exception:

  • PyErr_Clear(): clear the current exception,likeexcept:pass
  • PyErr_Fetch(exc_type,exc_value,exc_tb)
  • PyErr_Restore(exc_type,exc_value,exc_tb)
  • PyErr_GetExcInfo(exc_type,exc_value,exc_tb)
  • PyErr_SetExcInfo(exc_type,exc_value,exc_tb)

Others function to handle exceptions:

  • PyErr_ExceptionMatches(exc): check to implementexceptexc: ...
  • PyErr_GivenExceptionMatches(exc1,exc2)
  • PyErr_NormalizeException(exc_type,exc_value,exc_tb)
  • _PyErr_ChainExceptions(exc_type,exc_value,exc_tb)

Python Issues

Chain exceptions:

Changes preventing to loose exceptions:

Rejection

The PEP was rejected on 2017-09-12 by Victor Stinner. It was decided inthe python-dev discussion to not chain C exceptions by default, butinstead chain them explicitly only where it makes sense.

Copyright

This document has been placed in the public domain.


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

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


[8]ページ先頭

©2009-2025 Movatter.jp