Skip to content

Commit e191c95

Browse files
committed
pdb: import pdbcls lazily
Fixes #2064.
1 parent e393a73 commit e191c95

File tree

3 files changed

+37
-32
lines changed

3 files changed

+37
-32
lines changed

changelog/2064.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The debugging plugin imports the wrapped ``Pdb`` class (``--pdbcls``) on-demand now.

src/_pytest/debugging.py

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -49,42 +49,18 @@ def pytest_addoption(parser):
4949
)
5050

5151

52-
def _import_pdbcls(modname, classname):
53-
try:
54-
__import__(modname)
55-
mod = sys.modules[modname]
56-
57-
# Handle --pdbcls=pdb:pdb.Pdb (useful e.g. with pdbpp).
58-
parts = classname.split(".")
59-
pdb_cls = getattr(mod, parts[0])
60-
for part in parts[1:]:
61-
pdb_cls = getattr(pdb_cls, part)
62-
63-
return pdb_cls
64-
except Exception as exc:
65-
value = ":".join((modname, classname))
66-
raise UsageError("--pdbcls: could not import {!r}: {}".format(value, exc))
67-
68-
6952
def pytest_configure(config):
70-
pdb_cls = config.getvalue("usepdb_cls")
71-
if pdb_cls:
72-
pdb_cls = _import_pdbcls(*pdb_cls)
73-
else:
74-
pdb_cls = pdb.Pdb
75-
7653
if config.getvalue("trace"):
7754
config.pluginmanager.register(PdbTrace(), "pdbtrace")
7855
if config.getvalue("usepdb"):
7956
config.pluginmanager.register(PdbInvoke(), "pdbinvoke")
8057

8158
pytestPDB._saved.append(
82-
(pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config, pytestPDB._pdb_cls)
59+
(pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config)
8360
)
8461
pdb.set_trace = pytestPDB.set_trace
8562
pytestPDB._pluginmanager = config.pluginmanager
8663
pytestPDB._config = config
87-
pytestPDB._pdb_cls = pdb_cls
8864

8965
# NOTE: not using pytest_unconfigure, since it might get called although
9066
# pytest_configure was not (if another plugin raises UsageError).
@@ -93,7 +69,6 @@ def fin():
9369
pdb.set_trace,
9470
pytestPDB._pluginmanager,
9571
pytestPDB._config,
96-
pytestPDB._pdb_cls,
9772
) = pytestPDB._saved.pop()
9873

9974
config._cleanup.append(fin)
@@ -104,7 +79,6 @@ class pytestPDB(object):
10479

10580
_pluginmanager = None
10681
_config = None
107-
_pdb_cls = pdb.Pdb
10882
_saved = []
10983
_recursive_debug = 0
11084

@@ -114,6 +88,32 @@ def _is_capturing(cls, capman):
11488
return capman.is_capturing()
11589
return False
11690

91+
@classmethod
92+
def _import_pdb_cls(cls):
93+
if cls._config:
94+
pdb_cls = cls._config.getvalue("usepdb_cls")
95+
if pdb_cls:
96+
modname, classname = pdb_cls
97+
98+
try:
99+
__import__(modname)
100+
mod = sys.modules[modname]
101+
102+
# Handle --pdbcls=pdb:pdb.Pdb (useful e.g. with pdbpp).
103+
parts = classname.split(".")
104+
pdb_cls = getattr(mod, parts[0])
105+
for part in parts[1:]:
106+
pdb_cls = getattr(pdb_cls, part)
107+
108+
return pdb_cls
109+
except Exception as exc:
110+
value = ":".join((modname, classname))
111+
raise UsageError(
112+
"--pdbcls: could not import {!r}: {}".format(value, exc)
113+
)
114+
115+
return pdb.Pdb
116+
117117
@classmethod
118118
def _init_pdb(cls, *args, **kwargs):
119119
""" Initialize PDB debugging, dropping any IO capturing. """
@@ -144,7 +144,9 @@ def _init_pdb(cls, *args, **kwargs):
144144
else:
145145
tw.sep(">", "PDB set_trace")
146146

147-
class PytestPdbWrapper(cls._pdb_cls, object):
147+
pdb_cls = cls._import_pdb_cls()
148+
149+
class PytestPdbWrapper(pdb_cls, object):
148150
_pytest_capman = capman
149151
_continued = False
150152

@@ -227,7 +229,8 @@ def get_stack(self, f, t):
227229
_pdb = PytestPdbWrapper(**kwargs)
228230
cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config, pdb=_pdb)
229231
else:
230-
_pdb = cls._pdb_cls(**kwargs)
232+
pdb_cls = cls._import_pdb_cls()
233+
_pdb = pdb_cls(**kwargs)
231234
return _pdb
232235

233236
@classmethod

testing/test_pdb.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,12 +1157,13 @@ def runcall(self, *args, **kwds):
11571157
result = testdir.runpytest(
11581158
str(p1), "--pdbcls=really.invalid:Value", syspathinsert=True
11591159
)
1160-
result.stderr.fnmatch_lines(
1160+
result.stdout.fnmatch_lines(
11611161
[
1162-
"ERROR: --pdbcls: could not import 'really.invalid:Value': No module named *really*"
1162+
"*= FAILURES =*",
1163+
"E * --pdbcls: could not import 'really.invalid:Value': No module named *really*",
11631164
]
11641165
)
1165-
assert result.ret == 4
1166+
assert result.ret == 1
11661167

11671168
result = testdir.runpytest(
11681169
str(p1), "--pdbcls=mypdb:Wrapped.MyPdb", syspathinsert=True

0 commit comments

Comments
 (0)