Merge pull request #1712 from anntzer/custom-debugger
Allow passing a custom Pdb subclass via --pdbcls.
This commit is contained in:
commit
c4f20a1834
1
AUTHORS
1
AUTHORS
|
@ -10,6 +10,7 @@ Anatoly Bubenkoff
|
|||
Andreas Zeidler
|
||||
Andy Freeland
|
||||
Anthon van der Neut
|
||||
Antony Lee
|
||||
Armin Rigo
|
||||
Aron Curzon
|
||||
Aviv Palivoda
|
||||
|
|
|
@ -117,7 +117,8 @@
|
|||
Example '-o xfail_strict=True'. A complete ini-options can be viewed
|
||||
by py.test --help. Thanks `@blueyed`_ and `@fengxx`_ for the PR
|
||||
|
||||
*
|
||||
* Allow passing a custom debugger class (e.g. ``IPython.core.debugger:Pdb``
|
||||
via ``--pdbcls``). Thanks to `@anntzer`_ for the PR.
|
||||
|
||||
*
|
||||
|
||||
|
@ -270,6 +271,7 @@
|
|||
.. _@DRMacIver: https://github.com/DRMacIver
|
||||
.. _@RedBeardCode: https://github.com/RedBeardCode
|
||||
.. _@Vogtinator: https://github.com/Vogtinator
|
||||
.. _@anntzer: https://github.com/anntzer
|
||||
.. _@bagerard: https://github.com/bagerard
|
||||
.. _@blueyed: https://github.com/blueyed
|
||||
.. _@ceridwen: https://github.com/ceridwen
|
||||
|
|
|
@ -8,21 +8,33 @@ import pytest
|
|||
|
||||
def pytest_addoption(parser):
|
||||
group = parser.getgroup("general")
|
||||
group._addoption('--pdb',
|
||||
action="store_true", dest="usepdb", default=False,
|
||||
group._addoption(
|
||||
'--pdb', dest="usepdb", action="store_true",
|
||||
help="start the interactive Python debugger on errors.")
|
||||
group._addoption(
|
||||
'--pdbcls', dest="usepdb_cls", metavar="modulename:classname",
|
||||
help="start a custom interactive Python debugger on errors. "
|
||||
"For example: --pdbcls=IPython.core.debugger:Pdb")
|
||||
|
||||
def pytest_namespace():
|
||||
return {'set_trace': pytestPDB().set_trace}
|
||||
|
||||
def pytest_configure(config):
|
||||
if config.getvalue("usepdb"):
|
||||
if config.getvalue("usepdb") or config.getvalue("usepdb_cls"):
|
||||
config.pluginmanager.register(PdbInvoke(), 'pdbinvoke')
|
||||
if config.getvalue("usepdb_cls"):
|
||||
modname, classname = config.getvalue("usepdb_cls").split(":")
|
||||
__import__(modname)
|
||||
pdb_cls = getattr(sys.modules[modname], classname)
|
||||
else:
|
||||
pdb_cls = pdb.Pdb
|
||||
pytestPDB._pdb_cls = pdb_cls
|
||||
|
||||
old = (pdb.set_trace, pytestPDB._pluginmanager)
|
||||
def fin():
|
||||
pdb.set_trace, pytestPDB._pluginmanager = old
|
||||
pytestPDB._config = None
|
||||
pytestPDB._pdb_cls = pdb.Pdb
|
||||
pdb.set_trace = pytest.set_trace
|
||||
pytestPDB._pluginmanager = config.pluginmanager
|
||||
pytestPDB._config = config
|
||||
|
@ -32,6 +44,7 @@ class pytestPDB:
|
|||
""" Pseudo PDB that defers to the real pdb. """
|
||||
_pluginmanager = None
|
||||
_config = None
|
||||
_pdb_cls = pdb.Pdb
|
||||
|
||||
def set_trace(self):
|
||||
""" invoke PDB set_trace debugging, dropping any IO capturing. """
|
||||
|
@ -45,7 +58,7 @@ class pytestPDB:
|
|||
tw.line()
|
||||
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
|
||||
self._pluginmanager.hook.pytest_enter_pdb(config=self._config)
|
||||
pdb.Pdb().set_trace(frame)
|
||||
self._pdb_cls().set_trace(frame)
|
||||
|
||||
|
||||
class PdbInvoke:
|
||||
|
@ -98,7 +111,7 @@ def _find_last_non_hidden_frame(stack):
|
|||
|
||||
|
||||
def post_mortem(t):
|
||||
class Pdb(pdb.Pdb):
|
||||
class Pdb(pytestPDB._pdb_cls):
|
||||
def get_stack(self, f, t):
|
||||
stack, i = pdb.Pdb.get_stack(self, f, t)
|
||||
if f is None:
|
||||
|
|
|
@ -314,3 +314,28 @@ class TestPDB:
|
|||
child.sendeof()
|
||||
if child.isalive():
|
||||
child.wait()
|
||||
|
||||
def test_pdb_custom_cls(self, testdir):
|
||||
called = []
|
||||
|
||||
# install dummy debugger class and track which methods were called on it
|
||||
class _CustomPdb:
|
||||
def __init__(self, *args, **kwargs):
|
||||
called.append("init")
|
||||
|
||||
def reset(self):
|
||||
called.append("reset")
|
||||
|
||||
def interaction(self, *args):
|
||||
called.append("interaction")
|
||||
|
||||
_pytest._CustomPdb = _CustomPdb
|
||||
|
||||
p1 = testdir.makepyfile("""xxx """)
|
||||
result = testdir.runpytest_inprocess(
|
||||
"--pdbcls=_pytest:_CustomPdb", p1)
|
||||
result.stdout.fnmatch_lines([
|
||||
"*NameError*xxx*",
|
||||
"*1 error*",
|
||||
])
|
||||
assert called == ["init", "reset", "interaction"]
|
||||
|
|
Loading…
Reference in New Issue