def test_trace_filtering(self): """Test that trace hook is triggering event callbacks with filtering.""" global ignore_filter ignore_filter = tracefilter.TraceFilter() tracer.clear_hooks_and_stop() self.assertEqual( 1, tracer.add_hook(my_trace_dispatch, { 'start': True, 'event_set': frozenset(('call', )) })) def foo(): pass foo() tracer.stop() global trace_lines import pprint # for entry in trace_lines: # print entry.event, entry.filename, entry.lineno, entry.name self.assertTrue( len(trace_lines) >= 2, 'Should have captured some trace output') for i, right in [(-1, ( 'call', 'stop', )), (-2, ( 'call', 'foo', ))]: self.assertEqual(right, ( trace_lines[i].event, trace_lines[i].name, )) return
def __init__(self, debugger): self.debugger = debugger self.execution_status = 'Pre-execution' self.filename_cache = {} self.ignore_filter = tracefilter.TraceFilter([]) self.bpmgr = breakpoint.BreakpointManager() self.processor = MockProcessor(self) self.step_ignore = -1 self.stop_frame = None self.last_lineno = None self.last_filename = None self.different_line = None return
class Debugger: # The following functions have to be defined before # DEFAULT_INIT_OPTS which includes references to these. # FIXME DRY run, run_exec, run_eval. def run(self, cmd, start_opts=None, globals_=None, locals_=None): """ Run debugger on string `cmd' using builtin function eval and if that builtin exec. Arguments `globals_' and `locals_' are the dictionaries to use for local and global variables. By default, the value of globals is globals(), the current global variables. If `locals_' is not given, it becomes a copy of `globals_'. Debugger.core.start settings are passed via optional dictionary `start_opts'. Overall debugger settings are in Debugger.settings which changed after an instance is created . Also see `run_eval' if what you want to run is an run_eval'able expression have that result returned and `run_call' if you want to debug function run_call. """ if globals_ is None: globals_ = globals() if locals_ is None: locals_ = globals_ if not isinstance(cmd, types.CodeType): self.eval_string = cmd cmd = cmd+'\n' pass retval = None self.core.start(start_opts) try: retval = eval(cmd, globals_, locals_) except SyntaxError: try: exec(cmd, globals_, locals_) except DebuggerQuit: pass except DebuggerQuit: pass pass except DebuggerQuit: pass self.core.stop() return retval def run_exec(self, cmd, start_opts=None, globals_=None, locals_=None): """ Run debugger on string `cmd' which will executed via the builtin function exec. Arguments `globals_' and `locals_' are the dictionaries to use for local and global variables. By default, the value of globals is globals(), the current global variables. If `locals_' is not given, it becomes a copy of `globals_'. Debugger.core.start settings are passed via optional dictionary `start_opts'. Overall debugger settings are in Debugger.settings which changed after an instance is created . Also see `run_eval' if what you want to run is an run_eval'able expression have that result returned and `run_call' if you want to debug function run_call. """ if globals_ is None: globals_ = globals() if locals_ is None: locals_ = globals_ if not isinstance(cmd, types.CodeType): cmd = cmd+'\n' pass self.core.start(start_opts) try: exec(cmd, globals_, locals_) except DebuggerQuit: pass self.core.stop() return def run_call(self, func, start_opts=None, *args, **kwds): """ Run debugger on function call: `func(*args, **kwds)' See also `run_eval' if what you want to run is an eval'able expression have that result returned and `run' if you want to debug a statment via exec. """ res = None self.core.start(opts=start_opts) try: res = func(*args, **kwds) except DebuggerQuit: pass self.core.stop() return res def run_eval(self, expr, start_opts=None, globals_=None, locals_=None): """ Run debugger on string `expr' which will executed via the built-in Python function: eval; `globals_' and `locals_' are the dictionaries to use for local and global variables. If `globals' is not given, __main__.__dict__ (the current global variables) is used. If `locals_' is not given, it becomes a copy of `globals_'. See also `run_call' if what you to debug a function call and `run' if you want to debug general Python statements. """ if globals_ is None: globals_ = globals() if locals_ is None: locals_ = globals_ if not isinstance(expr, types.CodeType): self.eval_string = expr expr = expr+'\n' pass retval = None self.core.start(start_opts) try: retval = eval(expr, globals_, locals_) except DebuggerQuit: pass finally: pyficache.remove_remap_file('<string>') self.core.stop() return retval def run_script(self, filename, start_opts=None, globals_=None, locals_=None): """ Run debugger on Python script `filename'. The script may inspect sys.argv for command arguments. `globals_' and `locals_' are the dictionaries to use for local and global variables. If `globals' is not given, globals() (the current global variables) is used. If `locals_' is not given, it becomes a copy of `globals_'. True is returned if the program terminated normally and False if the debugger initiated a quit or the program did not normally terminate. See also `run_call' if what you to debug a function call, `run_eval' if you want to debug an expression, and `run' if you want to debug general Python statements not inside a file. """ self.mainpyfile = self.core.canonic(filename) # Start with fresh empty copy of globals and locals and tell the script # that it's being run as __main__ to avoid scripts being able to access # the debugger namespace. if globals_ is None: import __main__ # NOQA globals_ = {"__name__" : "__main__", "__file__" : self.mainpyfile, "__builtins__" : __builtins__ } if locals_ is None: locals_ = globals_ self.core.start(start_opts) retval = False self.core.execution_status = 'Running' try: exec(compile(open(self.mainpyfile).read(), self.mainpyfile, 'exec'), globals_, locals_) retval = True except SyntaxError: print(sys.exc_info()[1]) retval = False pass except IOError: print(sys.exc_info()[1]) except DebuggerQuit: retval = False pass except DebuggerRestart: self.core.execution_status = 'Restart requested' raise DebuggerRestart self.core.stop(options={'remove': True}) return retval def restart_argv(self): '''Return an array that would be execv-ed to restart the program''' return self.orig_sys_argv or self.program_sys_argv # Note: has to come after functions listed in ignore_filter. DEFAULT_INIT_OPTS = { # What routines will we not trace into? 'ignore_filter': tracefilter.TraceFilter( [tracer.start, tracer.stop, run_eval, run_call, run_eval, run_script]), # sys.argv when not None contains sys.argv *before* debugger # command processing. So sys.argv contains debugger options as # well as debugged-program options. These options are used to # do a "hard" or execv() restart. # program_sys_argv is set by option save_sys_argv and contains # sys.argv that we see now which may have debugger options # stripped, or it may be that we were not called from a # debugger front end but from inside the running # program. These options are suitable for a "soft" or # exception-handling DebuggerRestart kind of restart. 'orig_sys_argv' : None, 'save_sys_argv' : True, # How is I/O for this debugger handled? 'activate' : False, 'interface' : None, 'input' : None, 'output' : None, 'processor' : None, # Setting contains lots of debugger settings - a whole file # full of them! 'settings' : Mdefault.DEBUGGER_SETTINGS, 'start_opts' : Mdefault.START_OPTS, 'step_ignore' : 0, 'from_ipython' : False } def __init__(self, opts=None): """Create a debugger object. But depending on the value of key 'start' inside hash 'opts', we may or may not initially start debugging. See also Debugger.start and Debugger.stop. """ import trepan.lib.core as Mcore self.mainpyfile = None self.thread = None self.eval_string = None get_option = lambda key: option_set(opts, key, self.DEFAULT_INIT_OPTS) completer = lambda text, state: self.complete(text, state) # set the instance variables that come directly from options. for opt in ('settings', 'orig_sys_argv', 'from_ipython'): setattr(self, opt, get_option(opt)) pass core_opts = {} for opt in ('ignore_filter', 'proc_opts', 'processor', 'step_ignore', 'processor',): core_opts[opt] = get_option(opt) pass # How is I/O for this debugger handled? This should # be set before calling DebuggerCore. interface_opts={'complete': completer} # FIXME when I pass in opts=opts things break interface = (get_option('interface') or Muser.UserInterface(opts=interface_opts)) self.intf = [interface] inp = get_option('input') if inp: self.intf[-1].input = inp pass out = get_option('output') if out: self.intf[-1].output = out pass self.core = Mcore.DebuggerCore(self, core_opts) self.core.add_ignore(self.core.stop) # When set True, we'll also suspend our debug-hook tracing. # This gives us a way to prevent or allow self debugging. self.core.trace_hook_suspend = False if get_option('save_sys_argv'): # Save the debugged program's sys.argv? We do this so that # when the debugged script munges these, we have a good # copy to use for an exec restart self.program_sys_argv = list(sys.argv) else: self.program_sys_argv = None pass self.sigmgr = Msig.SignalManager(self) # Were we requested to activate immediately? if get_option('activate'): self.core.start(get_option('start_opts')) pass return def complete(self, last_token, state): if hasattr(self.core.processor, 'completer'): str = get_line_buffer() or last_token results = self.core.processor.completer(str, state) return results[state] else: return [None] pass
def setUp(self): global ignore_filter trace_lines = [] ignore_tracefilter = tracefilter.TraceFilter() return
#!/usr/bin/env python # -*- Python -*- "Unit test for Tracer's add-hook" import operator, os, sys, unittest import tracer, tracefilter trace_lines = [] ignore_filter = tracefilter.TraceFilter([tracer.stop]) def trace_dispatch1(frame, event, arg): return trace_dispatch1 def trace_dispatch2(frame, event, arg): return trace_dispatch2 def trace_dispatch3(frame, event, arg): return trace_dispatch3 class TestTraceAddHook(unittest.TestCase): def setUp(self): global ignore_filter trace_lines = [] ignore_tracefilter = tracefilter.TraceFilter() return def test_add_hook(self): """Basic sanity and status testing.""" self.assertEqual(0, tracer.size()) self.assertEqual(1, tracer.add_hook(trace_dispatch1)) self.assertEqual(2, tracer.add_hook(trace_dispatch2))
STARTED_STATE = False return len(HOOKS) raise NotImplementedError("sys.settrace() doesn't seem to be implemented") # Demo it if __name__ == '__main__': t = list(EVENT2SHORT.keys()) t.sort() print("EVENT2SHORT.keys() == ALL_EVENT_NAMES: %s" % (tuple(t) == ALL_EVENT_NAMES)) trace_count = 10 import tracefilter ignore_filter = tracefilter.TraceFilter([find_hook, stop, remove_hook]) def my_trace_dispatch(frame, event, arg): global trace_count, ignore_filter 'A sample trace function' if ignore_filter.is_included(frame): return None lineno = frame.f_lineno filename = frame.f_code.co_filename s = "%s - %s:%d" % (event, filename, lineno) if 'call' == event: s += (', %s()' % frame.f_code.co_name) if arg: print("%s arg %s" % (s, arg)) else: print(s) pass