1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
import inspect
def pytest_configure(config):
# stash it somewhere global-ish
from polymorphic import tests
tests.HEADLESS = not config.getoption("--headed")
def first_breakable_line(obj) -> tuple[str, int]:
"""
Return the absolute line number of the first executable statement
in a function or bound method.
"""
import ast
import textwrap
func = obj.__func__ if inspect.ismethod(obj) else obj
source = inspect.getsource(func)
source = textwrap.dedent(source)
filename = inspect.getsourcefile(func)
assert filename
_, start_lineno = inspect.getsourcelines(func)
tree = ast.parse(source)
for node in tree.body[0].body:
if (
isinstance(node, ast.Expr)
and isinstance(node.value, ast.Constant)
and isinstance(node.value.value, str)
):
continue
return filename, start_lineno + node.lineno - 1
# fallback: just return the line after the def
return filename, start_lineno + 1
def pytest_runtest_call(item):
# --trace cli option does not work for unittest style tests so we implement it here
test = getattr(item, "obj", None)
if item.config.option.trace and inspect.ismethod(test):
from IPython.terminal.debugger import TerminalPdb
try:
file = inspect.getsourcefile(test)
assert file
dbg = TerminalPdb()
dbg.set_break(*first_breakable_line(test))
dbg.cmdqueue.append("continue")
dbg.set_trace()
except (OSError, AssertionError):
pass
|