def default_should_trace_hook(frame, filename): ''' Return True if this frame should be traced, False if tracing should be blocked. ''' # First, check whether this code object has a cached value ignored_lines = _filename_to_ignored_lines.get(filename) if ignored_lines is None: # Now, look up that line of code and check for a @DontTrace # preceding or on the same line as the method. # E.g.: # #@DontTrace # def test(): # pass # ... or ... # def test(): #@DontTrace # pass ignored_lines = {} lines = linecache.getlines(filename) i_line = 0 # Could use enumerate, but not there on all versions... for line in lines: j = line.find('#') if j >= 0: comment = line[j:] if DONT_TRACE_TAG in comment: ignored_lines[i_line] = 1 #Note: when it's found in the comment, mark it up and down for the decorator lines found. k = i_line - 1 while k >= 0: if RE_DECORATOR.match(lines[k]): ignored_lines[k] = 1 k -= 1 else: break k = i_line + 1 while k <= len(lines): if RE_DECORATOR.match(lines[k]): ignored_lines[k] = 1 k += 1 else: break i_line += 1 _filename_to_ignored_lines[filename] = ignored_lines func_line = frame.f_code.co_firstlineno - 1 # co_firstlineno is 1-based, so -1 is needed return not (DictContains(ignored_lines, func_line - 1) or #-1 to get line before method DictContains(ignored_lines, func_line)) #method line
def _get_template_file_name(frame): try: if IS_DJANGO19: # The Node source was removed since Django 1.9 if DictContains(frame.f_locals, 'context'): context = frame.f_locals['context'] if hasattr(context, 'template') and hasattr(context.template, 'origin') and \ hasattr(context.template.origin, 'name'): return context.template.origin.name return None source = _get_source(frame) if source is None: pydev_log.debug("Source is None\n") return None fname = source[0].name if fname == '<unknown source>': pydev_log.debug("Source name is %s\n" % fname) return None else: filename, base = GetFileNameAndBaseFromFile(fname) return filename except: pydev_log.debug(traceback.format_exc()) return None
def stop(plugin, pydb, frame, event, args, stop_info, arg, step_cmd): pydb, filename, info, thread = args if DictContains(stop_info, 'jinja2_stop') and stop_info['jinja2_stop']: frame = _suspend_jinja2(pydb, thread, frame, step_cmd) if frame: pydb.doWaitSuspend(thread, frame, event, arg) return True return False
def stop(plugin, mainDebugger, frame, event, args, stop_info, arg, step_cmd): mainDebugger, filename, info, thread = args if DictContains(stop_info, 'django_stop') and stop_info['django_stop']: frame = suspend_django(mainDebugger, thread, frame, step_cmd) if frame: mainDebugger.doWaitSuspend(thread, frame, event, arg) return True return False
def _is_jinja2_render_call(frame): try: name = frame.f_code.co_name if DictContains(frame.f_globals, "__jinja_template__") and name in ( "root", "loop", "macro") or name.startswith("block_"): return True return False except: traceback.print_exc() return False
def get_task_id(self, frame): while frame is not None: if DictContains(frame.f_locals, "self"): self_obj = frame.f_locals["self"] if isinstance(self_obj, asyncio.Task): method_name = frame.f_code.co_name if method_name == "_step": return id(self_obj) frame = frame.f_back return None
def is_django_context_get_call(frame): try: if not DictContains(frame.f_locals, 'self'): return False cls = frame.f_locals['self'].__class__ return inherits(cls, 'BaseContext') except: traceback.print_exc() return False
def _find_render_function_frame(frame): #in order to hide internal rendering functions old_frame = frame try: while not (DictContains(frame.f_locals, 'self') and frame.f_locals['self'].__class__.__name__ == 'Template' and \ frame.f_code.co_name == 'render'): frame = frame.f_back if frame is None: return old_frame return frame except: return old_frame
def do_import(self, name, *args, **kwargs): activate_func = None if DictContains(self._modules_to_patch, name): activate_func = self._modules_to_patch.pop(name) module = self._system_import(name, *args, **kwargs) try: if activate_func: activate_func() #call activate function except: sys.stderr.write("Matplotlib support failed") return module
def is_django_resolve_call(frame): try: name = frame.f_code.co_name if name != '_resolve_lookup': return False if not DictContains(frame.f_locals, 'self'): return False cls = frame.f_locals['self'].__class__ clsname = cls.__name__ return clsname == 'Variable' except: traceback.print_exc() return False
def plugin_import(self, name, globals=None, locals=None, fromlist=None, level=-2): import_name = name try: if self.enabled: ref_globals = globals if ref_globals is None: ref_globals = sys._getframe(1).f_globals space = _discover_space(name, ref_globals) if space is not None: actual_name = space._rewrite_module_path(name) if actual_name is not None: import_name = actual_name except: sys.stderr.write("Failed to get import name for name %s\n" % name) if level == -2: # fake impossible value; default value depends on version if IS_PY24: # the level parameter was added in version 2.5 return self._system_import(import_name, globals, locals, fromlist) elif IS_PY3K: # default value for level parameter in python 3 level = 0 else: # default value for level parameter in other versions level = -1 if IS_JYTHON: import_name = name activate_func = None if name == import_name and DictContains(self._modules_to_patch, name): activate_func = DictPop(self._modules_to_patch, name) module = self._system_import(import_name, globals, locals, fromlist, level) try: if activate_func: activate_func() #call activate function except: sys.stderr.write("Patching modules in pluginbase failed\n") return module
def cmd_step_over(plugin, pydb, frame, event, args, stop_info, stop): pydb, filename, info, thread = args plugin_stop = False stop_info['jinja2_stop'] = False if not hasattr(info, 'pydev_call_from_jinja2'): info.pydev_call_from_jinja2 = None if not hasattr(info, 'pydev_call_inside_jinja2'): info.pydev_call_inside_jinja2 = None if _is_jinja2_suspended(thread): stop = False if info.pydev_call_inside_jinja2 is None: if _is_jinja2_render_call(frame): if event == 'call': info.pydev_call_inside_jinja2 = frame.f_back if event in ('line', 'return'): info.pydev_call_inside_jinja2 = frame else: if event == 'line': if _is_jinja2_render_call( frame) and info.pydev_call_inside_jinja2 is frame: stop_info['jinja2_stop'] = True plugin_stop = stop_info['jinja2_stop'] if event == 'return': if frame is info.pydev_call_inside_jinja2 and not DictContains( frame.f_back.f_locals, 'event'): info.pydev_call_inside_jinja2 = _find_jinja2_render_frame( frame.f_back) return stop, plugin_stop else: if event == 'return' and _is_jinja2_context_call(frame.f_back): #we return from python code to Jinja2 rendering frame info.pydev_call_from_jinja2 = None info.pydev_call_inside_jinja2 = _find_jinja2_render_frame(frame) thread.additionalInfo.suspend_type = JINJA2_SUSPEND stop = False return stop, plugin_stop #print "info.pydev_call_from_jinja2", info.pydev_call_from_jinja2, "stop", stop, "jinja_stop", jinja2_stop, \ # "thread.additionalInfo.suspend_type", thread.additionalInfo.suspend_type #print "event", event, "info.pydev_call_inside_jinja2", info.pydev_call_inside_jinja2 #print "frame", frame, "frame.f_back", frame.f_back, "step_stop", info.pydev_step_stop #print "is_context_call", _is_jinja2_context_call(frame) #print "render", _is_jinja2_render_call(frame) #print "-------------" return stop, plugin_stop
def _get_jinja2_template_line(frame): debug_info = None if DictContains(frame.f_globals, '__jinja_template__'): _debug_info = frame.f_globals['__jinja_template__']._debug_info if _debug_info != '': #sometimes template contains only plain text debug_info = frame.f_globals['__jinja_template__'].debug_info if debug_info is None: return None lineno = frame.f_lineno for pair in debug_info: if pair[1] == lineno: return pair[0] return None
def is_django_render_call(frame): try: name = frame.f_code.co_name if name != 'render': return False if not DictContains(frame.f_locals, 'self'): return False cls = frame.f_locals['self'].__class__ inherits_node = inherits(cls, 'Node') if not inherits_node: return False clsname = cls.__name__ return clsname != 'TextNode' and clsname != 'NodeList' except: traceback.print_exc() return False
def get_breakpoint(plugin, pydb, pydb_frame, frame, event, args): pydb, filename, info, thread = args new_frame = None jinja2_breakpoint = None flag = False if event in ('line', 'call') and info.pydev_state != STATE_SUSPEND and hasattr(pydb, 'jinja2_breakpoints') and \ pydb.jinja2_breakpoints and cached_call(pydb_frame, is_jinja2_render_call, frame): filename = get_jinja2_template_filename(frame) jinja2_breakpoints_for_file = pydb.jinja2_breakpoints.get(filename) new_frame = Jinja2TemplateFrame(frame) if jinja2_breakpoints_for_file: lineno = frame.f_lineno template_lineno = get_jinja2_template_line(frame) if template_lineno is not None and DictContains( jinja2_breakpoints_for_file, template_lineno): jinja2_breakpoint = jinja2_breakpoints_for_file[ template_lineno] flag = True new_frame = Jinja2TemplateFrame(frame) return flag, jinja2_breakpoint, new_frame
def get_breakpoint(plugin, mainDebugger, pydb_frame, frame, event, args): mainDebugger, filename, info, thread = args flag = False django_breakpoint = None new_frame = None type = 'django' if event == 'call' and info.pydev_state != STATE_SUSPEND and \ mainDebugger.django_breakpoints and _is_django_render_call(frame): filename = _get_template_file_name(frame) pydev_log.debug("Django is rendering a template: %s\n" % filename) django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename) if django_breakpoints_for_file: pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file) template_line = _get_template_line(frame) pydev_log.debug("Tracing template line: %d\n" % template_line) if DictContains(django_breakpoints_for_file, template_line): django_breakpoint = django_breakpoints_for_file[template_line] flag = True new_frame = DjangoTemplateFrame(frame) return flag, django_breakpoint, new_frame, type
def do_import(self, name, globals=None, locals=None, fromlist=None, level=-2): if level == -2: # fake impossible value; default value depends on version if IS_PY24: # the level parameter was added in version 2.5 return self._system_import(name, globals, locals, fromlist) elif IS_PY3K: # default value for level parameter in python 3 level = 0 else: # default value for level parameter in other versions level = -1 module = self._system_import(name, globals, locals, fromlist, level) if DictContains(self._modules_to_patch, name): self._modules_to_patch[name]() #call activate function self._modules_to_patch.pop(name) return module
def changeVariable(self, name, value): for d in self.back_context.dicts: if DictContains(d, name): d[name] = value self.f_locals[name] = value
def get_referrer_info(searched_obj): try: if searched_obj is None: ret = ['<xml>\n'] ret.append('<for>\n') ret.append( pydevd_vars.varToXML(searched_obj, 'Skipping getting referrers for None', ' id="%s"' % (id(searched_obj), ))) ret.append('</for>\n') ret.append('</xml>') ret = ''.join(ret) return ret obj_id = id(searched_obj) try: import gc referrers = gc.get_referrers(searched_obj) except: import traceback traceback.print_exc() ret = ['<xml>\n'] ret.append('<for>\n') ret.append( pydevd_vars.varToXML( searched_obj, 'Exception raised while trying to get_referrers.', ' id="%s"' % (id(searched_obj), ))) ret.append('</for>\n') ret.append('</xml>') ret = ''.join(ret) return ret traceback.print_exc() curr_frame = sys._getframe() frame_type = type(curr_frame) #Ignore this frame and any caller frame of this frame ignore_frames = { } #Should be a set, but it's not available on all python versions. while curr_frame is not None: if basename(curr_frame.f_code.co_filename).startswith('pydev'): ignore_frames[curr_frame] = 1 curr_frame = curr_frame.f_back ret = ['<xml>\n'] ret.append('<for>\n') ret.append( pydevd_vars.varToXML(searched_obj, 'Referrers of', ' id="%s"' % (obj_id, ))) ret.append('</for>\n') all_objects = None for r in referrers: try: if DictContains(ignore_frames, r): continue #Skip the references we may add ourselves except: pass #Ok: unhashable type checked... if r is referrers: continue r_type = type(r) r_id = str(id(r)) representation = str(r_type) found_as = '' if r_type == frame_type: for key, val in r.f_locals.items(): if val is searched_obj: found_as = key break elif r_type == dict: # Try to check if it's a value in the dict (and under which key it was found) for key, val in r.items(): if val is searched_obj: found_as = key break #Ok, there's one annoying thing: many times we find it in a dict from an instance, #but with this we don't directly have the class, only the dict, so, to workaround that #we iterate over all reachable objects ad check if one of those has the given dict. if all_objects is None: all_objects = gc.get_objects() for x in all_objects: if getattr(x, '__dict__', None) is r: r = x r_type = type(x) r_id = str(id(r)) representation = str(r_type) break elif r_type in (tuple, list): #Don't use enumerate() because not all Python versions have it. i = 0 for x in r: if x is searched_obj: found_as = '%s[%s]' % (r_type.__name__, i) break i += 1 if found_as: found_as = ' found_as="%s"' % ( pydevd_vars.makeValidXmlValue(found_as), ) ret.append( pydevd_vars.varToXML(r, representation, ' id="%s"%s' % (r_id, found_as))) finally: #If we have any exceptions, don't keep dangling references from this frame to any of our objects. all_objects = None referrers = None searched_obj = None r = None x = None key = None val = None curr_frame = None ignore_frames = None ret.append('</xml>') ret = ''.join(ret) return ret
def log_event(self, frame): event_time = cur_time() - self.start_time # Debug loop iterations # if isinstance(self_obj, asyncio.base_events.BaseEventLoop): # if method_name == "_run_once": # print("Loop iteration") if not hasattr(frame, "f_back") or frame.f_back is None: return back = frame.f_back method_name = back.f_code.co_name if DictContains(frame.f_locals, "self"): self_obj = frame.f_locals["self"] if isinstance(self_obj, asyncio.Task): if method_name in ("__init__",): task_id = id(self_obj) task_name = self.task_mgr.get(str(task_id)) send_message("asyncio_event", event_time, task_name, task_name, "thread", "start", frame.f_code.co_filename, frame.f_lineno, frame) method_name = frame.f_code.co_name if isinstance(self_obj, asyncio.Lock): if method_name in ("acquire", "release"): task_id = self.get_task_id(frame) task_name = self.task_mgr.get(str(task_id)) if method_name == "acquire": if not self_obj._waiters and not self_obj.locked(): send_message("asyncio_event", event_time, task_name, task_name, "lock", method_name+"_begin", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) if self_obj.locked(): method_name += "_begin" else: method_name += "_end" elif method_name == "release": method_name += "_end" send_message("asyncio_event", event_time, task_name, task_name, "lock", method_name, frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) if isinstance(self_obj, asyncio.Queue): if method_name in ("put", "get", "_put", "_get"): task_id = self.get_task_id(frame) task_name = self.task_mgr.get(str(task_id)) if method_name == "put": send_message("asyncio_event", event_time, task_name, task_name, "lock", "acquire_begin", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) elif method_name == "_put": send_message("asyncio_event", event_time, task_name, task_name, "lock", "acquire_end", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) send_message("asyncio_event", event_time, task_name, task_name, "lock", "release", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) elif method_name == "get": back = frame.f_back if back.f_code.co_name != "send": send_message("asyncio_event", event_time, task_name, task_name, "lock", "acquire_begin", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) else: send_message("asyncio_event", event_time, task_name, task_name, "lock", "acquire_end", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) send_message("asyncio_event", event_time, task_name, task_name, "lock", "release", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj)))
def error_once(message): if not DictContains(WARN_ONCE_MAP, message): WARN_ONCE_MAP[message] = True error(message)
def log_event(self, frame): write_log = False self_obj = None if DictContains(frame.f_locals, "self"): self_obj = frame.f_locals["self"] if isinstance(self_obj, threading.Thread) or self_obj.__class__ == ObjectWrapper: write_log = True try: if write_log: t = threadingCurrentThread() back = frame.f_back if not back: return name, back_base = pydevd_file_utils.GetFilenameAndBase(back) event_time = cur_time() - self.start_time method_name = frame.f_code.co_name if isinstance(self_obj, threading.Thread) and method_name in THREAD_METHODS: if back_base not in DONT_TRACE_THREADING or \ (method_name in INNER_METHODS and back_base in INNER_FILES): thread_id = GetThreadId(self_obj) name = self_obj.getName() real_method = frame.f_code.co_name if real_method == "_stop": # TODO: Python 2 if back_base in INNER_FILES and \ back.f_code.co_name == "_wait_for_tstate_lock": back = back.f_back.f_back real_method = "stop" elif real_method == "join": # join called in the current thread, not in self object thread_id = GetThreadId(t) name = t.getName() parent = None if real_method in ("start", "stop"): parent = GetThreadId(t) send_message("threading_event", event_time, name, thread_id, "thread", real_method, back.f_code.co_filename, back.f_lineno, back, parent=parent) # print(event_time, self_obj.getName(), thread_id, "thread", # real_method, back.f_code.co_filename, back.f_lineno) if self_obj.__class__ == ObjectWrapper: if back_base in DONT_TRACE_THREADING: # do not trace methods called from threading return _, back_back_base = pydevd_file_utils.GetFilenameAndBase(back.f_back) back = back.f_back if back_back_base in DONT_TRACE_THREADING: # back_back_base is the file, where the method was called froms return if method_name == "__init__": send_message("threading_event", event_time, t.getName(), GetThreadId(t), "lock", method_name, back.f_code.co_filename, back.f_lineno, back, lock_id=str(id(frame.f_locals["self"]))) if DictContains(frame.f_locals, "attr") and \ (frame.f_locals["attr"] in LOCK_METHODS or frame.f_locals["attr"] in QUEUE_METHODS): real_method = frame.f_locals["attr"] if method_name == "call_begin": real_method += "_begin" elif method_name == "call_end": real_method += "_end" else: return if real_method == "release_end": # do not log release end. Maybe use it later return send_message("threading_event", event_time, t.getName(), GetThreadId(t), "lock", real_method, back.f_code.co_filename, back.f_lineno, back, lock_id=str(id(self_obj))) if real_method in ("put_end", "get_end"): # fake release for queue, cause we don't call it directly send_message("threading_event", event_time, t.getName(), GetThreadId(t), "lock", "release", back.f_code.co_filename, back.f_lineno, back, lock_id=str(id(self_obj))) # print(event_time, t.getName(), GetThreadId(t), "lock", # real_method, back.f_code.co_filename, back.f_lineno) except Exception: traceback.print_exc()
def _is_jinja2_context_call(frame): return DictContains(frame.f_locals, "_Context__obj")
def _is_jinja2_internal_function(frame): return DictContains(frame.f_locals, 'self') and frame.f_locals['self'].__class__.__name__ in \ ('LoopContext', 'TemplateReference', 'Macro', 'BlockReference')
def _get_jinja2_template_filename(frame): if DictContains(frame.f_globals, '__jinja_template__'): fname = frame.f_globals['__jinja_template__'].filename filename, base = GetFileNameAndBaseFromFile(fname) return filename return None