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.
|
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
|
Print exception information and stack trace entries from traceback object
|
||||||
*tb* to *file*. This differs from :func:`print_tb` in the following
|
*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
|
* if *tb* is not ``None``, it prints a header ``Traceback (most recent
|
||||||
call last):``
|
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
|
.. 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
|
format, it prints the line where the syntax error occurred with a caret
|
||||||
indicating the approximate position of the error.
|
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`.
|
The optional *limit* argument has the same meaning as for :func:`print_tb`.
|
||||||
If *chain* is true (the default), then chained exceptions (the
|
If *chain* is true (the default), then chained exceptions (the
|
||||||
:attr:`__cause__` or :attr:`__context__` attributes of the exception) will be
|
:attr:`__cause__` or :attr:`__context__` attributes of the exception) will be
|
||||||
|
@ -62,6 +67,10 @@ The module defines the following functions:
|
||||||
.. versionchanged:: 3.5
|
.. versionchanged:: 3.5
|
||||||
The *etype* argument is ignored and inferred from the type of *value*.
|
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)
|
.. function:: print_exc(limit=None, file=None, chain=True)
|
||||||
|
|
||||||
|
@ -121,18 +130,26 @@ The module defines the following functions:
|
||||||
text line is not ``None``.
|
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
|
Format the exception part of a traceback using an exception value such as
|
||||||
type and value such as given by ``sys.last_type`` and ``sys.last_value``.
|
given by ``sys.last_value``. The return value is a list of strings, each
|
||||||
The return value is a list of strings, each ending in a newline. Normally,
|
ending in a newline. Normally, the list contains a single string; however,
|
||||||
the list contains a single string; however, for :exc:`SyntaxError`
|
for :exc:`SyntaxError` exceptions, it contains several lines that (when
|
||||||
exceptions, it contains several lines that (when printed) display detailed
|
printed) display detailed information about where the syntax error occurred.
|
||||||
information about where the syntax error occurred. The message indicating
|
The message indicating which exception occurred is the always last string in
|
||||||
which exception occurred is the always last string in the list.
|
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
|
Format a stack trace and the exception information. The arguments have the
|
||||||
same meaning as the corresponding arguments to :func:`print_exception`. 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
|
.. versionchanged:: 3.5
|
||||||
The *etype* argument is ignored and inferred from the type of *value*.
|
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)
|
.. function:: format_exc(limit=None, chain=True)
|
||||||
|
|
||||||
|
|
|
@ -232,6 +232,15 @@ retrieve the functions set by :func:`threading.settrace` and
|
||||||
:func:`threading.setprofile` respectively.
|
:func:`threading.setprofile` respectively.
|
||||||
(Contributed by Mario Corchero in :issue:`42251`.)
|
(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
|
types
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -328,6 +337,15 @@ This section lists previously described changes and other bugfixes
|
||||||
that may require changes to your code.
|
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
|
Build Changes
|
||||||
=============
|
=============
|
||||||
|
|
|
@ -212,6 +212,26 @@ class TracebackCases(unittest.TestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(output.getvalue(), "Exception: projector\n")
|
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):
|
class TracebackFormatTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,19 @@ _context_message = (
|
||||||
"another exception occurred:\n\n")
|
"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'.
|
"""Print exception up to 'limit' stack trace entries from 'tb' to 'file'.
|
||||||
|
|
||||||
This differs from print_tb() in the following ways: (1) if
|
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
|
occurred with a caret on the next line indicating the approximate
|
||||||
position of the error.
|
position of the error.
|
||||||
"""
|
"""
|
||||||
# format_exception has ignored etype for some time, and code such as cgitb
|
value, tb = _parse_value_tb(exc, value, tb)
|
||||||
# passes in bogus values as a result. For compatibility with such code we
|
|
||||||
# ignore it here (rather than in the new TracebackException API).
|
|
||||||
if file is None:
|
if file is None:
|
||||||
file = sys.stderr
|
file = sys.stderr
|
||||||
for line in TracebackException(
|
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="")
|
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.
|
"""Format a stack trace and the exception information.
|
||||||
|
|
||||||
The arguments have the same meaning as the corresponding arguments
|
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
|
these lines are concatenated and printed, exactly the same text is
|
||||||
printed as does print_exception().
|
printed as does print_exception().
|
||||||
"""
|
"""
|
||||||
# format_exception has ignored etype for some time, and code such as cgitb
|
value, tb = _parse_value_tb(exc, value, tb)
|
||||||
# passes in bogus values as a result. For compatibility with such code we
|
|
||||||
# ignore it here (rather than in the new TracebackException API).
|
|
||||||
return list(TracebackException(
|
return list(TracebackException(
|
||||||
type(value), value, tb, limit=limit).format(chain=chain))
|
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.
|
"""Format the exception part of a traceback.
|
||||||
|
|
||||||
The arguments are the exception type and value such as given by
|
The return value is a list of strings, each ending in a newline.
|
||||||
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
|
Normally, the list contains a single string; however, for
|
||||||
SyntaxError exceptions, it contains several lines that (when
|
SyntaxError exceptions, it contains several lines that (when
|
||||||
|
@ -137,7 +144,10 @@ def format_exception_only(etype, value):
|
||||||
string in the list.
|
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.
|
# -- 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