hookspec: type annotate pytest_internalerror
Also switch to using ExceptionRepr instead of `Union[ReprExceptionInfo, ExceptionChainRepr]` which is somewhat annoying and less future proof.
This commit is contained in:
parent
7081ed19b8
commit
0256cb3aae
|
@ -928,8 +928,13 @@ class TerminalRepr:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
# This class is abstract -- only subclasses are instantiated.
|
||||||
@attr.s(**{ATTRS_EQ_FIELD: False}) # type: ignore
|
@attr.s(**{ATTRS_EQ_FIELD: False}) # type: ignore
|
||||||
class ExceptionRepr(TerminalRepr):
|
class ExceptionRepr(TerminalRepr):
|
||||||
|
# Provided by in subclasses.
|
||||||
|
reprcrash = None # type: Optional[ReprFileLocation]
|
||||||
|
reprtraceback = None # type: ReprTraceback
|
||||||
|
|
||||||
def __attrs_post_init__(self):
|
def __attrs_post_init__(self):
|
||||||
self.sections = [] # type: List[Tuple[str, str, str]]
|
self.sections = [] # type: List[Tuple[str, str, str]]
|
||||||
|
|
||||||
|
|
|
@ -753,7 +753,7 @@ class CaptureManager:
|
||||||
self.stop_global_capturing()
|
self.stop_global_capturing()
|
||||||
|
|
||||||
@pytest.hookimpl(tryfirst=True)
|
@pytest.hookimpl(tryfirst=True)
|
||||||
def pytest_internalerror(self, excinfo):
|
def pytest_internalerror(self) -> None:
|
||||||
self.stop_global_capturing()
|
self.stop_global_capturing()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ from _pytest.warning_types import PytestConfigWarning
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
from _pytest._code.code import _TracebackStyle
|
||||||
from .argparsing import Argument
|
from .argparsing import Argument
|
||||||
|
|
||||||
|
|
||||||
|
@ -893,9 +894,13 @@ class Config:
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def notify_exception(self, excinfo, option=None):
|
def notify_exception(
|
||||||
|
self,
|
||||||
|
excinfo: ExceptionInfo[BaseException],
|
||||||
|
option: Optional[argparse.Namespace] = None,
|
||||||
|
) -> None:
|
||||||
if option and getattr(option, "fulltrace", False):
|
if option and getattr(option, "fulltrace", False):
|
||||||
style = "long"
|
style = "long" # type: _TracebackStyle
|
||||||
else:
|
else:
|
||||||
style = "native"
|
style = "native"
|
||||||
excrepr = excinfo.getrepr(
|
excrepr = excinfo.getrepr(
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
import argparse
|
import argparse
|
||||||
import functools
|
import functools
|
||||||
import sys
|
import sys
|
||||||
|
import types
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from _pytest import outcomes
|
from _pytest import outcomes
|
||||||
|
from _pytest._code import ExceptionInfo
|
||||||
from _pytest.compat import TYPE_CHECKING
|
from _pytest.compat import TYPE_CHECKING
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import ConftestImportFailure
|
from _pytest.config import ConftestImportFailure
|
||||||
|
@ -280,9 +282,10 @@ class PdbInvoke:
|
||||||
out, err = capman.read_global_capture()
|
out, err = capman.read_global_capture()
|
||||||
sys.stdout.write(out)
|
sys.stdout.write(out)
|
||||||
sys.stdout.write(err)
|
sys.stdout.write(err)
|
||||||
|
assert call.excinfo is not None
|
||||||
_enter_pdb(node, call.excinfo, report)
|
_enter_pdb(node, call.excinfo, report)
|
||||||
|
|
||||||
def pytest_internalerror(self, excrepr, excinfo) -> None:
|
def pytest_internalerror(self, excinfo: ExceptionInfo[BaseException]) -> None:
|
||||||
tb = _postmortem_traceback(excinfo)
|
tb = _postmortem_traceback(excinfo)
|
||||||
post_mortem(tb)
|
post_mortem(tb)
|
||||||
|
|
||||||
|
@ -320,7 +323,9 @@ def maybe_wrap_pytest_function_for_tracing(pyfuncitem):
|
||||||
wrap_pytest_function_for_tracing(pyfuncitem)
|
wrap_pytest_function_for_tracing(pyfuncitem)
|
||||||
|
|
||||||
|
|
||||||
def _enter_pdb(node: Node, excinfo, rep: BaseReport) -> BaseReport:
|
def _enter_pdb(
|
||||||
|
node: Node, excinfo: ExceptionInfo[BaseException], rep: BaseReport
|
||||||
|
) -> BaseReport:
|
||||||
# XXX we re-use the TerminalReporter's terminalwriter
|
# XXX we re-use the TerminalReporter's terminalwriter
|
||||||
# because this seems to avoid some encoding related troubles
|
# because this seems to avoid some encoding related troubles
|
||||||
# for not completely clear reasons.
|
# for not completely clear reasons.
|
||||||
|
@ -349,7 +354,7 @@ def _enter_pdb(node: Node, excinfo, rep: BaseReport) -> BaseReport:
|
||||||
return rep
|
return rep
|
||||||
|
|
||||||
|
|
||||||
def _postmortem_traceback(excinfo):
|
def _postmortem_traceback(excinfo: ExceptionInfo[BaseException]) -> types.TracebackType:
|
||||||
from doctest import UnexpectedException
|
from doctest import UnexpectedException
|
||||||
|
|
||||||
if isinstance(excinfo.value, UnexpectedException):
|
if isinstance(excinfo.value, UnexpectedException):
|
||||||
|
@ -361,10 +366,11 @@ def _postmortem_traceback(excinfo):
|
||||||
# Use the underlying exception instead:
|
# Use the underlying exception instead:
|
||||||
return excinfo.value.excinfo[2]
|
return excinfo.value.excinfo[2]
|
||||||
else:
|
else:
|
||||||
|
assert excinfo._excinfo is not None
|
||||||
return excinfo._excinfo[2]
|
return excinfo._excinfo[2]
|
||||||
|
|
||||||
|
|
||||||
def post_mortem(t) -> None:
|
def post_mortem(t: types.TracebackType) -> None:
|
||||||
p = pytestPDB._init_pdb("post_mortem")
|
p = pytestPDB._init_pdb("post_mortem")
|
||||||
p.reset()
|
p.reset()
|
||||||
p.interaction(None, t)
|
p.interaction(None, t)
|
||||||
|
|
|
@ -19,6 +19,7 @@ if TYPE_CHECKING:
|
||||||
import warnings
|
import warnings
|
||||||
from typing_extensions import Literal
|
from typing_extensions import Literal
|
||||||
|
|
||||||
|
from _pytest._code.code import ExceptionRepr
|
||||||
from _pytest.code import ExceptionInfo
|
from _pytest.code import ExceptionInfo
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
|
@ -759,8 +760,14 @@ def pytest_doctest_prepare_content(content):
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def pytest_internalerror(excrepr, excinfo):
|
def pytest_internalerror(
|
||||||
""" called for internal errors. """
|
excrepr: "ExceptionRepr", excinfo: "ExceptionInfo[BaseException]",
|
||||||
|
) -> Optional[bool]:
|
||||||
|
"""Called for internal errors.
|
||||||
|
|
||||||
|
Return True to suppress the fallback handling of printing an
|
||||||
|
INTERNALERROR message directly to sys.stderr.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def pytest_keyboard_interrupt(
|
def pytest_keyboard_interrupt(
|
||||||
|
|
|
@ -26,6 +26,7 @@ import pytest
|
||||||
from _pytest import deprecated
|
from _pytest import deprecated
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
from _pytest import timing
|
from _pytest import timing
|
||||||
|
from _pytest._code.code import ExceptionRepr
|
||||||
from _pytest.compat import TYPE_CHECKING
|
from _pytest.compat import TYPE_CHECKING
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import filename_arg
|
from _pytest.config import filename_arg
|
||||||
|
@ -642,7 +643,7 @@ class LogXML:
|
||||||
else:
|
else:
|
||||||
reporter.append_collect_skipped(report)
|
reporter.append_collect_skipped(report)
|
||||||
|
|
||||||
def pytest_internalerror(self, excrepr) -> None:
|
def pytest_internalerror(self, excrepr: ExceptionRepr) -> None:
|
||||||
reporter = self.node_reporter("internal")
|
reporter = self.node_reporter("internal")
|
||||||
reporter.attrs.update(classname="pytest", name="internal")
|
reporter.attrs.update(classname="pytest", name="internal")
|
||||||
reporter._add_simple(Junit.error, "internal error", excrepr)
|
reporter._add_simple(Junit.error, "internal error", excrepr)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import os
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
|
||||||
|
from _pytest._code.code import ExceptionRepr
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config.argparsing import Parser
|
from _pytest.config.argparsing import Parser
|
||||||
from _pytest.reports import CollectReport
|
from _pytest.reports import CollectReport
|
||||||
|
@ -99,9 +100,9 @@ class ResultLog:
|
||||||
longrepr = "%s:%d: %s" % report.longrepr # type: ignore
|
longrepr = "%s:%d: %s" % report.longrepr # type: ignore
|
||||||
self.log_outcome(report, code, longrepr)
|
self.log_outcome(report, code, longrepr)
|
||||||
|
|
||||||
def pytest_internalerror(self, excrepr):
|
def pytest_internalerror(self, excrepr: ExceptionRepr) -> None:
|
||||||
reprcrash = getattr(excrepr, "reprcrash", None)
|
if excrepr.reprcrash is not None:
|
||||||
path = getattr(reprcrash, "path", None)
|
path = excrepr.reprcrash.path
|
||||||
if path is None:
|
else:
|
||||||
path = "cwd:%s" % py.path.local()
|
path = "cwd:%s" % py.path.local()
|
||||||
self.write_log_entry(path, "!", str(excrepr))
|
self.write_log_entry(path, "!", str(excrepr))
|
||||||
|
|
|
@ -31,8 +31,7 @@ import pytest
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
from _pytest import timing
|
from _pytest import timing
|
||||||
from _pytest._code import ExceptionInfo
|
from _pytest._code import ExceptionInfo
|
||||||
from _pytest._code.code import ExceptionChainRepr
|
from _pytest._code.code import ExceptionRepr
|
||||||
from _pytest._code.code import ReprExceptionInfo
|
|
||||||
from _pytest._io import TerminalWriter
|
from _pytest._io import TerminalWriter
|
||||||
from _pytest._io.wcwidth import wcswidth
|
from _pytest._io.wcwidth import wcswidth
|
||||||
from _pytest.compat import order_preserving_dict
|
from _pytest.compat import order_preserving_dict
|
||||||
|
@ -318,9 +317,7 @@ class TerminalReporter:
|
||||||
self._show_progress_info = self._determine_show_progress_info()
|
self._show_progress_info = self._determine_show_progress_info()
|
||||||
self._collect_report_last_write = None # type: Optional[float]
|
self._collect_report_last_write = None # type: Optional[float]
|
||||||
self._already_displayed_warnings = None # type: Optional[int]
|
self._already_displayed_warnings = None # type: Optional[int]
|
||||||
self._keyboardinterrupt_memo = (
|
self._keyboardinterrupt_memo = None # type: Optional[ExceptionRepr]
|
||||||
None
|
|
||||||
) # type: Optional[Union[ReprExceptionInfo, ExceptionChainRepr]]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def writer(self) -> TerminalWriter:
|
def writer(self) -> TerminalWriter:
|
||||||
|
@ -454,10 +451,10 @@ class TerminalReporter:
|
||||||
if set_main_color:
|
if set_main_color:
|
||||||
self._set_main_color()
|
self._set_main_color()
|
||||||
|
|
||||||
def pytest_internalerror(self, excrepr):
|
def pytest_internalerror(self, excrepr: ExceptionRepr) -> bool:
|
||||||
for line in str(excrepr).split("\n"):
|
for line in str(excrepr).split("\n"):
|
||||||
self.write_line("INTERNALERROR> " + line)
|
self.write_line("INTERNALERROR> " + line)
|
||||||
return 1
|
return True
|
||||||
|
|
||||||
def pytest_warning_recorded(
|
def pytest_warning_recorded(
|
||||||
self, warning_message: warnings.WarningMessage, nodeid: str,
|
self, warning_message: warnings.WarningMessage, nodeid: str,
|
||||||
|
|
Loading…
Reference in New Issue