@@ -469,18 +469,41 @@ 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
+ :py:meth:`~BaseException.with_traceback()` method.
478
486
479
487
:param exprinfo:
480
488
A text string helping to determine if we should strip
481
489
``AssertionError`` from the output. Defaults to the exception
482
490
message/``__str__()``.
491
+
492
+ .. versionadded:: 7.4
483
493
"""
494
+ assert (
495
+ exception .__traceback__
496
+ ), "Exceptions passed to ExcInfo.from_exception(...) must have a non-None __traceback__."
497
+ exc_info = (type (exception ), exception , exception .__traceback__ )
498
+ return cls .from_exc_info (exc_info , exprinfo )
499
+
500
+ @classmethod
501
+ def from_exc_info (
502
+ cls ,
503
+ exc_info : Tuple [Type [E ], E , TracebackType ],
504
+ exprinfo : Optional [str ] = None ,
505
+ ) -> "ExceptionInfo[E]" :
506
+ """Like :func:`from_exception`, but using old-style exc_info tuple."""
484
507
_striptext = ""
485
508
if exprinfo is None and isinstance (exc_info [1 ], AssertionError ):
486
509
exprinfo = getattr (exc_info [1 ], "msg" , None )
@@ -954,21 +977,13 @@ def repr_excinfo(
954
977
repr_chain += [(reprtraceback , reprcrash , descr )]
955
978
if e .__cause__ is not None and self .chain :
956
979
e = e .__cause__
957
- excinfo_ = (
958
- ExceptionInfo .from_exc_info ((type (e ), e , e .__traceback__ ))
959
- if e .__traceback__
960
- else None
961
- )
980
+ excinfo_ = ExceptionInfo .from_exception (e ) if e .__traceback__ else None
962
981
descr = "The above exception was the direct cause of the following exception:"
963
982
elif (
964
983
e .__context__ is not None and not e .__suppress_context__ and self .chain
965
984
):
966
985
e = e .__context__
967
- excinfo_ = (
968
- ExceptionInfo .from_exc_info ((type (e ), e , e .__traceback__ ))
969
- if e .__traceback__
970
- else None
971
- )
986
+ excinfo_ = ExceptionInfo .from_exception (e ) if e .__traceback__ else None
972
987
descr = "During handling of the above exception, another exception occurred:"
973
988
else :
974
989
e = None
0 commit comments