From 6383b53ad91a5f6b1727190cb91c19243becede5 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 9 Jul 2016 20:55:43 -0700 Subject: [PATCH] Allow passing a custom Pdb subclass via --pdbcls. This obviates the need for plugins such as `pytest-ipdb`; instead one can simply call `py.test --pdb=IPython.core.debugger:Pdb` --- AUTHORS | 1 + CHANGELOG.rst | 3 ++- _pytest/debugging.py | 24 ++++++++++++++++++------ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/AUTHORS b/AUTHORS index fd543b145..67111393c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,6 +10,7 @@ Anatoly Bubenkoff Andreas Zeidler Andy Freeland Anthon van der Neut +Antony Lee Armin Rigo Aron Curzon Aviv Palivoda diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 593b81fa6..8d00c18d0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -185,7 +185,8 @@ Before, you only got exceptions later from ``argparse`` library, giving no clue about the actual reason for double-added options. -* +* Allow passing a custom debugger class (e.g. ``IPython.core.debugger:Pdb`` + via ``--pdbcls``. * diff --git a/_pytest/debugging.py b/_pytest/debugging.py index 84c920d17..dca2978a9 100644 --- a/_pytest/debugging.py +++ b/_pytest/debugging.py @@ -8,21 +8,32 @@ import pytest def pytest_addoption(parser): group = parser.getgroup("general") - group._addoption('--pdb', - action="store_true", dest="usepdb", default=False, - help="start the interactive Python debugger on errors.") + 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.") 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 +43,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 +57,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 +110,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: