diff options
| author | arcadia-devtools <[email protected]> | 2022-02-09 12:00:52 +0300 |
|---|---|---|
| committer | Daniil Cherednik <[email protected]> | 2022-02-10 15:58:17 +0300 |
| commit | 8e1413fed79d1e8036e65228af6c93399ccf5502 (patch) | |
| tree | 502c9df7b2614d20541c7a2d39d390e9a51877cc /contrib/python/pytest/py3/_pytest/debugging.py | |
| parent | 6b813c17d56d1d05f92c61ddc347d0e4d358fe85 (diff) | |
intermediate changes
ref:614ed510ddd3cdf86a8c5dbf19afd113397e0172
Diffstat (limited to 'contrib/python/pytest/py3/_pytest/debugging.py')
| -rw-r--r-- | contrib/python/pytest/py3/_pytest/debugging.py | 111 |
1 files changed, 72 insertions, 39 deletions
diff --git a/contrib/python/pytest/py3/_pytest/debugging.py b/contrib/python/pytest/py3/_pytest/debugging.py index 07f212fa5e3..b52840006b0 100644 --- a/contrib/python/pytest/py3/_pytest/debugging.py +++ b/contrib/python/pytest/py3/_pytest/debugging.py @@ -1,13 +1,33 @@ -""" interactive debugging with PDB, the Python Debugger. """ +"""Interactive debugging with PDB, the Python Debugger.""" import argparse import functools import os import sys +import types +from typing import Any +from typing import Callable +from typing import Generator +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union from _pytest import outcomes +from _pytest._code import ExceptionInfo +from _pytest.config import Config from _pytest.config import ConftestImportFailure from _pytest.config import hookimpl +from _pytest.config import PytestPluginManager +from _pytest.config.argparsing import Parser from _pytest.config.exceptions import UsageError +from _pytest.nodes import Node +from _pytest.reports import BaseReport + +if TYPE_CHECKING: + from _pytest.capture import CaptureManager + from _pytest.runner import CallInfo def import_readline(): @@ -46,18 +66,18 @@ def tty(): sys.path = old_sys_path -def _validate_usepdb_cls(value): +def _validate_usepdb_cls(value: str) -> Tuple[str, str]: """Validate syntax of --pdbcls option.""" try: modname, classname = value.split(":") - except ValueError: + except ValueError as e: raise argparse.ArgumentTypeError( - "{!r} is not in the format 'modname:classname'".format(value) - ) + f"{value!r} is not in the format 'modname:classname'" + ) from e return (modname, classname) -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("general") group._addoption( "--pdb", @@ -81,7 +101,7 @@ def pytest_addoption(parser): ) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: import pdb if config.getvalue("trace"): @@ -98,7 +118,7 @@ def pytest_configure(config): # NOTE: not using pytest_unconfigure, since it might get called although # pytest_configure was not (if another plugin raises UsageError). - def fin(): + def fin() -> None: ( pdb.set_trace, pytestPDB._pluginmanager, @@ -109,22 +129,24 @@ def pytest_configure(config): class pytestPDB: - """ Pseudo PDB that defers to the real pdb. """ + """Pseudo PDB that defers to the real pdb.""" - _pluginmanager = None - _config = None - _saved = [] # type: list + _pluginmanager: Optional[PytestPluginManager] = None + _config: Optional[Config] = None + _saved: List[ + Tuple[Callable[..., None], Optional[PytestPluginManager], Optional[Config]] + ] = [] _recursive_debug = 0 - _wrapped_pdb_cls = None + _wrapped_pdb_cls: Optional[Tuple[Type[Any], Type[Any]]] = None @classmethod - def _is_capturing(cls, capman): + def _is_capturing(cls, capman: Optional["CaptureManager"]) -> Union[str, bool]: if capman: return capman.is_capturing() return False @classmethod - def _import_pdb_cls(cls, capman): + def _import_pdb_cls(cls, capman: Optional["CaptureManager"]): if not cls._config: import pdb @@ -151,8 +173,8 @@ class pytestPDB: except Exception as exc: value = ":".join((modname, classname)) raise UsageError( - "--pdbcls: could not import {!r}: {}".format(value, exc) - ) + f"--pdbcls: could not import {value!r}: {exc}" + ) from exc else: import pdb @@ -163,10 +185,12 @@ class pytestPDB: return wrapped_cls @classmethod - def _get_pdb_wrapper_class(cls, pdb_cls, capman): + def _get_pdb_wrapper_class(cls, pdb_cls, capman: Optional["CaptureManager"]): import _pytest.config - class PytestPdbWrapper(pdb_cls): + # Type ignored because mypy doesn't support "dynamic" + # inheritance like this. + class PytestPdbWrapper(pdb_cls): # type: ignore[valid-type,misc] _pytest_capman = capman _continued = False @@ -179,6 +203,7 @@ class pytestPDB: def do_continue(self, arg): ret = super().do_continue(arg) if cls._recursive_debug == 0: + assert cls._config is not None tw = _pytest.config.create_terminal_writer(cls._config) tw.line() @@ -193,9 +218,11 @@ class pytestPDB: "PDB continue (IO-capturing resumed for %s)" % capturing, ) + assert capman is not None capman.resume() else: tw.sep(">", "PDB continue") + assert cls._pluginmanager is not None cls._pluginmanager.hook.pytest_leave_pdb(config=cls._config, pdb=self) self._continued = True return ret @@ -246,13 +273,13 @@ class pytestPDB: @classmethod def _init_pdb(cls, method, *args, **kwargs): - """ Initialize PDB debugging, dropping any IO capturing. """ + """Initialize PDB debugging, dropping any IO capturing.""" import _pytest.config - if cls._pluginmanager is not None: - capman = cls._pluginmanager.getplugin("capturemanager") + if cls._pluginmanager is None: + capman: Optional[CaptureManager] = None else: - capman = None + capman = cls._pluginmanager.getplugin("capturemanager") if capman: capman.suspend(in_=True) @@ -268,7 +295,7 @@ class pytestPDB: else: capturing = cls._is_capturing(capman) if capturing == "global": - tw.sep(">", "PDB {} (IO-capturing turned off)".format(method)) + tw.sep(">", f"PDB {method} (IO-capturing turned off)") elif capturing: tw.sep( ">", @@ -276,7 +303,7 @@ class pytestPDB: % (method, capturing), ) else: - tw.sep(">", "PDB {}".format(method)) + tw.sep(">", f"PDB {method}") _pdb = cls._import_pdb_cls(capman)(**kwargs) @@ -285,7 +312,7 @@ class pytestPDB: return _pdb @classmethod - def set_trace(cls, *args, **kwargs): + def set_trace(cls, *args, **kwargs) -> None: """Invoke debugging via ``Pdb.set_trace``, dropping any IO capturing.""" tty() frame = sys._getframe().f_back @@ -294,7 +321,9 @@ class pytestPDB: class PdbInvoke: - def pytest_exception_interact(self, node, call, report): + def pytest_exception_interact( + self, node: Node, call: "CallInfo[Any]", report: BaseReport + ) -> None: capman = node.config.pluginmanager.getplugin("capturemanager") if capman: capman.suspend_global_capture(in_=True) @@ -302,31 +331,32 @@ class PdbInvoke: sys.stdout.write(out) sys.stdout.write(err) tty() + assert call.excinfo is not None _enter_pdb(node, call.excinfo, report) - def pytest_internalerror(self, excrepr, excinfo): + def pytest_internalerror(self, excinfo: ExceptionInfo[BaseException]) -> None: tb = _postmortem_traceback(excinfo) post_mortem(tb) class PdbTrace: @hookimpl(hookwrapper=True) - def pytest_pyfunc_call(self, pyfuncitem): + def pytest_pyfunc_call(self, pyfuncitem) -> Generator[None, None, None]: wrap_pytest_function_for_tracing(pyfuncitem) yield def wrap_pytest_function_for_tracing(pyfuncitem): - """Changes the python function object of the given Function item by a wrapper which actually - enters pdb before calling the python function itself, effectively leaving the user - in the pdb prompt in the first statement of the function. - """ + """Change the Python function object of the given Function item by a + wrapper which actually enters pdb before calling the python function + itself, effectively leaving the user in the pdb prompt in the first + statement of the function.""" _pdb = pytestPDB._init_pdb("runcall") testfunction = pyfuncitem.obj # we can't just return `partial(pdb.runcall, testfunction)` because (on # python < 3.7.4) runcall's first param is `func`, which means we'd get - # an exception if one of the kwargs to testfunction was called `func` + # an exception if one of the kwargs to testfunction was called `func`. @functools.wraps(testfunction) def wrapper(*args, **kwargs): func = functools.partial(testfunction, *args, **kwargs) @@ -337,12 +367,14 @@ def wrap_pytest_function_for_tracing(pyfuncitem): def maybe_wrap_pytest_function_for_tracing(pyfuncitem): """Wrap the given pytestfunct item for tracing support if --trace was given in - the command line""" + the command line.""" if pyfuncitem.config.getvalue("trace"): wrap_pytest_function_for_tracing(pyfuncitem) -def _enter_pdb(node, excinfo, rep): +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. @@ -366,12 +398,12 @@ def _enter_pdb(node, excinfo, rep): rep.toterminal(tw) tw.sep(">", "entering PDB") tb = _postmortem_traceback(excinfo) - rep._pdbshown = True + rep._pdbshown = True # type: ignore[attr-defined] post_mortem(tb) return rep -def _postmortem_traceback(excinfo): +def _postmortem_traceback(excinfo: ExceptionInfo[BaseException]) -> types.TracebackType: from doctest import UnexpectedException if isinstance(excinfo.value, UnexpectedException): @@ -383,10 +415,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): +def post_mortem(t: types.TracebackType) -> None: p = pytestPDB._init_pdb("post_mortem") p.reset() p.interaction(None, t) |
