def test_tracing_vars(LineMatcher): lines = StringIO() with hunter.trace(actions=[ VarsPrinter('b', stream=lines), CodePrinter(stream=lines) ]): def a(): b = 1 b = 2 return 1 b = a() b = 2 try: raise Exception("BOOM!") except Exception: pass print(lines.getvalue()) lm = LineMatcher(lines.getvalue().splitlines()) lm.fnmatch_lines([ "*test_hunter.py* call def a():", "*test_hunter.py* line b = 1", "* vars b => 1", "*test_hunter.py* line b = 2", "* vars b => 2", "*test_hunter.py* line return 1", "* vars b => 2", "*test_hunter.py* return return 1", "* ... return value: 1", ])
def test_tracing_reinstall(LineMatcher): lines = StringIO() with hunter.trace(CodePrinter(stream=lines)): def foo(): a = 2 sys.settrace(sys.gettrace()) a = 3 def bar(): a = 1 foo() a = 4 bar() print(lines.getvalue()) lm = LineMatcher(lines.getvalue().splitlines()) lm.fnmatch_lines([ "*test_hunter.py:* call def bar():", "*test_hunter.py:* line a = 1", "*test_hunter.py:* line foo()", "*test_hunter.py:* call def foo():", "*test_hunter.py:* line a = 2", "*test_hunter.py:* line sys.settrace(sys.gettrace())", "*test_hunter.py:* line a = 3", "*test_hunter.py:* return a = 3", "* ... return value: None", "*test_hunter.py:* line a = 4", "*test_hunter.py:* return a = 4", "* ... return value: None", ])
def test_varssnooper(LineMatcher): lines = StringIO() snooper = VarsSnooper(stream=lines) def a(): foo = bar = b = 1 b = 2 foo = 3 foo = bar = 4 return b with trace(function='a', actions=[snooper, CodePrinter(stream=lines)]): a() print(lines.getvalue()) lm = LineMatcher(lines.getvalue().splitlines()) lm.fnmatch_lines([ "*test_*.py* line foo = bar = b = 1", "*test_*.py* line [[]b := 1[]]", "* * ... [[]bar := 1[]]", "* * ... [[]foo := 1[]]", "*test_*.py* line b = 2", "*test_*.py* line [[]b : 1 => 2[]]", "*test_*.py* line foo = 3", "*test_*.py* line [[]foo : 1 => 3[]]", "*test_*.py* line foo = bar = 4", "*test_*.py* line [[]bar : 1 => 4[]]", "* * ... [[]foo : 3 => 4[]]", "*test_*.py* line return b", "*test_*.py* return return b", "* * ... return value: 2", ]) assert snooper.stored_reprs == {}
def run(): output = StringIO() with t.trace( Q(Q(module="does-not-exist") | Q(module="does not exist".split()), action=CodePrinter(stream=output))): _bulky_func_that_use_stdlib() return output
def run(): output = StringIO() with t.trace( Q(Q(module="does-not-exist") | Q(module="does not exist".split()), action=CodePrinter(stream=output))): _tokenize() return output
def run(): output = StringIO() with t.trace( Q(~Q(module_in=['re', 'sre', 'sre_parse']) & ~Q(module_startswith='namedtuple') & Q(kind="call"), actions=[ CodePrinter(stream=output), VarsPrinter('line', globals=True, stream=output) ])): _bulky_func_that_use_stdlib()
def run(): output = StringIO() with t.trace( Q(~Q(module_contains='pytest'), ~Q(module_contains='hunter'), ~Q(filename=''), stdlib=False, action=CodePrinter(stream=output))): _bulky_func_that_use_stdlib() return output
def test_tracing_printing_failures(LineMatcher): lines = StringIO() with trace(actions=[ CodePrinter(stream=lines), VarsPrinter("x", stream=lines) ]): class Bad(object): __slots__ = [] def __repr__(self): raise RuntimeError("I'm a bad class!") def a(): x = Bad() return x def b(): x = Bad() raise Exception(x) a() try: b() except Exception as exc: pass lm = LineMatcher(lines.getvalue().splitlines()) lm.fnmatch_lines([ """*tests*test_hunter.py:* call class Bad(object):""", """*tests*test_hunter.py:* line class Bad(object):""", """*tests*test_hunter.py:* line def __repr__(self):""", """*tests*test_hunter.py:* return def __repr__(self):""", """* ... return value: *""", """*tests*test_hunter.py:* call def a():""", """*tests*test_hunter.py:* line x = Bad()""", """*tests*test_hunter.py:* line return x""", """* vars x => !!! FAILED REPR: RuntimeError("I'm a bad class!"*)""", """*tests*test_hunter.py:* return return x""", """* ... return value: !!! FAILED REPR: RuntimeError("I'm a bad class!"*)""", """* vars x => !!! FAILED REPR: RuntimeError("I'm a bad class!"*)""", """*tests*test_hunter.py:* call def b():""", """*tests*test_hunter.py:* line x = Bad()""", """*tests*test_hunter.py:* line raise Exception(x)""", """* vars x => !!! FAILED REPR: RuntimeError("I'm a bad class!"*)""", """*tests*test_hunter.py:* exception raise Exception(x)""", """* ... exception value: !!! FAILED REPR: RuntimeError("I'm a bad class!"*)""", """* vars x => !!! FAILED REPR: RuntimeError("I'm a bad class!"*)""", """*tests*test_hunter.py:* return raise Exception(x)""", """* ... return value: None""", """* vars x => !!! FAILED REPR: RuntimeError("I'm a bad class!"*)""", ])
def test_locals(): out = StringIO() with hunter.trace(lambda event: event.locals.get('node') == 'Foobar', module=__name__, function='foo', action=CodePrinter(stream=out)): def foo(): a = 1 node = 'Foobar' node += 'x' a += 2 return a foo() assert out.getvalue().endswith("node += 'x'\n")
def test_locals(): out = StringIO() with hunter.trace(lambda event: event.locals.get("node") == "Foobar", module="test_hunter", function="foo", action=CodePrinter(stream=out)): def foo(): a = 1 node = "Foobar" node += "x" a += 2 return a foo() assert out.getvalue().endswith('node += "x"\n')
def test_threading_support(LineMatcher): lines = StringIO() idents = set() names = set() started = threading.Event() def record(event): idents.add(event.threadid) names.add(event.threadname) return True with hunter.trace(record, actions=[ CodePrinter(stream=lines), VarsPrinter('a', stream=lines), CallPrinter(stream=lines) ], threading_support=True): def foo(a=1): started.set() print(a) def main(): foo() t = threading.Thread(target=foo) t.start() started.wait(10) main() lm = LineMatcher(lines.getvalue().splitlines()) assert idents - {t.ident} == {None} assert 'MainThread' in names assert any(name.startswith('Thread-') for name in names) lm.fnmatch_lines_random([ 'Thread-* *test_hunter.py:* call def foo(a=1):', 'Thread-* * vars a => 1', 'Thread-* *test_hunter.py:* call => foo(a=1)', 'Thread-* * vars a => 1', 'MainThread *test_hunter.py:* call def foo(a=1):', 'MainThread * vars a => 1', 'MainThread *test_hunter.py:* call => foo(a=1)', 'MainThread * vars a => 1', ])
def test_fullsource_decorator_issue(LineMatcher): out = StringIO() with trace(kind='call', action=CodePrinter(stream=out)): foo = bar = lambda x: x @foo @bar def foo(): return 1 foo() lm = LineMatcher(out.getvalue().splitlines()) lm.fnmatch_lines([ '* call @foo', '* | @bar', '* | def foo():', ])
def test_thread_filtering(LineMatcher, query): lines = StringIO() idents = set() names = set() started = threading.Event() def record(event): idents.add(event.threadid) names.add(event.threadname) return True with hunter.trace(~Q(**query), record, actions=[ CodePrinter(stream=lines), VarsPrinter('a', stream=lines), CallPrinter(stream=lines) ], threading_support=True): def foo(a=1): started.set() print(a) def main(): foo() t = threading.Thread(target=foo) t.start() started.wait(10) main() lm = LineMatcher(lines.getvalue().splitlines()) print(lines.getvalue()) assert None not in idents assert 'MainThread' not in names pprint(lm.lines) lm.fnmatch_lines_random([ 'Thread-* *test_hunter.py:* call def foo(a=1):', 'Thread-* * vars a => 1', 'Thread-* *test_hunter.py:* call => foo(a=1)', 'Thread-* * vars a => 1', ])
def test_tracing_bare(LineMatcher): lines = StringIO() with trace(CodePrinter(stream=lines)): def a(): return 1 b = a() b = 2 try: raise Exception('BOOM!') except Exception: pass print(lines.getvalue()) lm = LineMatcher(lines.getvalue().splitlines()) lm.fnmatch_lines([ "*test_*.py* call def a():", "*test_*.py* line return 1", "*test_*.py* return return 1", "* ... return value: 1", ])
def test_q_action_codeprinter(): out = repr(Q(action=CodePrinter())) assert 'condition=<hunter.' in out assert 'actions=(CodePrinter' in out
def test_q_deduplicate_codeprinter_cls_inverted(): out = repr(Q(CodePrinter(), action=CallPrinter)) assert out.startswith('CodePrinter(')
def test_q_deduplicate_codeprinter(): out = repr(Q(CodePrinter(), action=CodePrinter())) assert out.startswith('CodePrinter(')
def test_predicate_q_deduplicate_callprinter_inverted(): out = repr(Q(CallPrinter(), action=CodePrinter())) assert out.startswith('CallPrinter(')