Make debugging's pytest_configure re-entrant
This is relevant when using runpytest in-process. Fixes: E def test_1(testdir): E testdir.runpytest() E > __import__('pdb').set_trace() E E ../../test_trace_after_runpytest.py:3: E …/Vcs/pytest/src/_pytest/debugging.py:81: in set_trace E tw = _pytest.config.create_terminal_writer(cls._config) E E config = None, args = (), kwargs = {}, tw = <py._io.terminalwriter.TerminalWriter object at 0x7f1097088160> E E def create_terminal_writer(config, *args, **kwargs): E """Create a TerminalWriter instance configured according to the options E in the config object. Every code which requires a TerminalWriter object E and has access to a config object should use this function. E """ E tw = py.io.TerminalWriter(*args, **kwargs) E > if config.option.color == "yes": E E AttributeError: 'NoneType' object has no attribute 'option'
This commit is contained in:
parent
21725e9304
commit
e61e81a7b5
|
@ -0,0 +1 @@
|
|||
Fix nested usage of debugging plugin (pdb), e.g. with pytester's ``testdir.runpytest``.
|
|
@ -47,17 +47,24 @@ def pytest_configure(config):
|
|||
if config.getvalue("usepdb"):
|
||||
config.pluginmanager.register(PdbInvoke(), "pdbinvoke")
|
||||
|
||||
old = (pdb.set_trace, pytestPDB._pluginmanager)
|
||||
|
||||
def fin():
|
||||
pdb.set_trace, pytestPDB._pluginmanager = old
|
||||
pytestPDB._config = None
|
||||
pytestPDB._pdb_cls = pdb.Pdb
|
||||
|
||||
pytestPDB._saved.append(
|
||||
(pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config, pytestPDB._pdb_cls)
|
||||
)
|
||||
pdb.set_trace = pytestPDB.set_trace
|
||||
pytestPDB._pluginmanager = config.pluginmanager
|
||||
pytestPDB._config = config
|
||||
pytestPDB._pdb_cls = pdb_cls
|
||||
|
||||
# NOTE: not using pytest_unconfigure, since it might get called although
|
||||
# pytest_configure was not (if another plugin raises UsageError).
|
||||
def fin():
|
||||
(
|
||||
pdb.set_trace,
|
||||
pytestPDB._pluginmanager,
|
||||
pytestPDB._config,
|
||||
pytestPDB._pdb_cls,
|
||||
) = pytestPDB._saved.pop()
|
||||
|
||||
config._cleanup.append(fin)
|
||||
|
||||
|
||||
|
@ -67,6 +74,7 @@ class pytestPDB(object):
|
|||
_pluginmanager = None
|
||||
_config = None
|
||||
_pdb_cls = pdb.Pdb
|
||||
_saved = []
|
||||
|
||||
@classmethod
|
||||
def set_trace(cls, set_break=True):
|
||||
|
|
|
@ -784,3 +784,30 @@ class TestTraceOption:
|
|||
assert "1 passed" in rest
|
||||
assert "reading from stdin while output" not in rest
|
||||
TestPDB.flush(child)
|
||||
|
||||
|
||||
def test_trace_after_runpytest(testdir):
|
||||
"""Test that debugging's pytest_configure is re-entrant."""
|
||||
p1 = testdir.makepyfile(
|
||||
"""
|
||||
from _pytest.debugging import pytestPDB
|
||||
|
||||
def test_outer(testdir):
|
||||
from _pytest.debugging import pytestPDB
|
||||
|
||||
assert len(pytestPDB._saved) == 1
|
||||
|
||||
testdir.runpytest("-k test_inner")
|
||||
|
||||
__import__('pdb').set_trace()
|
||||
|
||||
def test_inner(testdir):
|
||||
assert len(pytestPDB._saved) == 2
|
||||
"""
|
||||
)
|
||||
child = testdir.spawn_pytest("-p pytester %s -k test_outer" % p1)
|
||||
child.expect(r"\(Pdb")
|
||||
child.sendline("c")
|
||||
rest = child.read().decode("utf8")
|
||||
TestPDB.flush(child)
|
||||
assert child.exitstatus == 0, rest
|
||||
|
|
Loading…
Reference in New Issue