pdb: allow for --pdbclass=mod:attr.class

This commit is contained in:
Daniel Hahler 2019-02-28 18:10:57 +01:00
parent a868a9ac13
commit f7a3e001f7
3 changed files with 38 additions and 22 deletions

View File

@ -0,0 +1,4 @@
The ``--pdbcls`` option handles classes via module attributes now (e.g.
``pdb:pdb.Pdb`` with `pdb++`_), and its validation was improved.
.. _pdb++: https://pypi.org/project/pdbpp/

View File

@ -12,8 +12,7 @@ from _pytest import outcomes
from _pytest.config import hookimpl from _pytest.config import hookimpl
def pytest_addoption(parser): def _validate_usepdb_cls(value):
def validate_usepdb_cls(value):
try: try:
modname, classname = value.split(":") modname, classname = value.split(":")
except ValueError: except ValueError:
@ -23,14 +22,22 @@ def pytest_addoption(parser):
try: try:
__import__(modname) __import__(modname)
pdb_cls = getattr(sys.modules[modname], classname) 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: except Exception as exc:
raise argparse.ArgumentTypeError( raise argparse.ArgumentTypeError(
"could not get pdb class for {!r}: {}".format(value, exc) "could not get pdb class for {!r}: {}".format(value, exc)
) )
return pdb_cls
def pytest_addoption(parser):
group = parser.getgroup("general") group = parser.getgroup("general")
group._addoption( group._addoption(
"--pdb", "--pdb",
@ -42,7 +49,7 @@ def pytest_addoption(parser):
"--pdbcls", "--pdbcls",
dest="usepdb_cls", dest="usepdb_cls",
metavar="modulename:classname", metavar="modulename:classname",
type=validate_usepdb_cls, type=_validate_usepdb_cls,
help="start a custom interactive Python debugger on errors. " help="start a custom interactive Python debugger on errors. "
"For example: --pdbcls=IPython.terminal.debugger:TerminalPdb", "For example: --pdbcls=IPython.terminal.debugger:TerminalPdb",
) )

View File

@ -2,12 +2,14 @@ from __future__ import absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
import argparse
import os import os
import platform import platform
import sys import sys
import _pytest._code import _pytest._code
import pytest import pytest
from _pytest.debugging import _validate_usepdb_cls
try: try:
breakpoint breakpoint
@ -695,12 +697,15 @@ class TestPDB(object):
"*: error: argument --pdbcls: 'invalid' is not in the format 'modname:classname'" "*: error: argument --pdbcls: 'invalid' is not in the format 'modname:classname'"
] ]
) )
result = testdir.runpytest_inprocess("--pdbcls=pdb:DoesNotExist")
result.stderr.fnmatch_lines( def test_pdb_validate_usepdb_cls(self, testdir):
[ assert _validate_usepdb_cls("os.path:dirname.__name__") == "dirname"
"*: error: argument --pdbcls: could not get pdb class for 'pdb:DoesNotExist':*"
] with pytest.raises(
) argparse.ArgumentTypeError,
match=r"^could not get pdb class for 'pdb:DoesNotExist': .*'DoesNotExist'",
):
_validate_usepdb_cls("pdb:DoesNotExist")
def test_pdb_custom_cls_without_pdb(self, testdir, custom_pdb_calls): def test_pdb_custom_cls_without_pdb(self, testdir, custom_pdb_calls):
p1 = testdir.makepyfile("""xxx """) p1 = testdir.makepyfile("""xxx """)