Merge pull request #4855 from blueyed/pdbcls-attr
--pdbcls: improve validation, and allow for "mod:attr.class"
This commit is contained in:
commit
84555c89de
|
@ -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/
|
|
@ -3,6 +3,7 @@ from __future__ import absolute_import
|
|||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import pdb
|
||||
import sys
|
||||
from doctest import UnexpectedException
|
||||
|
@ -11,6 +12,31 @@ from _pytest import outcomes
|
|||
from _pytest.config import hookimpl
|
||||
|
||||
|
||||
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)
|
||||
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)
|
||||
)
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.getgroup("general")
|
||||
group._addoption(
|
||||
|
@ -23,6 +49,7 @@ def pytest_addoption(parser):
|
|||
"--pdbcls",
|
||||
dest="usepdb_cls",
|
||||
metavar="modulename:classname",
|
||||
type=_validate_usepdb_cls,
|
||||
help="start a custom interactive Python debugger on errors. "
|
||||
"For example: --pdbcls=IPython.terminal.debugger:TerminalPdb",
|
||||
)
|
||||
|
@ -35,11 +62,8 @@ def pytest_addoption(parser):
|
|||
|
||||
|
||||
def pytest_configure(config):
|
||||
if config.getvalue("usepdb_cls"):
|
||||
modname, classname = config.getvalue("usepdb_cls").split(":")
|
||||
__import__(modname)
|
||||
pdb_cls = getattr(sys.modules[modname], classname)
|
||||
else:
|
||||
pdb_cls = config.getvalue("usepdb_cls")
|
||||
if not pdb_cls:
|
||||
pdb_cls = pdb.Pdb
|
||||
|
||||
if config.getvalue("trace"):
|
||||
|
|
|
@ -2,12 +2,14 @@ from __future__ import absolute_import
|
|||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
import _pytest._code
|
||||
import pytest
|
||||
from _pytest.debugging import _validate_usepdb_cls
|
||||
|
||||
try:
|
||||
breakpoint
|
||||
|
@ -688,6 +690,23 @@ class TestPDB(object):
|
|||
result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"])
|
||||
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'"
|
||||
]
|
||||
)
|
||||
|
||||
def test_pdb_validate_usepdb_cls(self, testdir):
|
||||
assert _validate_usepdb_cls("os.path:dirname.__name__") == "dirname"
|
||||
|
||||
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):
|
||||
p1 = testdir.makepyfile("""xxx """)
|
||||
result = testdir.runpytest_inprocess("--pdbcls=_pytest:_CustomPdb", p1)
|
||||
|
|
Loading…
Reference in New Issue