pdb: validate --pdbcls option

This commit is contained in:
Daniel Hahler 2019-02-28 17:46:09 +01:00
parent c7bbb2a788
commit a868a9ac13
2 changed files with 36 additions and 5 deletions

View File

@ -3,6 +3,7 @@ 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 pdb import pdb
import sys import sys
from doctest import UnexpectedException from doctest import UnexpectedException
@ -12,6 +13,24 @@ from _pytest.config import hookimpl
def pytest_addoption(parser): def pytest_addoption(parser):
def validate_usepdb_cls(value):
try:
modname, classname = value.split(":")
except ValueError:
raise argparse.ArgumentTypeError(
"{!r} is not in the format 'modname:classname'".format(value)
)
try:
__import__(modname)
pdb_cls = getattr(sys.modules[modname], classname)
except Exception as exc:
raise argparse.ArgumentTypeError(
"could not get pdb class for {!r}: {}".format(value, exc)
)
return pdb_cls
group = parser.getgroup("general") group = parser.getgroup("general")
group._addoption( group._addoption(
"--pdb", "--pdb",
@ -23,6 +42,7 @@ def pytest_addoption(parser):
"--pdbcls", "--pdbcls",
dest="usepdb_cls", dest="usepdb_cls",
metavar="modulename:classname", metavar="modulename:classname",
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",
) )
@ -35,11 +55,8 @@ def pytest_addoption(parser):
def pytest_configure(config): def pytest_configure(config):
if config.getvalue("usepdb_cls"): pdb_cls = config.getvalue("usepdb_cls")
modname, classname = config.getvalue("usepdb_cls").split(":") if not pdb_cls:
__import__(modname)
pdb_cls = getattr(sys.modules[modname], classname)
else:
pdb_cls = pdb.Pdb pdb_cls = pdb.Pdb
if config.getvalue("trace"): if config.getvalue("trace"):

View File

@ -688,6 +688,20 @@ class TestPDB(object):
result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"]) result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"])
assert custom_pdb_calls == ["init", "reset", "interaction"] assert custom_pdb_calls == ["init", "reset", "interaction"]
def test_pdb_custom_cls_invalid(self, testdir):
result = testdir.runpytest_inprocess("--pdbcls=invalid")
result.stderr.fnmatch_lines(
[
"*: error: argument --pdbcls: 'invalid' is not in the format 'modname:classname'"
]
)
result = testdir.runpytest_inprocess("--pdbcls=pdb:DoesNotExist")
result.stderr.fnmatch_lines(
[
"*: error: argument --pdbcls: could not get pdb class for '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 """)
result = testdir.runpytest_inprocess("--pdbcls=_pytest:_CustomPdb", p1) result = testdir.runpytest_inprocess("--pdbcls=_pytest:_CustomPdb", p1)