Skip to content

Commit

Permalink
pdb: try to import --pdbcls in pytest_configure only
Browse files Browse the repository at this point in the history
  • Loading branch information
blueyed committed Apr 3, 2019
1 parent 46df1d5 commit 9a60d45
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 17 deletions.
1 change: 1 addition & 0 deletions changelog/5039.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix regression with ``--pdbcls``, which stopped working with local modules in 4.0.0.
40 changes: 23 additions & 17 deletions src/_pytest/debugging.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,18 @@

from _pytest import outcomes
from _pytest.config import hookimpl
from _pytest.config.exceptions import UsageError


def _validate_usepdb_cls(value):
"""Validate syntax of --pdbcls option."""
try:
modname, classname = value.split(":")
except ValueError:
raise argparse.ArgumentTypeError(
"{!r} is not in the format 'modname:classname'".format(value)
)

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:
raise argparse.ArgumentTypeError(
"could not get pdb class for {!r}: {}".format(value, exc)
)
return (modname, classname)


def pytest_addoption(parser):
Expand All @@ -61,9 +48,28 @@ 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 not pdb_cls:
if pdb_cls:
pdb_cls = _import_pdbcls(*pdb_cls)
else:
pdb_cls = pdb.Pdb

if config.getvalue("trace"):
Expand Down
29 changes: 29 additions & 0 deletions testing/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,3 +1121,32 @@ def test_inner({fixture}):
assert child.exitstatus == 0
assert "= 1 passed in " in rest
assert "> PDB continue (IO-capturing resumed for fixture %s) >" % (fixture) in rest


def test_pdbcls_via_local_module(testdir):
"""It should be imported in pytest_configure or later only."""
p1 = testdir.makepyfile(
"""
def test():
print("before_settrace")
__import__("pdb").set_trace()
""",
mypdb="""
class MyPdb:
def set_trace(self, *args):
print("mypdb_called", args)
""",
)
result = testdir.runpytest(
str(p1), "--pdbcls=really.invalid:Value", syspathinsert=True
)
result.stderr.fnmatch_lines(
[
"ERROR: --pdbcls: could not import 'really.invalid:Value': No module named 'really'"
]
)
assert result.ret == 4

result = testdir.runpytest(str(p1), "--pdbcls=mypdb:MyPdb", syspathinsert=True)
assert result.ret == 0
result.stdout.fnmatch_lines(["mypdb_called *", "* 1 passed in *"])

0 comments on commit 9a60d45

Please sign in to comment.