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:
Ran Benita 2020-06-08 16:08:46 +03:00
parent 7081ed19b8
commit 0256cb3aae
8 changed files with 43 additions and 21 deletions

View File

@ -928,8 +928,13 @@ class TerminalRepr:
raise NotImplementedError()
# This class is abstract -- only subclasses are instantiated.
@attr.s(**{ATTRS_EQ_FIELD: False}) # type: ignore
class ExceptionRepr(TerminalRepr):
# Provided by in subclasses.
reprcrash = None # type: Optional[ReprFileLocation]
reprtraceback = None # type: ReprTraceback
def __attrs_post_init__(self):
self.sections = [] # type: List[Tuple[str, str, str]]

View File

@ -753,7 +753,7 @@ class CaptureManager:
self.stop_global_capturing()
@pytest.hookimpl(tryfirst=True)
def pytest_internalerror(self, excinfo):
def pytest_internalerror(self) -> None:
self.stop_global_capturing()

View File

@ -48,6 +48,7 @@ from _pytest.warning_types import PytestConfigWarning
if TYPE_CHECKING:
from typing import Type
from _pytest._code.code import _TracebackStyle
from .argparsing import Argument
@ -893,9 +894,13 @@ class Config:
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):
style = "long"
style = "long" # type: _TracebackStyle
else:
style = "native"
excrepr = excinfo.getrepr(

View File

@ -2,11 +2,13 @@
import argparse
import functools
import sys
import types
from typing import Generator
from typing import Tuple
from typing import Union
from _pytest import outcomes
from _pytest._code import ExceptionInfo
from _pytest.compat import TYPE_CHECKING
from _pytest.config import Config
from _pytest.config import ConftestImportFailure
@ -280,9 +282,10 @@ class PdbInvoke:
out, err = capman.read_global_capture()
sys.stdout.write(out)
sys.stdout.write(err)
assert call.excinfo is not None
_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)
post_mortem(tb)
@ -320,7 +323,9 @@ def maybe_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
# because this seems to avoid some encoding related troubles
# for not completely clear reasons.
@ -349,7 +354,7 @@ def _enter_pdb(node: Node, excinfo, rep: BaseReport) -> BaseReport:
return rep
def _postmortem_traceback(excinfo):
def _postmortem_traceback(excinfo: ExceptionInfo[BaseException]) -> types.TracebackType:
from doctest import UnexpectedException
if isinstance(excinfo.value, UnexpectedException):
@ -361,10 +366,11 @@ def _postmortem_traceback(excinfo):
# Use the underlying exception instead:
return excinfo.value.excinfo[2]
else:
assert excinfo._excinfo is not None
return excinfo._excinfo[2]
def post_mortem(t) -> None:
def post_mortem(t: types.TracebackType) -> None:
p = pytestPDB._init_pdb("post_mortem")
p.reset()
p.interaction(None, t)

View File

@ -19,6 +19,7 @@ if TYPE_CHECKING:
import warnings
from typing_extensions import Literal
from _pytest._code.code import ExceptionRepr
from _pytest.code import ExceptionInfo
from _pytest.config import Config
from _pytest.config import ExitCode
@ -759,8 +760,14 @@ def pytest_doctest_prepare_content(content):
# -------------------------------------------------------------------------
def pytest_internalerror(excrepr, excinfo):
""" called for internal errors. """
def pytest_internalerror(
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(

View File

@ -26,6 +26,7 @@ import pytest
from _pytest import deprecated
from _pytest import nodes
from _pytest import timing
from _pytest._code.code import ExceptionRepr
from _pytest.compat import TYPE_CHECKING
from _pytest.config import Config
from _pytest.config import filename_arg
@ -642,7 +643,7 @@ class LogXML:
else:
reporter.append_collect_skipped(report)
def pytest_internalerror(self, excrepr) -> None:
def pytest_internalerror(self, excrepr: ExceptionRepr) -> None:
reporter = self.node_reporter("internal")
reporter.attrs.update(classname="pytest", name="internal")
reporter._add_simple(Junit.error, "internal error", excrepr)

View File

@ -5,6 +5,7 @@ import os
import py
from _pytest._code.code import ExceptionRepr
from _pytest.config import Config
from _pytest.config.argparsing import Parser
from _pytest.reports import CollectReport
@ -99,9 +100,9 @@ class ResultLog:
longrepr = "%s:%d: %s" % report.longrepr # type: ignore
self.log_outcome(report, code, longrepr)
def pytest_internalerror(self, excrepr):
reprcrash = getattr(excrepr, "reprcrash", None)
path = getattr(reprcrash, "path", None)
if path is None:
def pytest_internalerror(self, excrepr: ExceptionRepr) -> None:
if excrepr.reprcrash is not None:
path = excrepr.reprcrash.path
else:
path = "cwd:%s" % py.path.local()
self.write_log_entry(path, "!", str(excrepr))

View File

@ -31,8 +31,7 @@ import pytest
from _pytest import nodes
from _pytest import timing
from _pytest._code import ExceptionInfo
from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ReprExceptionInfo
from _pytest._code.code import ExceptionRepr
from _pytest._io import TerminalWriter
from _pytest._io.wcwidth import wcswidth
from _pytest.compat import order_preserving_dict
@ -318,9 +317,7 @@ class TerminalReporter:
self._show_progress_info = self._determine_show_progress_info()
self._collect_report_last_write = None # type: Optional[float]
self._already_displayed_warnings = None # type: Optional[int]
self._keyboardinterrupt_memo = (
None
) # type: Optional[Union[ReprExceptionInfo, ExceptionChainRepr]]
self._keyboardinterrupt_memo = None # type: Optional[ExceptionRepr]
@property
def writer(self) -> TerminalWriter:
@ -454,10 +451,10 @@ class TerminalReporter:
if 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"):
self.write_line("INTERNALERROR> " + line)
return 1
return True
def pytest_warning_recorded(
self, warning_message: warnings.WarningMessage, nodeid: str,