From c6e16cef04255d5cc77ff95744d453a96a4c4803 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 24 May 2019 18:10:05 +0200 Subject: [PATCH] pdb: import pdbcls lazily Fixes https://github.com/pytest-dev/pytest/issues/2064. --- src/_pytest/debugging.py | 61 +++++++++++++++++++++------------------- testing/test_pdb.py | 7 +++-- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/_pytest/debugging.py b/src/_pytest/debugging.py index 3605490e67e..0bbb34f34e7 100644 --- a/src/_pytest/debugging.py +++ b/src/_pytest/debugging.py @@ -49,42 +49,18 @@ def pytest_addoption(parser): ) -def _import_pdbcls(modname, classname): - try: - __import__(modname) - mod = sys.modules[modname] - - # Handle --pdbcls=pdb:pdb.Pdb (useful e.g. with pdbpp). - parts = classname.split(".") - pdb_cls = getattr(mod, parts[0]) - for part in parts[1:]: - pdb_cls = getattr(pdb_cls, part) - - return pdb_cls - except Exception as exc: - value = ":".join((modname, classname)) - raise UsageError("--pdbcls: could not import {!r}: {}".format(value, exc)) - - def pytest_configure(config): - pdb_cls = config.getvalue("usepdb_cls") - if pdb_cls: - pdb_cls = _import_pdbcls(*pdb_cls) - else: - pdb_cls = pdb.Pdb - if config.getvalue("trace"): config.pluginmanager.register(PdbTrace(), "pdbtrace") if config.getvalue("usepdb"): config.pluginmanager.register(PdbInvoke(), "pdbinvoke") pytestPDB._saved.append( - (pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config, pytestPDB._pdb_cls) + (pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config) ) pdb.set_trace = pytestPDB.set_trace pytestPDB._pluginmanager = config.pluginmanager pytestPDB._config = config - pytestPDB._pdb_cls = pdb_cls # NOTE: not using pytest_unconfigure, since it might get called although # pytest_configure was not (if another plugin raises UsageError). @@ -93,7 +69,6 @@ def fin(): pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config, - pytestPDB._pdb_cls, ) = pytestPDB._saved.pop() config._cleanup.append(fin) @@ -104,7 +79,6 @@ class pytestPDB(object): _pluginmanager = None _config = None - _pdb_cls = pdb.Pdb _saved = [] _recursive_debug = 0 @@ -114,6 +88,32 @@ def _is_capturing(cls, capman): return capman.is_capturing() return False + @classmethod + def _import_pdb_cls(cls): + if cls._config: + pdb_cls = cls._config.getvalue("usepdb_cls") + if pdb_cls: + modname, classname = pdb_cls + + try: + __import__(modname) + mod = sys.modules[modname] + + # Handle --pdbcls=pdb:pdb.Pdb (useful e.g. with pdbpp). + parts = classname.split(".") + pdb_cls = getattr(mod, parts[0]) + for part in parts[1:]: + pdb_cls = getattr(pdb_cls, part) + + return pdb_cls + except Exception as exc: + value = ":".join((modname, classname)) + raise UsageError( + "--pdbcls: could not import {!r}: {}".format(value, exc) + ) + + return pdb.Pdb + @classmethod def _init_pdb(cls, *args, **kwargs): """ Initialize PDB debugging, dropping any IO capturing. """ @@ -144,7 +144,9 @@ def _init_pdb(cls, *args, **kwargs): else: tw.sep(">", "PDB set_trace") - class PytestPdbWrapper(cls._pdb_cls, object): + pdb_cls = cls._import_pdb_cls() + + class PytestPdbWrapper(pdb_cls, object): _pytest_capman = capman _continued = False @@ -227,7 +229,8 @@ def get_stack(self, f, t): _pdb = PytestPdbWrapper(**kwargs) cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config, pdb=_pdb) else: - _pdb = cls._pdb_cls(**kwargs) + pdb_cls = cls._import_pdb_cls() + _pdb = pdb_cls(**kwargs) return _pdb @classmethod diff --git a/testing/test_pdb.py b/testing/test_pdb.py index 4b084a26a75..007423a9e2c 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -1157,12 +1157,13 @@ def runcall(self, *args, **kwds): result = testdir.runpytest( str(p1), "--pdbcls=really.invalid:Value", syspathinsert=True ) - result.stderr.fnmatch_lines( + result.stdout.fnmatch_lines( [ - "ERROR: --pdbcls: could not import 'really.invalid:Value': No module named *really*" + "*= FAILURES =*", + "E * --pdbcls: could not import 'really.invalid:Value': No module named *really*", ] ) - assert result.ret == 4 + assert result.ret == 1 result = testdir.runpytest( str(p1), "--pdbcls=mypdb:Wrapped.MyPdb", syspathinsert=True