@@ -469,12 +469,20 @@ def __init__(
469
469
self ._traceback = traceback
470
470
471
471
@classmethod
472
- def from_exc_info (
472
+ def from_exception (
473
473
cls ,
474
- exc_info : Tuple [Type [E ], E , TracebackType ],
474
+ # Ignoring error: "Cannot use a covariant type variable as a parameter".
475
+ # This is OK to ignore because this class is (conceptually) readonly.
476
+ # See https://github.com/python/mypy/issues/7049.
477
+ exception : E , # type: ignore[misc]
475
478
exprinfo : Optional [str ] = None ,
476
479
) -> "ExceptionInfo[E]" :
477
- """Return an ExceptionInfo for an existing exc_info tuple.
480
+ """Return an ExceptionInfo for an existing exception.
481
+
482
+ The exception must have a non-``None`` ``__traceback__`` attribute,
483
+ otherwise this function fails with an assertion error. This means that
484
+ the exception must have been raised, or added a traceback with the
485
+ :func:`BaseException.with_traceback()` method.
478
486
479
487
.. warning::
480
488
@@ -484,7 +492,22 @@ def from_exc_info(
484
492
A text string helping to determine if we should strip
485
493
``AssertionError`` from the output. Defaults to the exception
486
494
message/``__str__()``.
495
+
496
+ .. versionadded:: 7.4
487
497
"""
498
+ assert (
499
+ exception .__traceback__
500
+ ), "Exceptions passed to ExcInfo.from_exception(...) must have a non-None __traceback__."
501
+ exc_info = (type (exception ), exception , exception .__traceback__ )
502
+ return cls .from_exc_info (exc_info , exprinfo )
503
+
504
+ @classmethod
505
+ def from_exc_info (
506
+ cls ,
507
+ exc_info : Tuple [Type [E ], E , TracebackType ],
508
+ exprinfo : Optional [str ] = None ,
509
+ ) -> "ExceptionInfo[E]" :
510
+ """Like :func:`from_exception`, but using old-style exc_info tuple."""
488
511
_striptext = ""
489
512
if exprinfo is None and isinstance (exc_info [1 ], AssertionError ):
490
513
exprinfo = getattr (exc_info [1 ], "msg" , None )
@@ -965,21 +988,13 @@ def repr_excinfo(
965
988
966
989
if e .__cause__ is not None and self .chain :
967
990
e = e .__cause__
968
- excinfo_ = (
969
- ExceptionInfo .from_exc_info ((type (e ), e , e .__traceback__ ))
970
- if e .__traceback__
971
- else None
972
- )
991
+ excinfo_ = ExceptionInfo .from_exception (e ) if e .__traceback__ else None
973
992
descr = "The above exception was the direct cause of the following exception:"
974
993
elif (
975
994
e .__context__ is not None and not e .__suppress_context__ and self .chain
976
995
):
977
996
e = e .__context__
978
- excinfo_ = (
979
- ExceptionInfo .from_exc_info ((type (e ), e , e .__traceback__ ))
980
- if e .__traceback__
981
- else None
982
- )
997
+ excinfo_ = ExceptionInfo .from_exception (e ) if e .__traceback__ else None
983
998
descr = "During handling of the above exception, another exception occurred:"
984
999
else :
985
1000
e = None
0 commit comments