def test_depth_limit(LineMatcher, tracer_impl, depth): buff = StringIO() from sample7 import one tracer = tracer_impl() predicate = When(Q(depth_lt=depth), CallPrinter(stream=buff)) try: tracer.trace(predicate) one() finally: tracer.stop() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ "* call => one()", "* line for i in range(1): # one", "* line two()", "* call => two()", "* return <= two: None", "* line for i in range(1): # one", "* return <= one: None", ]) if depth < 3: assert 'three' not in output if depth < 4: assert 'four' not in output if depth < 5: assert 'five' not in output
def test_callprinter_indent(LineMatcher): from sample6 import bar out = StringIO() with trace(action=CallPrinter(stream=out)): bar() lm = LineMatcher(out.getvalue().splitlines()) lm.fnmatch_lines([ "*sample6.py:1 call => bar()", "*sample6.py:2 line foo()", "*sample6.py:5 call => foo()", "*sample6.py:6 line try:", "*sample6.py:7 line asdf()", "*sample6.py:16 call => asdf()", "*sample6.py:17 line raise Exception()", "*sample6.py:17 exception ! asdf: (<*Exception'>, Exception(), <traceback object at *>)", "*sample6.py:17 return <= asdf: None", "*sample6.py:7 exception ! foo: (<*Exception'>, Exception(), <traceback object at *>)", "*sample6.py:8 line except:", "*sample6.py:9 line pass", "*sample6.py:10 line try:", "*sample6.py:11 line asdf()", "*sample6.py:16 call => asdf()", "*sample6.py:17 line raise Exception()", "*sample6.py:17 exception ! asdf: (<*Exception'>, Exception(), <traceback object at *>)", "*sample6.py:17 return <= asdf: None", "*sample6.py:11 exception ! foo: (<*Exception'>, Exception(), <traceback object at *>)", "*sample6.py:12 line except:", "*sample6.py:13 line pass", "*sample6.py:13 return <= foo: None", "*sample6.py:2 return <= bar: None", ])
def test_clear_env_var(monkeypatch): monkeypatch.setitem(os.environ, 'PYTHONHUNTER', '123') assert os.environ.get('PYTHONHUNTER') == '123' out = StringIO() with trace(action=CallPrinter(stream=out), clear_env_var=True): assert 'PYTHONHUNTER' not in os.environ assert os.environ.get('PYTHONHUNTER') == None
def test_from_predicate_line_no_predicate(LineMatcher): buff = StringIO() from sample7 import one with trace(From(Q(fullsource_has='in_five')), action=CallPrinter(stream=buff)): one() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ "* line * for i in range(1): # five", "* line * return i", ]) assert 'four' not in output assert 'three' not in output assert 'two' not in output assert 'one' not in output
def test_from_predicate(LineMatcher): buff = StringIO() from sample7 import one with trace(From(Q(function='five'), CallPrinter(stream=buff))): one() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ "* call => five()", "* line for i in range(1): # five", "* line return i", "* return <= five: 0", ]) assert 'four' not in output assert 'three' not in output assert 'two' not in output assert 'one' not in output
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_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_from_predicate_with_subpredicate(LineMatcher): buff = StringIO() from sample7 import one with trace(From(Q(source_has='# two'), Q(depth_lt=1)), action=CallPrinter(stream=buff)): one() output = buff.getvalue() lm = LineMatcher(output.splitlines()) lm.fnmatch_lines([ '* line for i in range(1): # two', '* line three()', '* call => three()', '* return <= three: None', '* line for i in range(1): # two', ]) assert 'five' not in output assert 'four' not in output assert 'one()' not in output assert '# one' not in output assert len(lm.lines) == 5
def test_profile_mode(LineMatcher, module): lines = StringIO() with trace(profile=True, action=CallPrinter(stream=lines)): def a(): foo = 1 sys.getsizeof(foo, 2) return getattr(a, 'b', foo) a() print(lines.getvalue()) lm = LineMatcher(lines.getvalue().splitlines()) if module == 'sys': lm.fnmatch_lines([ '* <sys> call * => getsizeof: *', '* <sys> return * <= getsizeof', ]) else: lm.fnmatch_lines([ "* <*builtin*> * call * => getattr: *", '* <*builtin*> * return * <= getattr', ])
def test_callprinter(LineMatcher): out = StringIO() with trace(action=CallPrinter(stream=out)): foo = bar = lambda x: x @foo @bar def foo(): return 1 foo() lm = LineMatcher(out.getvalue().splitlines()) lm.fnmatch_lines([ '* call => <lambda>(x=<function *foo at *>)', '* line foo = bar = lambda x: x', '* return <= <lambda>: <function *foo at *>', '* call => <lambda>(x=<function *foo at *>)', '* line foo = bar = lambda x: x', '* return <= <lambda>: <function *foo at *>', '* call => foo()', '* line return 1', '* return <= foo: 1', ])
def test_q_action_callprinter(): out = repr(Q(action=CallPrinter())) assert 'condition=<hunter.' in out assert 'actions=(CallPrinter' in out
def test_q_deduplicate_callprinter_cls_inverted(): out = repr(Q(CallPrinter(), action=CodePrinter)) assert out.startswith('CallPrinter(')
def test_q_deduplicate_callprinter(): out = repr(Q(CallPrinter(), action=CallPrinter())) assert out.startswith('CallPrinter(')
def test_predicate_q_deduplicate_codeprinter_inverted(): out = repr(Q(CodePrinter(), action=CallPrinter())) assert out.startswith('CodePrinter(')