diff options
author | Zackery Spytz <zspytz@gmail.com> | 2020-11-05 22:18:44 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-05 22:18:44 (GMT) |
commit | 91e93794d5dd1aa91fbe142099c2955e0c4c1660 (patch) | |
tree | df0294cde2ffeabdb5fcbdc2107712fe1fd2b117 /Lib | |
parent | dc42af8fd16b10127ce1fc93c13bc1bfd2674aa2 (diff) | |
download | cpython-91e93794d5dd1aa91fbe142099c2955e0c4c1660.zip cpython-91e93794d5dd1aa91fbe142099c2955e0c4c1660.tar.gz cpython-91e93794d5dd1aa91fbe142099c2955e0c4c1660.tar.bz2 |
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>
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_traceback.py | 20 | ||||
-rw-r--r-- | Lib/traceback.py | 36 |
2 files changed, 43 insertions, 13 deletions
diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 730596e..91688ff 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -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): diff --git a/Lib/traceback.py b/Lib/traceback.py index a19e387..d2d93c8 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -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. |