Skip to content

Commit b549438

Browse files
authored
Merge pull request #5058 from blueyed/merge-master-into-features
Merge master into features
2 parents 87ce586 + 3778881 commit b549438

File tree

3 files changed

+61
-24
lines changed

3 files changed

+61
-24
lines changed

changelog/5039.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix regression with ``--pdbcls``, which stopped working with local modules in 4.0.0.

src/_pytest/debugging.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,18 @@
1010

1111
from _pytest import outcomes
1212
from _pytest.config import hookimpl
13+
from _pytest.config.exceptions import UsageError
1314

1415

1516
def _validate_usepdb_cls(value):
17+
"""Validate syntax of --pdbcls option."""
1618
try:
1719
modname, classname = value.split(":")
1820
except ValueError:
1921
raise argparse.ArgumentTypeError(
2022
"{!r} is not in the format 'modname:classname'".format(value)
2123
)
22-
23-
try:
24-
__import__(modname)
25-
mod = sys.modules[modname]
26-
27-
# Handle --pdbcls=pdb:pdb.Pdb (useful e.g. with pdbpp).
28-
parts = classname.split(".")
29-
pdb_cls = getattr(mod, parts[0])
30-
for part in parts[1:]:
31-
pdb_cls = getattr(pdb_cls, part)
32-
33-
return pdb_cls
34-
except Exception as exc:
35-
raise argparse.ArgumentTypeError(
36-
"could not get pdb class for {!r}: {}".format(value, exc)
37-
)
24+
return (modname, classname)
3825

3926

4027
def pytest_addoption(parser):
@@ -68,9 +55,28 @@ def pytest_addoption(parser):
6855
)
6956

7057

58+
def _import_pdbcls(modname, classname):
59+
try:
60+
__import__(modname)
61+
mod = sys.modules[modname]
62+
63+
# Handle --pdbcls=pdb:pdb.Pdb (useful e.g. with pdbpp).
64+
parts = classname.split(".")
65+
pdb_cls = getattr(mod, parts[0])
66+
for part in parts[1:]:
67+
pdb_cls = getattr(pdb_cls, part)
68+
69+
return pdb_cls
70+
except Exception as exc:
71+
value = ":".join((modname, classname))
72+
raise UsageError("--pdbcls: could not import {!r}: {}".format(value, exc))
73+
74+
7175
def pytest_configure(config):
7276
pdb_cls = config.getvalue("usepdb_cls")
73-
if not pdb_cls:
77+
if pdb_cls:
78+
pdb_cls = _import_pdbcls(*pdb_cls)
79+
else:
7480
pdb_cls = pdb.Pdb
7581

7682
if config.getvalue("trace"):

testing/test_pdb.py

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from __future__ import division
33
from __future__ import print_function
44

5-
import argparse
65
import os
76
import platform
87
import sys
@@ -804,13 +803,12 @@ def test_pdb_custom_cls_invalid(self, testdir):
804803
)
805804

806805
def test_pdb_validate_usepdb_cls(self, testdir):
807-
assert _validate_usepdb_cls("os.path:dirname.__name__") == "dirname"
806+
assert _validate_usepdb_cls("os.path:dirname.__name__") == (
807+
"os.path",
808+
"dirname.__name__",
809+
)
808810

809-
with pytest.raises(
810-
argparse.ArgumentTypeError,
811-
match=r"^could not get pdb class for 'pdb:DoesNotExist': .*'DoesNotExist'",
812-
):
813-
_validate_usepdb_cls("pdb:DoesNotExist")
811+
assert _validate_usepdb_cls("pdb:DoesNotExist") == ("pdb", "DoesNotExist")
814812

815813
def test_pdb_custom_cls_without_pdb(self, testdir, custom_pdb_calls):
816814
p1 = testdir.makepyfile("""xxx """)
@@ -1136,3 +1134,35 @@ def test_pdb_skip_option(testdir):
11361134
result = testdir.runpytest_inprocess("--pdb-ignore-set_trace", "-s", p)
11371135
assert result.ret == EXIT_NOTESTSCOLLECTED
11381136
result.stdout.fnmatch_lines(["*before_set_trace*", "*after_set_trace*"])
1137+
1138+
1139+
def test_pdbcls_via_local_module(testdir):
1140+
"""It should be imported in pytest_configure or later only."""
1141+
p1 = testdir.makepyfile(
1142+
"""
1143+
def test():
1144+
print("before_settrace")
1145+
__import__("pdb").set_trace()
1146+
""",
1147+
mypdb="""
1148+
class Wrapped:
1149+
class MyPdb:
1150+
def set_trace(self, *args):
1151+
print("mypdb_called", args)
1152+
""",
1153+
)
1154+
result = testdir.runpytest(
1155+
str(p1), "--pdbcls=really.invalid:Value", syspathinsert=True
1156+
)
1157+
result.stderr.fnmatch_lines(
1158+
[
1159+
"ERROR: --pdbcls: could not import 'really.invalid:Value': No module named *really*"
1160+
]
1161+
)
1162+
assert result.ret == 4
1163+
1164+
result = testdir.runpytest(
1165+
str(p1), "--pdbcls=mypdb:Wrapped.MyPdb", syspathinsert=True
1166+
)
1167+
assert result.ret == 0
1168+
result.stdout.fnmatch_lines(["*mypdb_called*", "* 1 passed in *"])

0 commit comments

Comments
 (0)