Merge pull request #3647 from jeffreyrack/3610-add-trace-option
3610 add trace option
This commit is contained in:
commit
303133f013
|
@ -0,0 +1 @@
|
||||||
|
Added the `--trace` option to enter the debugger at the start of a test.
|
|
@ -171,6 +171,18 @@ for example::
|
||||||
>>> sys.last_value
|
>>> sys.last_value
|
||||||
AssertionError('assert result == "ok"',)
|
AssertionError('assert result == "ok"',)
|
||||||
|
|
||||||
|
.. _trace-option:
|
||||||
|
|
||||||
|
Dropping to PDB_ (Python Debugger) at the start of a test
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
``pytest`` allows one to drop into the PDB_ prompt immediately at the start of each test via a command line option::
|
||||||
|
|
||||||
|
pytest --trace
|
||||||
|
|
||||||
|
This will invoke the Python debugger at the start of every test.
|
||||||
|
|
||||||
.. _breakpoints:
|
.. _breakpoints:
|
||||||
|
|
||||||
Setting breakpoints
|
Setting breakpoints
|
||||||
|
|
|
@ -5,6 +5,8 @@ import sys
|
||||||
import os
|
import os
|
||||||
from doctest import UnexpectedException
|
from doctest import UnexpectedException
|
||||||
|
|
||||||
|
from _pytest.config import hookimpl
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from builtins import breakpoint # noqa
|
from builtins import breakpoint # noqa
|
||||||
|
|
||||||
|
@ -28,6 +30,12 @@ def pytest_addoption(parser):
|
||||||
help="start a custom interactive Python debugger on errors. "
|
help="start a custom interactive Python debugger on errors. "
|
||||||
"For example: --pdbcls=IPython.terminal.debugger:TerminalPdb",
|
"For example: --pdbcls=IPython.terminal.debugger:TerminalPdb",
|
||||||
)
|
)
|
||||||
|
group._addoption(
|
||||||
|
"--trace",
|
||||||
|
dest="trace",
|
||||||
|
action="store_true",
|
||||||
|
help="Immediately break when running each test.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
|
@ -38,6 +46,8 @@ def pytest_configure(config):
|
||||||
else:
|
else:
|
||||||
pdb_cls = pdb.Pdb
|
pdb_cls = pdb.Pdb
|
||||||
|
|
||||||
|
if config.getvalue("trace"):
|
||||||
|
config.pluginmanager.register(PdbTrace(), "pdbtrace")
|
||||||
if config.getvalue("usepdb"):
|
if config.getvalue("usepdb"):
|
||||||
config.pluginmanager.register(PdbInvoke(), "pdbinvoke")
|
config.pluginmanager.register(PdbInvoke(), "pdbinvoke")
|
||||||
|
|
||||||
|
@ -71,7 +81,7 @@ class pytestPDB(object):
|
||||||
_pdb_cls = pdb.Pdb
|
_pdb_cls = pdb.Pdb
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_trace(cls):
|
def set_trace(cls, set_break=True):
|
||||||
""" invoke PDB set_trace debugging, dropping any IO capturing. """
|
""" invoke PDB set_trace debugging, dropping any IO capturing. """
|
||||||
import _pytest.config
|
import _pytest.config
|
||||||
|
|
||||||
|
@ -84,7 +94,8 @@ class pytestPDB(object):
|
||||||
tw.line()
|
tw.line()
|
||||||
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
|
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
|
||||||
cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config)
|
cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config)
|
||||||
cls._pdb_cls().set_trace(frame)
|
if set_break:
|
||||||
|
cls._pdb_cls().set_trace(frame)
|
||||||
|
|
||||||
|
|
||||||
class PdbInvoke(object):
|
class PdbInvoke(object):
|
||||||
|
@ -104,6 +115,30 @@ class PdbInvoke(object):
|
||||||
post_mortem(tb)
|
post_mortem(tb)
|
||||||
|
|
||||||
|
|
||||||
|
class PdbTrace(object):
|
||||||
|
@hookimpl(hookwrapper=True)
|
||||||
|
def pytest_pyfunc_call(self, pyfuncitem):
|
||||||
|
_test_pytest_function(pyfuncitem)
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
def _test_pytest_function(pyfuncitem):
|
||||||
|
pytestPDB.set_trace(set_break=False)
|
||||||
|
testfunction = pyfuncitem.obj
|
||||||
|
pyfuncitem.obj = pdb.runcall
|
||||||
|
if pyfuncitem._isyieldedfunction():
|
||||||
|
arg_list = list(pyfuncitem._args)
|
||||||
|
arg_list.insert(0, testfunction)
|
||||||
|
pyfuncitem._args = tuple(arg_list)
|
||||||
|
else:
|
||||||
|
if "func" in pyfuncitem._fixtureinfo.argnames:
|
||||||
|
raise ValueError("--trace can't be used with a fixture named func!")
|
||||||
|
pyfuncitem.funcargs["func"] = testfunction
|
||||||
|
new_list = list(pyfuncitem._fixtureinfo.argnames)
|
||||||
|
new_list.append("func")
|
||||||
|
pyfuncitem._fixtureinfo.argnames = tuple(new_list)
|
||||||
|
|
||||||
|
|
||||||
def _enter_pdb(node, excinfo, rep):
|
def _enter_pdb(node, excinfo, rep):
|
||||||
# XXX we re-use the TerminalReporter's terminalwriter
|
# XXX we re-use the TerminalReporter's terminalwriter
|
||||||
# because this seems to avoid some encoding related troubles
|
# because this seems to avoid some encoding related troubles
|
||||||
|
|
|
@ -696,3 +696,40 @@ class TestDebuggingBreakpoints(object):
|
||||||
assert "1 failed" in rest
|
assert "1 failed" in rest
|
||||||
assert "reading from stdin while output" not in rest
|
assert "reading from stdin while output" not in rest
|
||||||
TestPDB.flush(child)
|
TestPDB.flush(child)
|
||||||
|
|
||||||
|
|
||||||
|
class TestTraceOption:
|
||||||
|
def test_trace_sets_breakpoint(self, testdir):
|
||||||
|
p1 = testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
def test_1():
|
||||||
|
assert True
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
child = testdir.spawn_pytest("--trace " + str(p1))
|
||||||
|
child.expect("test_1")
|
||||||
|
child.expect("(Pdb)")
|
||||||
|
child.sendeof()
|
||||||
|
rest = child.read().decode("utf8")
|
||||||
|
assert "1 passed" in rest
|
||||||
|
assert "reading from stdin while output" not in rest
|
||||||
|
TestPDB.flush(child)
|
||||||
|
|
||||||
|
def test_trace_against_yield_test(self, testdir):
|
||||||
|
p1 = testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
def is_equal(a, b):
|
||||||
|
assert a == b
|
||||||
|
|
||||||
|
def test_1():
|
||||||
|
yield is_equal, 1, 1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
child = testdir.spawn_pytest("--trace " + str(p1))
|
||||||
|
child.expect("is_equal")
|
||||||
|
child.expect("(Pdb)")
|
||||||
|
child.sendeof()
|
||||||
|
rest = child.read().decode("utf8")
|
||||||
|
assert "1 passed" in rest
|
||||||
|
assert "reading from stdin while output" not in rest
|
||||||
|
TestPDB.flush(child)
|
||||||
|
|
Loading…
Reference in New Issue