[Python-checkins] bpo-26389: Allow passing an exception object in the traceback module (GH-22610)
pablogsal
webhook-mailer at python.org
Thu Nov 5 17:18:59 EST 2020
https://github.com/python/cpython/commit/91e93794d5dd1aa91fbe142099c2955e0c4c1660
commit: 91e93794d5dd1aa91fbe142099c2955e0c4c1660
branch: master
author: Zackery Spytz <zspytz at gmail.com>
committer: pablogsal <Pablogsal at gmail.com>
date: 2020-11-05T22:18:44Z
summary:
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 at gmail.com>
files:
A Misc/NEWS.d/next/Library/2020-10-08-23-51-55.bpo-26389.uga44e.rst
M Doc/library/traceback.rst
M Doc/whatsnew/3.10.rst
M Lib/test/test_traceback.py
M Lib/traceback.py
diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst
index 462a6a5566e20..c233f18d30a29 100644
--- a/Doc/library/traceback.rst
+++ b/Doc/library/traceback.rst
@@ -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 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.
- 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.
+ 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)
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index bac1a2e678309..0ed7084ccd2ff 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -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
=============
diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py
index 730596efd8bce..91688ff72bbea 100644
--- a/Lib/test/test_traceback.py
+++ b/Lib/test/test_traceback.py
@@ -212,6 +212,26 @@ def test_print_exception(self):
)
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):
diff --git a/Lib/traceback.py b/Lib/traceback.py
index a19e38718b120..d2d93c8a32ac2 100644
--- a/Lib/traceback.py
+++ b/Lib/traceback.py
@@ -84,7 +84,19 @@ def extract_tb(tb, limit=None):
"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.
diff --git a/Misc/NEWS.d/next/Library/2020-10-08-23-51-55.bpo-26389.uga44e.rst b/Misc/NEWS.d/next/Library/2020-10-08-23-51-55.bpo-26389.uga44e.rst
new file mode 100644
index 0000000000000..a721a0d7cd0e8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-10-08-23-51-55.bpo-26389.uga44e.rst
@@ -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.
More information about the Python-checkins
mailing list