bpo-26389: Allow passing an exception object in the traceback module (GH-22610)
The format_exception(), format_exception_only(), and print_exception() functions can now take an exception object as a positional-only argument. Co-Authored-By: Matthias Bussonnier <bussonniermatthias@gmail.com>
This commit is contained in:
parent
dc42af8fd1
commit
91e93794d5
|
@ -36,7 +36,8 @@ The module defines the following functions:
|
|||
Added negative *limit* support.
|
||||
|
||||
|
||||
.. function:: print_exception(etype, value, tb, limit=None, file=None, chain=True)
|
||||
.. function:: print_exception(exc, /[, value, tb], limit=None, \
|
||||
file=None, chain=True)
|
||||
|
||||
Print exception information and stack trace entries from traceback object
|
||||
*tb* to *file*. This differs from :func:`print_tb` in the following
|
||||
|
@ -45,7 +46,7 @@ The module defines the following functions:
|
|||
* if *tb* is not ``None``, it prints a header ``Traceback (most recent
|
||||
call last):``
|
||||
|
||||
* it prints the exception *etype* and *value* after the stack trace
|
||||
* it prints the exception type and *value* after the stack trace
|
||||
|
||||
.. index:: single: ^ (caret); marker
|
||||
|
||||
|
@ -53,6 +54,10 @@ The module defines the following functions:
|
|||
format, it prints the line where the syntax error occurred with a caret
|
||||
indicating the approximate position of the error.
|
||||
|
||||
Since Python 3.10, instead of passing *value* and *tb*, an exception object
|
||||
can be passed as the first argument. If *value* and *tb* are provided, the
|
||||
first argument is ignored in order to provide backwards compatibility.
|
||||
|
||||
The optional *limit* argument has the same meaning as for :func:`print_tb`.
|
||||
If *chain* is true (the default), then chained exceptions (the
|
||||
:attr:`__cause__` or :attr:`__context__` attributes of the exception) will be
|
||||
|
@ -62,6 +67,10 @@ The module defines the following functions:
|
|||
.. versionchanged:: 3.5
|
||||
The *etype* argument is ignored and inferred from the type of *value*.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
The *etype* parameter has been renamed to *exc* and is now
|
||||
positional-only.
|
||||
|
||||
|
||||
.. function:: print_exc(limit=None, file=None, chain=True)
|
||||
|
||||
|
@ -121,18 +130,26 @@ The module defines the following functions:
|
|||
text line is not ``None``.
|
||||
|
||||
|
||||
.. function:: format_exception_only(etype, value)
|
||||
.. function:: format_exception_only(exc, /[, value])
|
||||
|
||||
Format the exception part of a traceback. The arguments are the exception
|
||||
type and value such as given by ``sys.last_type`` and ``sys.last_value``.
|
||||
The return value is a list of strings, each ending in a newline. Normally,
|
||||
the list contains a single string; however, for :exc:`SyntaxError`
|
||||
exceptions, it contains several lines that (when printed) display detailed
|
||||
information about where the syntax error occurred. The message indicating
|
||||
which exception occurred is the always last string in the list.
|
||||
Format the exception part of a traceback using an exception value such as
|
||||
given by ``sys.last_value``. The return value is a list of strings, each
|
||||
ending in a newline. Normally, the list contains a single string; however,
|
||||
for :exc:`SyntaxError` exceptions, it contains several lines that (when
|
||||
printed) display detailed information about where the syntax error occurred.
|
||||
The message indicating which exception occurred is the always last string in
|
||||
the list.
|
||||
|
||||
Since Python 3.10, instead of passing *value*, an exception object
|
||||
can be passed as the first argument. If *value* is provided, the first
|
||||
argument is ignored in order to provide backwards compatibility.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
The *etype* parameter has been renamed to *exc* and is now
|
||||
positional-only.
|
||||
|
||||
|
||||
.. function:: format_exception(etype, value, tb, limit=None, chain=True)
|
||||
.. function:: format_exception(exc, /[, value, tb], limit=None, chain=True)
|
||||
|
||||
Format a stack trace and the exception information. The arguments have the
|
||||
same meaning as the corresponding arguments to :func:`print_exception`. The
|
||||
|
@ -143,6 +160,10 @@ The module defines the following functions:
|
|||
.. versionchanged:: 3.5
|
||||
The *etype* argument is ignored and inferred from the type of *value*.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
This function's behavior and signature were modified to match
|
||||
:func:`print_exception`.
|
||||
|
||||
|
||||
.. function:: format_exc(limit=None, chain=True)
|
||||
|
||||
|
|
|
@ -232,6 +232,15 @@ retrieve the functions set by :func:`threading.settrace` and
|
|||
:func:`threading.setprofile` respectively.
|
||||
(Contributed by Mario Corchero in :issue:`42251`.)
|
||||
|
||||
traceback
|
||||
---------
|
||||
|
||||
The :func:`~traceback.format_exception`,
|
||||
:func:`~traceback.format_exception_only`, and
|
||||
:func:`~traceback.print_exception` functions can now take an exception object
|
||||
as a positional-only argument.
|
||||
(Contributed by Zackery Spytz and Matthias Bussonnier in :issue:`26389`.)
|
||||
|
||||
types
|
||||
-----
|
||||
|
||||
|
@ -328,6 +337,15 @@ This section lists previously described changes and other bugfixes
|
|||
that may require changes to your code.
|
||||
|
||||
|
||||
Changes in the Python API
|
||||
-------------------------
|
||||
|
||||
* The *etype* parameters of the :func:`~traceback.format_exception`,
|
||||
:func:`~traceback.format_exception_only`, and
|
||||
:func:`~traceback.print_exception` functions in the :mod:`traceback` module
|
||||
have been renamed to *exc*.
|
||||
(Contributed by Zackery Spytz and Matthias Bussonnier in :issue:`26389`.)
|
||||
|
||||
|
||||
Build Changes
|
||||
=============
|
||||
|
|
|
@ -212,6 +212,26 @@ class TracebackCases(unittest.TestCase):
|
|||
)
|
||||
self.assertEqual(output.getvalue(), "Exception: projector\n")
|
||||
|
||||
def test_print_exception_exc(self):
|
||||
output = StringIO()
|
||||
traceback.print_exception(Exception("projector"), file=output)
|
||||
self.assertEqual(output.getvalue(), "Exception: projector\n")
|
||||
|
||||
def test_format_exception_exc(self):
|
||||
e = Exception("projector")
|
||||
output = traceback.format_exception(e)
|
||||
self.assertEqual(output, ["Exception: projector\n"])
|
||||
with self.assertRaisesRegex(ValueError, 'Both or neither'):
|
||||
traceback.format_exception(e.__class__, e)
|
||||
with self.assertRaisesRegex(ValueError, 'Both or neither'):
|
||||
traceback.format_exception(e.__class__, tb=e.__traceback__)
|
||||
with self.assertRaisesRegex(TypeError, 'positional-only'):
|
||||
traceback.format_exception(exc=e)
|
||||
|
||||
def test_format_exception_only_exc(self):
|
||||
output = traceback.format_exception_only(Exception("projector"))
|
||||
self.assertEqual(output, ["Exception: projector\n"])
|
||||
|
||||
|
||||
class TracebackFormatTests(unittest.TestCase):
|
||||
|
||||
|
|
|
@ -84,7 +84,19 @@ _context_message = (
|
|||
"another exception occurred:\n\n")
|
||||
|
||||
|
||||
def print_exception(etype, value, tb, limit=None, file=None, chain=True):
|
||||
_sentinel = object()
|
||||
|
||||
|
||||
def _parse_value_tb(exc, value, tb):
|
||||
if (value is _sentinel) != (tb is _sentinel):
|
||||
raise ValueError("Both or neither of value and tb must be given")
|
||||
if value is tb is _sentinel:
|
||||
return exc, exc.__traceback__
|
||||
return value, tb
|
||||
|
||||
|
||||
def print_exception(exc, /, value=_sentinel, tb=_sentinel, limit=None, \
|
||||
file=None, chain=True):
|
||||
"""Print exception up to 'limit' stack trace entries from 'tb' to 'file'.
|
||||
|
||||
This differs from print_tb() in the following ways: (1) if
|
||||
|
@ -95,9 +107,7 @@ def print_exception(etype, value, tb, limit=None, file=None, chain=True):
|
|||
occurred with a caret on the next line indicating the approximate
|
||||
position of the error.
|
||||
"""
|
||||
# format_exception has ignored etype for some time, and code such as cgitb
|
||||
# passes in bogus values as a result. For compatibility with such code we
|
||||
# ignore it here (rather than in the new TracebackException API).
|
||||
value, tb = _parse_value_tb(exc, value, tb)
|
||||
if file is None:
|
||||
file = sys.stderr
|
||||
for line in TracebackException(
|
||||
|
@ -105,7 +115,8 @@ def print_exception(etype, value, tb, limit=None, file=None, chain=True):
|
|||
print(line, file=file, end="")
|
||||
|
||||
|
||||
def format_exception(etype, value, tb, limit=None, chain=True):
|
||||
def format_exception(exc, /, value=_sentinel, tb=_sentinel, limit=None, \
|
||||
chain=True):
|
||||
"""Format a stack trace and the exception information.
|
||||
|
||||
The arguments have the same meaning as the corresponding arguments
|
||||
|
@ -114,19 +125,15 @@ def format_exception(etype, value, tb, limit=None, chain=True):
|
|||
these lines are concatenated and printed, exactly the same text is
|
||||
printed as does print_exception().
|
||||
"""
|
||||
# format_exception has ignored etype for some time, and code such as cgitb
|
||||
# passes in bogus values as a result. For compatibility with such code we
|
||||
# ignore it here (rather than in the new TracebackException API).
|
||||
value, tb = _parse_value_tb(exc, value, tb)
|
||||
return list(TracebackException(
|
||||
type(value), value, tb, limit=limit).format(chain=chain))
|
||||
|
||||
|
||||
def format_exception_only(etype, value):
|
||||
def format_exception_only(exc, /, value=_sentinel):
|
||||
"""Format the exception part of a traceback.
|
||||
|
||||
The arguments are the exception type and value such as given by
|
||||
sys.last_type and sys.last_value. The return value is a list of
|
||||
strings, each ending in a newline.
|
||||
The return value is a list of strings, each ending in a newline.
|
||||
|
||||
Normally, the list contains a single string; however, for
|
||||
SyntaxError exceptions, it contains several lines that (when
|
||||
|
@ -137,7 +144,10 @@ def format_exception_only(etype, value):
|
|||
string in the list.
|
||||
|
||||
"""
|
||||
return list(TracebackException(etype, value, None).format_exception_only())
|
||||
if value is _sentinel:
|
||||
value = exc
|
||||
return list(TracebackException(
|
||||
type(value), value, None).format_exception_only())
|
||||
|
||||
|
||||
# -- not official API but folk probably use these two functions.
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
The :func:`traceback.format_exception`,
|
||||
:func:`traceback.format_exception_only`, and
|
||||
:func:`traceback.print_exception` functions can now take an exception object
|
||||
as a positional-only argument.
|
Loading…
Reference in New Issue