Merge pull request #1712 from anntzer/custom-debugger

Allow passing a custom Pdb subclass via --pdbcls.
This commit is contained in:
Ronny Pfannschmidt 2016-07-12 16:45:07 +02:00 committed by GitHub
commit c4f20a1834
4 changed files with 48 additions and 7 deletions

View File

@ -10,6 +10,7 @@ Anatoly Bubenkoff
Andreas Zeidler Andreas Zeidler
Andy Freeland Andy Freeland
Anthon van der Neut Anthon van der Neut
Antony Lee
Armin Rigo Armin Rigo
Aron Curzon Aron Curzon
Aviv Palivoda Aviv Palivoda

View File

@ -117,7 +117,8 @@
Example '-o xfail_strict=True'. A complete ini-options can be viewed Example '-o xfail_strict=True'. A complete ini-options can be viewed
by py.test --help. Thanks `@blueyed`_ and `@fengxx`_ for the PR 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 .. _@DRMacIver: https://github.com/DRMacIver
.. _@RedBeardCode: https://github.com/RedBeardCode .. _@RedBeardCode: https://github.com/RedBeardCode
.. _@Vogtinator: https://github.com/Vogtinator .. _@Vogtinator: https://github.com/Vogtinator
.. _@anntzer: https://github.com/anntzer
.. _@bagerard: https://github.com/bagerard .. _@bagerard: https://github.com/bagerard
.. _@blueyed: https://github.com/blueyed .. _@blueyed: https://github.com/blueyed
.. _@ceridwen: https://github.com/ceridwen .. _@ceridwen: https://github.com/ceridwen

View File

@ -8,21 +8,33 @@ import pytest
def pytest_addoption(parser): def pytest_addoption(parser):
group = parser.getgroup("general") group = parser.getgroup("general")
group._addoption('--pdb', group._addoption(
action="store_true", dest="usepdb", default=False, '--pdb', dest="usepdb", action="store_true",
help="start the interactive Python debugger on errors.") 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(): def pytest_namespace():
return {'set_trace': pytestPDB().set_trace} return {'set_trace': pytestPDB().set_trace}
def pytest_configure(config): def pytest_configure(config):
if config.getvalue("usepdb"): if config.getvalue("usepdb") or config.getvalue("usepdb_cls"):
config.pluginmanager.register(PdbInvoke(), 'pdbinvoke') 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) old = (pdb.set_trace, pytestPDB._pluginmanager)
def fin(): def fin():
pdb.set_trace, pytestPDB._pluginmanager = old pdb.set_trace, pytestPDB._pluginmanager = old
pytestPDB._config = None pytestPDB._config = None
pytestPDB._pdb_cls = pdb.Pdb
pdb.set_trace = pytest.set_trace pdb.set_trace = pytest.set_trace
pytestPDB._pluginmanager = config.pluginmanager pytestPDB._pluginmanager = config.pluginmanager
pytestPDB._config = config pytestPDB._config = config
@ -32,6 +44,7 @@ class pytestPDB:
""" Pseudo PDB that defers to the real pdb. """ """ Pseudo PDB that defers to the real pdb. """
_pluginmanager = None _pluginmanager = None
_config = None _config = None
_pdb_cls = pdb.Pdb
def set_trace(self): def set_trace(self):
""" invoke PDB set_trace debugging, dropping any IO capturing. """ """ invoke PDB set_trace debugging, dropping any IO capturing. """
@ -45,7 +58,7 @@ class pytestPDB:
tw.line() tw.line()
tw.sep(">", "PDB set_trace (IO-capturing turned off)") tw.sep(">", "PDB set_trace (IO-capturing turned off)")
self._pluginmanager.hook.pytest_enter_pdb(config=self._config) self._pluginmanager.hook.pytest_enter_pdb(config=self._config)
pdb.Pdb().set_trace(frame) self._pdb_cls().set_trace(frame)
class PdbInvoke: class PdbInvoke:
@ -98,7 +111,7 @@ def _find_last_non_hidden_frame(stack):
def post_mortem(t): def post_mortem(t):
class Pdb(pdb.Pdb): class Pdb(pytestPDB._pdb_cls):
def get_stack(self, f, t): def get_stack(self, f, t):
stack, i = pdb.Pdb.get_stack(self, f, t) stack, i = pdb.Pdb.get_stack(self, f, t)
if f is None: if f is None:

View File

@ -314,3 +314,28 @@ class TestPDB:
child.sendeof() child.sendeof()
if child.isalive(): if child.isalive():
child.wait() 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"]