From 84023a4c15e4e736f0dc313c7a17090000089665 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Fri, 5 Sep 2014 19:39:09 +0200 Subject: [PATCH] Cache functions from plugins lazily as methods in debugger obj. --- python/helpers/pydev/pydevd.py | 20 ++++++++++++++------ python/helpers/pydev/pydevd_frame.py | 16 ++++++++-------- python/helpers/pydev/pydevd_plugin_utils.py | 18 ++++++++++-------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index d4b2ef937ebc..9ae2739eca3e 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -9,7 +9,7 @@ pydev_monkey_qt.patch_qt() import traceback -from pydevd_plugin_utils import load_plugins, NullProxy, PluginProxy +from pydevd_plugin_utils import load_plugins, NullProxy, bind_func_to_method, clear_bindings from pydevd_frame_utils import add_exception_to_frame import pydev_imports @@ -349,7 +349,13 @@ class PyDB: self.plugins = load_plugins('pydevd_plugins') self.plugin = NullProxy() + self._plugin_method_prefix = 'plugin_' + def __getattr__(self, item): + if item.startswith(self._plugin_method_prefix): + # we lazily cache plugin functions as methods of debugger object + return bind_func_to_method(self.plugin, item[len(self._plugin_method_prefix):], self, item) + raise AttributeError(item) def haveAliveThreads(self): for t in threadingEnumerate(): @@ -902,7 +908,7 @@ class PyDB: breakpoints = self.breakpoints file_to_id_to_breakpoint = self.file_to_id_to_line_breakpoint else: - result = self.plugin.get_breakpoints(self, breakpoint_type) + result = self.plugin_get_breakpoints(breakpoint_type) if result is not None: file_to_id_to_breakpoint = self.file_to_id_to_plugin_breakpoint breakpoints = result @@ -1084,7 +1090,7 @@ class PyDB: pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0]) update_exception_hook(self) else: - supported_type = self.plugin.remove_exception_breakpoint(self, type, exception) + supported_type = self.plugin_remove_exception_breakpoint(type, exception) if not supported_type: raise NameError(type) @@ -1107,7 +1113,7 @@ class PyDB: elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK: exception = text - self.plugin.remove_exception_breakpoint(self, 'django', exception) + self.plugin_remove_exception_breakpoint('django', exception) elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION: # Command which takes care for the debug console communication @@ -1589,7 +1595,7 @@ class PyDB: self.writer.addCommand(cmd) def add_plugin_breakpoint(self, func_name, *args, **kwargs): - # add breakpoint from plugin and remember plugin to use + # add breakpoint for plugin and remember which plugin to use in tracing for plugin in self.plugins: if hasattr(plugin, func_name): func = getattr(plugin, func_name) @@ -1597,7 +1603,9 @@ class PyDB: if result: # On adding breakpoint we override plugin that will be used # That means that we don't work with more then 1 plugin at a time - self.plugin = plugin + if self.plugin != plugin: + clear_bindings(self, self._plugin_method_prefix) # remove plugin methods that are cached already + self.plugin = plugin return result return None diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index 93b5cb2e1620..c54ebc191f8d 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -93,7 +93,7 @@ class PyDBFrame: flag = False else: try: - result = mainDebugger.plugin.exception_break(mainDebugger, self, frame, event, self._args, arg) + result = mainDebugger.plugin_exception_break(self, frame, event, self._args, arg) if result: (flag, frame) = result @@ -239,7 +239,7 @@ class PyDBFrame: is_exception_event = event == 'exception' has_exception_breakpoints = main_debugger.break_on_caught_exceptions \ - or main_debugger.plugin.has_exception_breaks(main_debugger) + or main_debugger.plugin_has_exception_breaks() if is_exception_event: if has_exception_breakpoints: @@ -280,7 +280,7 @@ class PyDBFrame: or (step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame) if can_skip: - can_skip = main_debugger.plugin.can_skip(main_debugger, frame) + can_skip = main_debugger.plugin_can_skip(frame) # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint, # we will return nothing for the next trace @@ -335,7 +335,7 @@ class PyDBFrame: if info.pydev_step_cmd == CMD_STEP_OVER and info.pydev_step_stop is frame and event in ('line', 'return'): stop_info['stop'] = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later) else: - result = main_debugger.plugin.get_breakpoint(main_debugger, frame, event, self._args) + result = main_debugger.plugin_get_breakpoint(frame, event, self._args) if result: exist_result = True (flag, breakpoint, new_frame) = result @@ -366,7 +366,7 @@ class PyDBFrame: if stop_info['stop']: self.setSuspend(thread, CMD_SET_BREAK) elif flag: - result = main_debugger.plugin.suspend(main_debugger, self, thread, frame) + result = main_debugger.plugin_suspend(self, thread, frame) if result: frame = result @@ -396,11 +396,11 @@ class PyDBFrame: elif step_cmd == CMD_STEP_INTO: stop_info['stop'] = event in ('line', 'return') - main_debugger.plugin.cmd_step_into(main_debugger, frame, event, self._args, stop_info) + main_debugger.plugin_cmd_step_into(frame, event, self._args, stop_info) elif step_cmd == CMD_STEP_OVER: stop_info['stop'] = info.pydev_step_stop is frame and event in ('line', 'return') - main_debugger.plugin.cmd_step_over(main_debugger, frame, event, self._args, stop_info) + main_debugger.plugin_cmd_step_over(frame, event, self._args, stop_info) elif step_cmd == CMD_SMART_STEP_INTO: stop_info['stop'] = False @@ -449,7 +449,7 @@ class PyDBFrame: stop_info['stop'] = False if True in stop_info.values(): - stopped_on_plugin = main_debugger.plugin.stop(main_debugger, frame, event, self._args, stop_info, arg, step_cmd) + stopped_on_plugin = main_debugger.plugin_stop(frame, event, self._args, stop_info, arg, step_cmd) if DictContains(stop_info, 'stop') and stop_info['stop'] and not stopped_on_plugin: if event == 'line': self.setSuspend(thread, step_cmd) diff --git a/python/helpers/pydev/pydevd_plugin_utils.py b/python/helpers/pydev/pydevd_plugin_utils.py index 76f031049299..5c63de8d257c 100644 --- a/python/helpers/pydev/pydevd_plugin_utils.py +++ b/python/helpers/pydev/pydevd_plugin_utils.py @@ -1,4 +1,5 @@ import os +import types import pydev_log from pluginbase import PluginBase @@ -30,16 +31,17 @@ class NullProxy(object): def __getattr__(self, name): return self.null_func -class PluginProxy(object): - def __init__(self, plugin): - self.plugin = plugin - self.cache = {} - def __getattr__(self, name): - if not hasattr(self.cache, name): - self.cache[name] = getattr(self.plugin, name) +def bind_func_to_method(plugin, func_name, obj, method_name): + foo = types.MethodType(getattr(plugin, func_name), obj) + setattr(obj, method_name, foo) + return foo - return self.cache[name] + +def clear_bindings(obj, method_prefix): + for attr in dir(obj): + if attr.startswith(method_prefix): + delattr(obj, attr)