def _pydev_stop_at_break(): frame = sys._getframe(1) t = threading.currentThread() if t.additional_info.is_tracing: return False if t.additional_info.pydev_step_cmd == -1 and frame.f_trace in (None, dummy_tracing_holder.dummy_trace_func): # do not handle breakpoints while stepping, because they're handled by old tracing function t.additional_info.is_tracing = True debugger = get_global_debugger() try: abs_path_real_path_and_base = NORM_PATHS_AND_BASE_CONTAINER[frame.f_code.co_filename] except: abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame) filename = abs_path_real_path_and_base[1] breakpoints_for_file = debugger.breakpoints.get(filename) line = _get_line_for_frame(frame) try: breakpoint = breakpoints_for_file[line] except KeyError: pydev_log.debug("Couldn't find breakpoint in the file {} on line {}".format(frame.f_code.co_filename, line)) t.additional_info.is_tracing = False return False if breakpoint and handle_breakpoint(frame, t, debugger, breakpoint): pydev_log.debug("Suspending at breakpoint in file: {} on line {}".format(frame.f_code.co_filename, line)) debugger.set_suspend(t, CMD_SET_BREAK) debugger.do_wait_suspend(t, frame, 'line', None, "frame_eval") t.additional_info.is_tracing = False return t.additional_info.pydev_step_cmd == CMD_SET_NEXT_STATEMENT return False
def _excepthook(exctype, value, tb): from _pydevd_bundle.pydevd_frame import handle_breakpoint_condition, handle_breakpoint_expression global _handle_exceptions if _handle_exceptions: exception_breakpoint = get_exception_breakpoint(exctype, _handle_exceptions) else: exception_breakpoint = None #Always call the original excepthook before going on to call the debugger post mortem to show it. _original_excepthook(exctype, value, tb) if not exception_breakpoint: return if tb is None: #sometimes it can be None, e.g. with GTK return if exctype is KeyboardInterrupt: return frames = [] debugger = get_global_debugger() user_frame = None while tb: frame = tb.tb_frame if exception_breakpoint.ignore_libraries and not debugger.not_in_scope(frame.f_code.co_filename): user_frame = tb.tb_frame frames.append(tb.tb_frame) tb = tb.tb_next thread = threadingCurrentThread() frames_byid = dict([(id(frame),frame) for frame in frames]) if exception_breakpoint.ignore_libraries and user_frame is not None: frame = user_frame else: frame = frames[-1] exception = (exctype, value, tb) _set_additional_info_if_needed(thread) info = thread.additional_info add_exception_to_frame(frame, exception) if exception_breakpoint.condition is not None: eval_result = handle_breakpoint_condition(debugger, info, exception_breakpoint, frame) if not eval_result: return if exception_breakpoint.expression is not None: handle_breakpoint_expression(exception_breakpoint, info, frame) try: thread.additional_info.pydev_message = exception_breakpoint.qname except: thread.additional_info.pydev_message = exception_breakpoint.qname.encode('utf-8') pydevd_tracing.SetTrace(None) #no tracing from here pydev_log.debug('Handling post-mortem stop on exception breakpoint %s' % exception_breakpoint.qname) debugger.handle_post_mortem_stop(thread, frame, frames_byid, exception)
def set_show_return_values(self, py_db, show_return_values): if show_return_values: py_db.show_return_values = True else: if py_db.show_return_values: # We should remove saved return values py_db.remove_return_values_flag = True py_db.show_return_values = False pydev_log.debug("Show return values: %s\n" % py_db.show_return_values)
def _get_stepping_filters(filters_cache=[]): if not filters_cache: filters = os.getenv('PYDEVD_FILTERS', '').split(';') pydev_log.debug("PYDEVD_FILTERS %s\n" % filters) new_filters = [] for new_filter in filters: new_filters.append(new_filter) filters_cache.append(new_filters) return filters_cache[-1]
def _get_library_roots(library_roots_cache=[]): # Note: the project_roots_cache is the same instance among the many calls to the method if not library_roots_cache: roots = os.getenv('LIBRARY_ROOTS', '').split(os.pathsep) pydev_log.debug("LIBRARY_ROOTS %s\n" % roots) new_roots = [] for root in roots: new_roots.append(os.path.normcase(root)) library_roots_cache.append(new_roots) return library_roots_cache[-1] # returns the project roots with case normalized
def stop_on_unhandled_exception(py_db, thread, additional_info, arg): exctype, value, tb = arg break_on_uncaught_exceptions = py_db.break_on_uncaught_exceptions if break_on_uncaught_exceptions: exception_breakpoint = py_db.get_exception_breakpoint(exctype, break_on_uncaught_exceptions) else: exception_breakpoint = None if not exception_breakpoint: return if tb is None: # sometimes it can be None, e.g. with GTK return if exctype is KeyboardInterrupt: return if py_db.exclude_exception_by_filter(exception_breakpoint, tb, True): return frames = [] user_frame = None while tb: frame = tb.tb_frame if exception_breakpoint.ignore_libraries and py_db.in_project_scope(frame.f_code.co_filename): user_frame = tb.tb_frame frames.append(tb.tb_frame) tb = tb.tb_next frames_byid = dict([(id(frame), frame) for frame in frames]) if exception_breakpoint.ignore_libraries and user_frame is not None: frame = user_frame else: frame = frames[-1] add_exception_to_frame(frame, arg) if exception_breakpoint.condition is not None: eval_result = py_db.handle_breakpoint_condition(additional_info, exception_breakpoint, frame) if not eval_result: return if exception_breakpoint.expression is not None: py_db.handle_breakpoint_expression(exception_breakpoint, additional_info, frame) try: additional_info.pydev_message = exception_breakpoint.qname except: additional_info.pydev_message = exception_breakpoint.qname.encode('utf-8') pydev_log.debug('Handling post-mortem stop on exception breakpoint %s' % (exception_breakpoint.qname,)) py_db.do_stop_on_unhandled_exception(thread, frame, frames_byid, arg)
def remove_python_exception_breakpoint(self, py_db, exception): try: cp = py_db.break_on_uncaught_exceptions.copy() cp.pop(exception, None) py_db.break_on_uncaught_exceptions = cp cp = py_db.break_on_caught_exceptions.copy() cp.pop(exception, None) py_db.break_on_caught_exceptions = cp except: pydev_log.debug("Error while removing exception %s" % sys.exc_info()[0]) py_db.on_breakpoints_changed(removed=True)
def is_ignored_by_filter(filename, filename_to_ignored_by_filters_cache={}): try: return filename_to_ignored_by_filters_cache[filename] except: import fnmatch for stepping_filter in _get_stepping_filters(): if fnmatch.fnmatch(filename, stepping_filter): pydev_log.debug("File %s ignored by filter %s" % (filename, stepping_filter)) filename_to_ignored_by_filters_cache[filename] = True break else: filename_to_ignored_by_filters_cache[filename] = False return filename_to_ignored_by_filters_cache[filename]
def should_stop_on_exception(self, frame, event, arg): # ENDIF # main_debugger, _filename, info, _thread = self._args main_debugger = self._args[0] info = self._args[2] flag = False if info.pydev_state != STATE_SUSPEND: # and breakpoint is not None: exception, value, trace = arg if trace is not None: # on jython trace is None on the first event exception_breakpoint = get_exception_breakpoint(exception, main_debugger.break_on_caught_exceptions) if exception_breakpoint is not None: if exception_breakpoint.ignore_libraries: if exception_breakpoint.notify_on_first_raise_only: if main_debugger.first_appearance_in_scope(trace): add_exception_to_frame(frame, (exception, value, trace)) try: info.pydev_message = exception_breakpoint.qname except: info.pydev_message = exception_breakpoint.qname.encode("utf-8") flag = True else: pydev_log.debug( "Ignore exception %s in library %s" % (exception, frame.f_code.co_filename) ) flag = False else: if not exception_breakpoint.notify_on_first_raise_only or just_raised(trace): add_exception_to_frame(frame, (exception, value, trace)) try: info.pydev_message = exception_breakpoint.qname except: info.pydev_message = exception_breakpoint.qname.encode("utf-8") flag = True else: flag = False else: try: if main_debugger.plugin is not None: result = main_debugger.plugin.exception_break(main_debugger, self, frame, self._args, arg) if result: (flag, frame) = result except: flag = False return flag, frame
def exclude_by_filter(self, filename, module_name): ''' :return: True if it should be excluded, False if it should be included and None if no rule matched the given file. ''' for exclude_filter in self._exclude_filters: # : :type exclude_filter: ExcludeFilter if exclude_filter.is_path: if glob_matches_path(filename, exclude_filter.name): if exclude_filter.exclude: pydev_log.debug("File %s ignored by filter %s" % (filename, exclude_filter.name)) return exclude_filter.exclude else: # Module filter. if exclude_filter.name == module_name or module_name.startswith(exclude_filter.name + '.'): return exclude_filter.exclude return None
def suspend_at_builtin_breakpoint(): # used by built-in breakpoint() function appeared in Python 3.7 frame = sys._getframe(3) t = threading.currentThread() if t.additional_info.is_tracing: return False if t.additional_info.pydev_step_cmd == -1: # do not handle breakpoints while stepping, because they're handled by old tracing function t.additional_info.is_tracing = True pydev_log.debug("Suspending at breakpoint in file: {} on line {}".format(frame.f_code.co_filename, frame.f_lineno)) debugger = get_global_debugger() debugger.set_suspend(t, CMD_SET_BREAK) debugger.do_wait_suspend(t, frame, 'line', None, "frame_eval") t.additional_info.is_tracing = False return t.additional_info.pydev_step_cmd == CMD_SET_NEXT_STATEMENT return False
def __init__(self): self._exclude_filters = [] self._project_roots = [] self._library_roots = [] # Filter out libraries? self._use_libraries_filter = False self.require_module = False # True if some exclude filter filters by the module. self.set_use_libraries_filter(os.getenv('PYDEVD_FILTER_LIBRARIES') is not None) project_roots = os.getenv('IDE_PROJECT_ROOTS', None) if project_roots is not None: project_roots = project_roots.split(os.pathsep) else: project_roots = [] self.set_project_roots(project_roots) library_roots = os.getenv('LIBRARY_ROOTS', None) if library_roots is not None: library_roots = library_roots.split(os.pathsep) else: library_roots = self._get_default_library_roots() self.set_library_roots(library_roots) # Stepping filters. pydevd_filters = os.getenv('PYDEVD_FILTERS', '') if pydevd_filters.startswith('{'): # dict(glob_pattern (str) -> exclude(True or False)) exclude_filters = [] for key, val in json.loads(pydevd_filters).items(): exclude_filters.append(ExcludeFilter(key, val, True)) self._exclude_filters = exclude_filters else: # A ';' separated list of strings with globs for the # list of excludes. filters = pydevd_filters.split(';') pydev_log.debug("PYDEVD_FILTERS %s\n" % filters) new_filters = [] for new_filter in filters: if new_filter.strip(): new_filters.append(ExcludeFilter(new_filter.strip(), True, True)) self._exclude_filters = new_filters
def _get_source_django_18_or_lower(frame): # This method is usable only for the Django <= 1.8 try: node = frame.f_locals['self'] if hasattr(node, 'source'): return node.source else: if IS_DJANGO18: # The debug setting was changed since Django 1.8 pydev_log.error_once("WARNING: Template path is not available. Set the 'debug' option in the OPTIONS of a DjangoTemplates " "backend.") else: # The debug setting for Django < 1.8 pydev_log.error_once("WARNING: Template path is not available. Please set TEMPLATE_DEBUG=True in your settings.py to make " "django template breakpoints working") return None except: pydev_log.debug(traceback.format_exc()) return None
def _pydev_stop_at_break(line): frame = sys._getframe(1) t = threading.currentThread() if t.additional_info.is_tracing: return False t.additional_info.is_tracing = True try: debugger = get_global_debugger() try: abs_path_real_path_and_base = NORM_PATHS_AND_BASE_CONTAINER[frame.f_code.co_filename] except: abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame) filename = abs_path_real_path_and_base[1] try: python_breakpoint = debugger.breakpoints[filename][line] except: # print("Couldn't find breakpoint in the file %s on line %s" % (frame.f_code.co_filename, line)) # Could be KeyError if line is not there or TypeError if breakpoints_for_file is None. # Note: using catch-all exception for performance reasons (if the user adds a breakpoint # and then removes it after hitting it once, this method added for the programmatic # breakpoint will keep on being called and one of those exceptions will always be raised # here). return if python_breakpoint: pydev_log.debug("Suspending at breakpoint in file: {} on line {}".format(frame.f_code.co_filename, line)) t.additional_info.trace_suspend_type = 'frame_eval' pydevd_frame_eval_cython_wrapper = sys.modules['_pydevd_frame_eval.pydevd_frame_eval_cython_wrapper'] thread_info = pydevd_frame_eval_cython_wrapper.get_thread_info_py() if thread_info.thread_trace_func is not None: frame.f_trace = thread_info.thread_trace_func else: debugger = get_global_debugger() frame.f_trace = debugger.get_thread_local_trace_func() finally: t.additional_info.is_tracing = False
def _get_template_file_name(frame): try: if IS_DJANGO19_OR_HIGHER: # The Node source was removed since Django 1.9 if dict_contains(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_django_18_or_lower(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: abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(fname) return abs_path_real_path_and_base[1] except: pydev_log.debug(traceback.format_exc()) return None
def _get_template_file_name(frame): try: if IS_DJANGO19: # The Node source was removed since Django 1.9 if 'context' in frame.f_locals: context = frame.f_locals['context'] if hasattr(context, '_has_included_template'): # if there was included template we need to inspect the previous frames and find its name back = frame.f_back while back is not None and frame.f_code.co_name in ('render', '_render'): locals = back.f_locals if 'self' in locals: self = locals['self'] if self.__class__.__name__ == 'Template' and hasattr(self, 'origin') and \ hasattr(self.origin, 'name'): return normcase(self.origin.name) back = back.f_back else: if hasattr(context, 'template') and hasattr(context.template, 'origin') and \ hasattr(context.template.origin, 'name'): return normcase(context.template.origin.name) return None elif IS_DJANGO19_OR_HIGHER: # For Django 1.10 and later there is much simpler way to get template name if 'self' in frame.f_locals: self = frame.f_locals['self'] if hasattr(self, 'origin') and hasattr(self.origin, 'name'): return normcase(self.origin.name) return None source = _get_source_django_18_or_lower(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: abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(fname) return abs_path_real_path_and_base[1] except: pydev_log.debug(traceback.format_exc()) return None
def get_breakpoint(plugin, main_debugger, pydb_frame, frame, event, args): main_debugger, filename, info, thread = args flag = False django_breakpoint = None new_frame = None type = 'django' if event == 'call' and info.pydev_state != STATE_SUSPEND and \ main_debugger.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 = main_debugger.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 dict_contains(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 set_library_roots(roots): roots = _set_roots(roots, _LIBRARY_ROOTS_CACHE) pydev_log.debug("LIBRARY_ROOTS %s\n" % roots)
def set_use_libraries_filter(self, use): pydev_log.debug("pydevd: Use libraries filter: %s\n" % use) self._use_libraries_filter = use
def _on_run(self): try: content_len = -1 while not self.killReceived: try: line = self._read_line() if len(line) == 0: self.handle_except() return # Finished communication. if line.startswith(b'Content-Length:'): content_len = int(line.strip().split(b':', 1)[1]) continue if content_len != -1: # If we previously received a content length, read until a '\r\n'. if line == b'\r\n': json_contents = self._read(content_len) content_len = -1 if len(json_contents) == 0: self.handle_except() return # Finished communication. # We just received a json message, let's process it. self.process_net_command_json( self.global_debugger_holder.global_dbg, json_contents) continue else: # No content len, regular line-based protocol message (remove trailing new-line). if line.endswith(b'\n\n'): line = line[:-2] elif line.endswith(b'\n'): line = line[:-1] elif line.endswith(b'\r'): line = line[:-1] except: if not self.killReceived: traceback.print_exc() self.handle_except() return # Finished communication. # Note: the java backend is always expected to pass utf-8 encoded strings. We now work with unicode # internally and thus, we may need to convert to the actual encoding where needed (i.e.: filenames # on python 2 may need to be converted to the filesystem encoding). if hasattr(line, 'decode'): line = line.decode('utf-8') if DebugInfoHolder.DEBUG_RECORD_SOCKET_READS: sys.stderr.write(u'debugger: received >>%s<<\n' % (line, )) sys.stderr.flush() args = line.split(u'\t', 2) try: cmd_id = int(args[0]) pydev_log.debug('Received command: %s %s\n' % ( ID_TO_MEANING.get(str(cmd_id), '???'), line, )) self.process_command(cmd_id, int(args[1]), args[2]) except: if traceback is not None and sys is not None: # Could happen at interpreter shutdown traceback.print_exc() sys.stderr.write("Can't process net command: %s\n" % line) sys.stderr.flush() except: if not self.killReceived: if traceback is not None: # Could happen at interpreter shutdown traceback.print_exc() self.handle_except()
def add_breakpoint(self, py_db, filename, breakpoint_type, breakpoint_id, line, condition, func_name, expression, suspend_policy, hit_condition, is_logpoint): ''' :param str filename: Note: must be already translated for the server. :param str breakpoint_type: One of: 'python-line', 'django-line', 'jinja2-line'. :param int breakpoint_id: :param int line: :param condition: Either None or the condition to activate the breakpoint. :param str func_name: If "None" (str), may hit in any context. Empty string will hit only top level. Any other value must match the scope of the method to be matched. :param str expression: None or the expression to be evaluated. :param suspend_policy: Either "NONE" (to suspend only the current thread when the breakpoint is hit) or "ALL" (to suspend all threads when a breakpoint is hit). :param str hit_condition: An expression where `@HIT@` will be replaced by the number of hits. i.e.: `@HIT@ == x` or `@HIT@ >= x` :param bool is_logpoint: If True and an expression is passed, pydevd will create an io message command with the result of the evaluation. :return int: :see: ADD_BREAKPOINT_NO_ERROR = 0 :see: ADD_BREAKPOINT_FILE_NOT_FOUND = 1 :see: ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS = 2 ''' assert filename.__class__ == str # i.e.: bytes on py2 and str on py3 assert func_name.__class__ == str # i.e.: bytes on py2 and str on py3 if not pydevd_file_utils.exists(filename): return self.ADD_BREAKPOINT_FILE_NOT_FOUND error_code = self.ADD_BREAKPOINT_NO_ERROR if (py_db.is_files_filter_enabled and not py_db.get_require_module_for_filters() and py_db.apply_files_filter(self._DummyFrame(filename), filename, False)): # Note that if `get_require_module_for_filters()` returns False, we don't do this check. # This is because we don't have the module name given a file at this point (in # runtime it's gotten from the frame.f_globals). # An option could be calculate it based on the filename and current sys.path, # but on some occasions that may be wrong (for instance with `__main__` or if # the user dynamically changes the PYTHONPATH). # Note: depending on the use-case, filters may be changed, so, keep on going and add the # breakpoint even with the error code. error_code = self.ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS if breakpoint_type == 'python-line': added_breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy, hit_condition=hit_condition, is_logpoint=is_logpoint) breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint supported_type = True else: result = None plugin = py_db.get_plugin_lazy_init() if plugin is not None: result = plugin.add_breakpoint('add_line_breakpoint', py_db, breakpoint_type, filename, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint) if result is not None: supported_type = True added_breakpoint, breakpoints = result file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint else: supported_type = False if not supported_type: raise NameError(breakpoint_type) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n', filename, line, func_name) if filename in file_to_id_to_breakpoint: id_to_pybreakpoint = file_to_id_to_breakpoint[filename] else: id_to_pybreakpoint = file_to_id_to_breakpoint[filename] = {} id_to_pybreakpoint[breakpoint_id] = added_breakpoint py_db.consolidate_breakpoints(filename, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() py_db.on_breakpoints_changed() return error_code
def set_project_roots(self, project_roots): self._project_roots = self._fix_roots(project_roots) pydev_log.debug("IDE_PROJECT_ROOTS %s\n" % project_roots)
def add_breakpoint(self, py_db, filename, breakpoint_type, breakpoint_id, line, condition, func_name, expression, suspend_policy, hit_condition, is_logpoint): ''' :param str filename: Note: must be already translated for the server. :param str breakpoint_type: One of: 'python-line', 'django-line', 'jinja2-line'. :param int breakpoint_id: :param int line: :param condition: Either None or the condition to activate the breakpoint. :param str func_name: If "None" (str), may hit in any context. Empty string will hit only top level. Any other value must match the scope of the method to be matched. :param str expression: None or the expression to be evaluated. :param suspend_policy: Either "NONE" (to suspend only the current thread when the breakpoint is hit) or "ALL" (to suspend all threads when a breakpoint is hit). :param str hit_condition: An expression where `@HIT@` will be replaced by the number of hits. i.e.: `@HIT@ == x` or `@HIT@ >= x` :param bool is_logpoint: If True and an expression is passed, pydevd will create an io message command with the result of the evaluation. ''' assert filename.__class__ == str # i.e.: bytes on py2 and str on py3 assert func_name.__class__ == str # i.e.: bytes on py2 and str on py3 if not pydevd_file_utils.exists(filename): sys.stderr.write('pydev debugger: warning: trying to add breakpoint'\ ' to file that does not exist: %s (will have no effect)\n' % (filename,)) sys.stderr.flush() return if breakpoint_type == 'python-line': added_breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy, hit_condition=hit_condition, is_logpoint=is_logpoint) breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint supported_type = True else: result = None plugin = py_db.get_plugin_lazy_init() if plugin is not None: result = plugin.add_breakpoint('add_line_breakpoint', py_db, breakpoint_type, filename, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint) if result is not None: supported_type = True added_breakpoint, breakpoints = result file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint else: supported_type = False if not supported_type: raise NameError(breakpoint_type) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n' % (filename, line, func_name)) sys.stderr.flush() if filename in file_to_id_to_breakpoint: id_to_pybreakpoint = file_to_id_to_breakpoint[filename] else: id_to_pybreakpoint = file_to_id_to_breakpoint[filename] = {} id_to_pybreakpoint[breakpoint_id] = added_breakpoint py_db.consolidate_breakpoints(filename, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() py_db.on_breakpoints_changed()
def is_filter_libraries(): is_filter = os.getenv('PYDEVD_FILTER_LIBRARIES') is not None pydev_log.debug("PYDEVD_FILTER_LIBRARIES %s\n" % is_filter) return is_filter
def _internal_patch_qt(QtCore, qt_support_mode='auto'): pydev_log.debug('Patching Qt: %s', QtCore) _original_thread_init = QtCore.QThread.__init__ _original_runnable_init = QtCore.QRunnable.__init__ _original_QThread = QtCore.QThread class FuncWrapper: def __init__(self, original): self._original = original def __call__(self, *args, **kwargs): set_trace_in_qt() return self._original(*args, **kwargs) class StartedSignalWrapper(QtCore.QObject): # Wrapper for the QThread.started signal try: _signal = QtCore.Signal() # @UndefinedVariable except: _signal = QtCore.pyqtSignal() # @UndefinedVariable def __init__(self, thread, original_started): QtCore.QObject.__init__(self) self.thread = thread self.original_started = original_started if qt_support_mode in ('pyside', 'pyside2'): self._signal = original_started else: self._signal.connect(self._on_call) self.original_started.connect(self._signal) def connect(self, func, *args, **kwargs): if qt_support_mode in ('pyside', 'pyside2'): return self._signal.connect(FuncWrapper(func), *args, **kwargs) else: return self._signal.connect(func, *args, **kwargs) def disconnect(self, *args, **kwargs): return self._signal.disconnect(*args, **kwargs) def emit(self, *args, **kwargs): return self._signal.emit(*args, **kwargs) def _on_call(self, *args, **kwargs): set_trace_in_qt() class ThreadWrapper(QtCore.QThread): # Wrapper for QThread def __init__(self, *args, **kwargs): _original_thread_init(self, *args, **kwargs) # In PyQt5 the program hangs when we try to call original run method of QThread class. # So we need to distinguish instances of QThread class and instances of QThread inheritors. if self.__class__.run == _original_QThread.run: self.run = self._exec_run else: self._original_run = self.run self.run = self._new_run self._original_started = self.started self.started = StartedSignalWrapper(self, self.started) def _exec_run(self): set_trace_in_qt() self.exec_() return None def _new_run(self): set_trace_in_qt() return self._original_run() class RunnableWrapper(QtCore.QRunnable): # Wrapper for QRunnable def __init__(self, *args, **kwargs): _original_runnable_init(self, *args, **kwargs) self._original_run = self.run self.run = self._new_run def _new_run(self): set_trace_in_qt() return self._original_run() QtCore.QThread = ThreadWrapper QtCore.QRunnable = RunnableWrapper
def patch_args(args, is_exec=False): ''' :param list args: Arguments to patch. :param bool is_exec: If it's an exec, the current process will be replaced (this means we have to keep the same ppid). ''' try: pydev_log.debug("Patching args: %s", args) original_args = args unquoted_args = remove_quotes_from_args(args) # Internally we should reference original_args (if we want to return them) or unquoted_args # to add to the list which will be then quoted in the end. del args from pydevd import SetupHolder if not unquoted_args: return original_args if not is_python(unquoted_args[0]): pydev_log.debug("Process is not python, returning.") return original_args # Note: we create a copy as string to help with analyzing the arguments, but # the final list should have items from the unquoted_args as they were initially. args_as_str = _get_str_type_compatible('', unquoted_args) params_with_value_in_separate_arg = ( '--check-hash-based-pycs', '--jit' # pypy option ) # All short switches may be combined together. The ones below require a value and the # value itself may be embedded in the arg. # # i.e.: Python accepts things as: # # python -OQold -qmtest # # Which is the same as: # # python -O -Q old -q -m test # # or even: # # python -OQold "-vcimport sys;print(sys)" # # Which is the same as: # # python -O -Q old -v -c "import sys;print(sys)" params_with_combinable_arg = set(('W', 'X', 'Q', 'c', 'm')) module_name = None before_module_flag = '' module_name_i_start = -1 module_name_i_end = -1 code = None code_i = -1 code_i_end = -1 code_flag = '' filename = None filename_i = -1 ignore_next = True # start ignoring the first (the first entry is the python executable) for i, arg_as_str in enumerate(args_as_str): if ignore_next: ignore_next = False continue if arg_as_str.startswith('-'): if arg_as_str == '-': # Contents will be read from the stdin. This is not currently handled. pydev_log.debug( 'Unable to fix arguments to attach debugger on subprocess when reading from stdin ("python ... -").' ) return original_args if arg_as_str.startswith(params_with_value_in_separate_arg): if arg_as_str in params_with_value_in_separate_arg: ignore_next = True continue break_out = False for j, c in enumerate(arg_as_str): # i.e.: Python supports -X faulthandler as well as -Xfaulthandler # (in one case we have to ignore the next and in the other we don't # have to ignore it). if c in params_with_combinable_arg: remainder = arg_as_str[j + 1:] if not remainder: ignore_next = True if c == 'm': # i.e.: Something as # python -qm test # python -m test # python -qmtest before_module_flag = arg_as_str[: j] # before_module_flag would then be "-q" if before_module_flag == '-': before_module_flag = '' module_name_i_start = i if not remainder: module_name = unquoted_args[i + 1] module_name_i_end = i + 1 else: # i.e.: python -qmtest should provide 'test' as the module_name module_name = unquoted_args[i][j + 1:] module_name_i_end = module_name_i_start break_out = True break elif c == 'c': # i.e.: Something as # python -qc "import sys" # python -c "import sys" # python "-qcimport sys" code_flag = arg_as_str[:j + 1] # code_flag would then be "-qc" if not remainder: # arg_as_str is something as "-qc", "import sys" code = unquoted_args[i + 1] code_i_end = i + 2 else: # if arg_as_str is something as "-qcimport sys" code = remainder # code would be "import sys" code_i_end = i + 1 code_i = i break_out = True break else: break if break_out: break else: # It doesn't start with '-' and we didn't ignore this entry: # this means that this is the file to be executed. filename = unquoted_args[i] filename_i = i # When executing .zip applications, don't attach the debugger. extensions = _get_str_type_compatible( filename, ['.zip', '.pyz', '.pyzw']) for ext in extensions: if filename.endswith(ext): pydev_log.debug( 'Executing a PyZip (debugger will not be attached to subprocess).' ) return original_args if _is_managed_arg(filename): # no need to add pydevd twice pydev_log.debug( 'Skipped monkey-patching as pydevd.py is in args already.' ) return original_args break else: # We didn't find the filename (something is unexpected). pydev_log.debug( 'Unable to fix arguments to attach debugger on subprocess (filename not found).' ) return original_args if code_i != -1: host, port = _get_host_port() if port is not None: new_args = [] new_args.extend(unquoted_args[:code_i]) new_args.append(code_flag) new_args.append( _get_python_c_args(host, port, code, unquoted_args, SetupHolder.setup)) new_args.extend(unquoted_args[code_i_end:]) return quote_args(new_args) first_non_vm_index = max(filename_i, module_name_i_start) if first_non_vm_index == -1: pydev_log.debug( 'Unable to fix arguments to attach debugger on subprocess (could not resolve filename nor module name).' ) return original_args # Original args should be something as: # ['X:\\pysrc\\pydevd.py', '--multiprocess', '--print-in-debugger-startup', # '--vm_type', 'python', '--client', '127.0.0.1', '--port', '56352', '--file', 'x:\\snippet1.py'] from _pydevd_bundle.pydevd_command_line_handling import setup_to_argv new_args = [] new_args.extend(unquoted_args[:first_non_vm_index]) if before_module_flag: new_args.append(before_module_flag) add_module_at = len(new_args) + 1 new_args.extend( setup_to_argv( _get_setup_updated_with_protocol_and_ppid(SetupHolder.setup, is_exec=is_exec))) new_args.append('--file') if module_name is not None: assert module_name_i_start != -1 assert module_name_i_end != -1 # Always after 'pydevd' (i.e.: pydevd "--module" --multiprocess ...) new_args.insert(add_module_at, '--module') new_args.append(module_name) new_args.extend(unquoted_args[module_name_i_end + 1:]) elif filename is not None: assert filename_i != -1 new_args.append(filename) new_args.extend(unquoted_args[filename_i + 1:]) else: raise AssertionError('Internal error (unexpected condition)') return quote_args(new_args) except: pydev_log.exception( 'Error patching args (debugger not attached to subprocess).') return original_args
def set_project_roots(project_roots): project_roots = _set_roots(project_roots, _PROJECT_ROOTS_CACHE) pydev_log.debug("IDE_PROJECT_ROOTS %s\n" % project_roots)
def _excepthook(exctype, value, tb): from _pydevd_bundle.pydevd_frame import handle_breakpoint_condition, handle_breakpoint_expression global _handle_exceptions if _handle_exceptions: exception_breakpoint = get_exception_breakpoint( exctype, _handle_exceptions) else: exception_breakpoint = None #Always call the original excepthook before going on to call the debugger post mortem to show it. _original_excepthook(exctype, value, tb) if not exception_breakpoint: return if tb is None: #sometimes it can be None, e.g. with GTK return if exctype is KeyboardInterrupt: return frames = [] debugger = get_global_debugger() user_frame = None while tb: frame = tb.tb_frame if exception_breakpoint.ignore_libraries and not debugger.not_in_scope( frame.f_code.co_filename): user_frame = tb.tb_frame frames.append(tb.tb_frame) tb = tb.tb_next thread = threadingCurrentThread() frames_byid = dict([(id(frame), frame) for frame in frames]) if exception_breakpoint.ignore_libraries and user_frame is not None: frame = user_frame else: frame = frames[-1] exception = (exctype, value, tb) _set_additional_info_if_needed(thread) info = thread.additional_info add_exception_to_frame(frame, exception) if exception_breakpoint.condition is not None: eval_result = handle_breakpoint_condition(debugger, info, exception_breakpoint, frame) if not eval_result: return if exception_breakpoint.expression is not None: handle_breakpoint_expression(exception_breakpoint, info, frame) try: thread.additional_info.pydev_message = exception_breakpoint.qname except: thread.additional_info.pydev_message = exception_breakpoint.qname.encode( 'utf-8') thread.additional_info.pydev_message = 'python-%s' % thread.additional_info.pydev_message pydevd_tracing.SetTrace(None) #no tracing from here pydev_log.debug('Handling post-mortem stop on exception breakpoint %s' % exception_breakpoint.qname) debugger.handle_post_mortem_stop(thread, frame, frames_byid, exception)
def patch_args(args): try: pydev_log.debug("Patching args: %s", args) args = remove_quotes_from_args(args) from pydevd import SetupHolder new_args = [] if len(args) == 0: return args if is_python(args[0]): ind_c = get_c_option_index(args) if ind_c != -1: host, port = _get_host_port() if port is not None: new_args.extend(args) new_args[ind_c + 1] = _get_python_c_args( host, port, ind_c, args, SetupHolder.setup) return quote_args(new_args) else: # Check for Python ZIP Applications and don't patch the args for them. # Assumes the first non `-<flag>` argument is what we need to check. # There's probably a better way to determine this but it works for most cases. continue_next = False for i in range(1, len(args)): if continue_next: continue_next = False continue arg = args[i] if arg.startswith('-'): # Skip the next arg too if this flag expects a value. continue_next = arg in ['-m', '-W', '-X'] continue if arg.rsplit('.')[-1] in ['zip', 'pyz', 'pyzw']: pydev_log.debug('Executing a PyZip, returning') return args break new_args.append(args[0]) else: pydev_log.debug("Process is not python, returning.") return args i = 1 # Original args should be something as: # ['X:\\pysrc\\pydevd.py', '--multiprocess', '--print-in-debugger-startup', # '--vm_type', 'python', '--client', '127.0.0.1', '--port', '56352', '--file', 'x:\\snippet1.py'] from _pydevd_bundle.pydevd_command_line_handling import setup_to_argv original = setup_to_argv(SetupHolder.setup) + ['--file'] while i < len(args): if args[i] == '-m': # Always insert at pos == 1 (i.e.: pydevd "--module" --multiprocess ...) original.insert(1, '--module') else: if args[i].startswith('-'): new_args.append(args[i]) else: break i += 1 # Note: undoing https://github.com/Elizaveta239/PyDev.Debugger/commit/053c9d6b1b455530bca267e7419a9f63bf51cddf # (i >= len(args) instead of i < len(args)) # in practice it'd raise an exception here and would return original args, which is not what we want... providing # a proper fix for https://youtrack.jetbrains.com/issue/PY-9767 elsewhere. if i < len(args) and _is_managed_arg( args[i]): # no need to add pydevd twice return args for x in original: new_args.append(x) if x == '--file': break while i < len(args): new_args.append(args[i]) i += 1 return quote_args(new_args) except: pydev_log.exception('Error patching args') return args
def add_breakpoint(self, py_db, original_filename, breakpoint_type, breakpoint_id, line, condition, func_name, expression, suspend_policy, hit_condition, is_logpoint, adjust_line=False): ''' :param str original_filename: Note: must be sent as it was received in the protocol. It may be translated in this function and its final value will be available in the returned _AddBreakpointResult. :param str breakpoint_type: One of: 'python-line', 'django-line', 'jinja2-line'. :param int breakpoint_id: :param int line: Note: it's possible that a new line was actually used. If that's the case its final value will be available in the returned _AddBreakpointResult. :param condition: Either None or the condition to activate the breakpoint. :param str func_name: If "None" (str), may hit in any context. Empty string will hit only top level. Any other value must match the scope of the method to be matched. :param str expression: None or the expression to be evaluated. :param suspend_policy: Either "NONE" (to suspend only the current thread when the breakpoint is hit) or "ALL" (to suspend all threads when a breakpoint is hit). :param str hit_condition: An expression where `@HIT@` will be replaced by the number of hits. i.e.: `@HIT@ == x` or `@HIT@ >= x` :param bool is_logpoint: If True and an expression is passed, pydevd will create an io message command with the result of the evaluation. :return _AddBreakpointResult: ''' assert original_filename.__class__ == str, 'Expected str, found: %s' % ( original_filename.__class__, ) # i.e.: bytes on py2 and str on py3 pydev_log.debug('Request for breakpoint in: %s line: %s', original_filename, line) # Parameters to reapply breakpoint. api_add_breakpoint_params = (original_filename, breakpoint_type, breakpoint_id, line, condition, func_name, expression, suspend_policy, hit_condition, is_logpoint) translated_filename = self.filename_to_server( original_filename) # Apply user path mapping. pydev_log.debug('Breakpoint (after path translation) in: %s line: %s', translated_filename, line) func_name = self.to_str(func_name) assert translated_filename.__class__ == str # i.e.: bytes on py2 and str on py3 assert func_name.__class__ == str # i.e.: bytes on py2 and str on py3 # Apply source mapping (i.e.: ipython). source_mapped_filename, new_line, multi_mapping_applied = py_db.source_mapping.map_to_server( translated_filename, line) if multi_mapping_applied: pydev_log.debug( 'Breakpoint (after source mapping) in: %s line: %s', source_mapped_filename, new_line) # Note that source mapping is internal and does not change the resulting filename nor line # (we want the outside world to see the line in the original file and not in the ipython # cell, otherwise the editor wouldn't be correct as the returned line is the line to # which the breakpoint will be moved in the editor). result = self._AddBreakpointResult(original_filename, line) # If a multi-mapping was applied, consider it the canonical / source mapped version (translated to ipython cell). translated_absolute_filename = source_mapped_filename canonical_normalized_filename = pydevd_file_utils.normcase( source_mapped_filename) line = new_line else: translated_absolute_filename = pydevd_file_utils.absolute_path( translated_filename) canonical_normalized_filename = pydevd_file_utils.canonical_normalized_path( translated_filename) if adjust_line and not translated_absolute_filename.startswith( '<'): # Validate breakpoints and adjust their positions. try: lines = sorted( _get_code_lines(translated_absolute_filename)) except Exception: pass else: if line not in lines: # Adjust to the first preceding valid line. idx = bisect.bisect_left(lines, line) if idx > 0: line = lines[idx - 1] result = self._AddBreakpointResult(original_filename, line) py_db.api_received_breakpoints[(original_filename, breakpoint_id)] = ( canonical_normalized_filename, api_add_breakpoint_params) if not translated_absolute_filename.startswith('<'): # Note: if a mapping pointed to a file starting with '<', don't validate. if not pydevd_file_utils.exists(translated_absolute_filename): result.error_code = self.ADD_BREAKPOINT_FILE_NOT_FOUND return result if (py_db.is_files_filter_enabled and not py_db.get_require_module_for_filters() and py_db.apply_files_filter( self._DummyFrame(translated_absolute_filename), translated_absolute_filename, False)): # Note that if `get_require_module_for_filters()` returns False, we don't do this check. # This is because we don't have the module name given a file at this point (in # runtime it's gotten from the frame.f_globals). # An option could be calculate it based on the filename and current sys.path, # but on some occasions that may be wrong (for instance with `__main__` or if # the user dynamically changes the PYTHONPATH). # Note: depending on the use-case, filters may be changed, so, keep on going and add the # breakpoint even with the error code. result.error_code = self.ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS if breakpoint_type == 'python-line': added_breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy, hit_condition=hit_condition, is_logpoint=is_logpoint) breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint supported_type = True else: add_plugin_breakpoint_result = None plugin = py_db.get_plugin_lazy_init() if plugin is not None: add_plugin_breakpoint_result = plugin.add_breakpoint( 'add_line_breakpoint', py_db, breakpoint_type, canonical_normalized_filename, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint) if add_plugin_breakpoint_result is not None: supported_type = True added_breakpoint, breakpoints = add_plugin_breakpoint_result file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint else: supported_type = False if not supported_type: raise NameError(breakpoint_type) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n', canonical_normalized_filename, line, func_name) if canonical_normalized_filename in file_to_id_to_breakpoint: id_to_pybreakpoint = file_to_id_to_breakpoint[ canonical_normalized_filename] else: id_to_pybreakpoint = file_to_id_to_breakpoint[ canonical_normalized_filename] = {} id_to_pybreakpoint[breakpoint_id] = added_breakpoint py_db.consolidate_breakpoints(canonical_normalized_filename, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() py_db.on_breakpoints_changed() return result
def patch_qt(qt_support_mode): ''' This method patches qt (PySide2, PySide, PyQt4, PyQt5) so that we have hooks to set the tracing for QThread. ''' if not qt_support_mode: return if qt_support_mode is True or qt_support_mode == 'True': # do not break backward compatibility qt_support_mode = 'auto' if qt_support_mode == 'auto': qt_support_mode = os.getenv('PYDEVD_PYQT_MODE', 'auto') # Avoid patching more than once global _patched_qt if _patched_qt: return pydev_log.debug('Qt support mode: %s', qt_support_mode) _patched_qt = True if qt_support_mode == 'auto': patch_qt_on_import = None try: import PySide2 # @UnresolvedImport @UnusedImport qt_support_mode = 'pyside2' except: try: import Pyside # @UnresolvedImport @UnusedImport qt_support_mode = 'pyside' except: try: import PyQt5 # @UnresolvedImport @UnusedImport qt_support_mode = 'pyqt5' except: try: import PyQt4 # @UnresolvedImport @UnusedImport qt_support_mode = 'pyqt4' except: return if qt_support_mode == 'pyside2': try: import PySide2.QtCore # @UnresolvedImport _internal_patch_qt(PySide2.QtCore, qt_support_mode) except: return elif qt_support_mode == 'pyside': try: import PySide.QtCore # @UnresolvedImport _internal_patch_qt(PySide.QtCore, qt_support_mode) except: return elif qt_support_mode == 'pyqt5': try: import PyQt5.QtCore # @UnresolvedImport _internal_patch_qt(PyQt5.QtCore) except: return elif qt_support_mode == 'pyqt4': # Ok, we have an issue here: # PyDev-452: Selecting PyQT API version using sip.setapi fails in debug mode # http://pyqt.sourceforge.net/Docs/PyQt4/incompatible_apis.html # Mostly, if the user uses a different API version (i.e.: v2 instead of v1), # that has to be done before importing PyQt4 modules (PySide/PyQt5 don't have this issue # as they only implements v2). patch_qt_on_import = 'PyQt4' def get_qt_core_module(): import PyQt4.QtCore # @UnresolvedImport return PyQt4.QtCore _patch_import_to_patch_pyqt_on_import(patch_qt_on_import, get_qt_core_module) else: raise ValueError('Unexpected qt support mode: %s' % (qt_support_mode,))
def add_breakpoint( self, py_db, filename, breakpoint_type, breakpoint_id, line, condition, func_name, expression, suspend_policy, hit_condition, is_logpoint): ''' :param str filename: Note: must be already translated for the server. :param str breakpoint_type: One of: 'python-line', 'django-line', 'jinja2-line'. :param int breakpoint_id: :param int line: :param condition: Either None or the condition to activate the breakpoint. :param str func_name: If "None" (str), may hit in any context. Empty string will hit only top level. Any other value must match the scope of the method to be matched. :param str expression: None or the expression to be evaluated. :param suspend_policy: Either "NONE" (to suspend only the current thread when the breakpoint is hit) or "ALL" (to suspend all threads when a breakpoint is hit). :param str hit_condition: An expression where `@HIT@` will be replaced by the number of hits. i.e.: `@HIT@ == x` or `@HIT@ >= x` :param bool is_logpoint: If True and an expression is passed, pydevd will create an io message command with the result of the evaluation. ''' assert filename.__class__ == str # i.e.: bytes on py2 and str on py3 assert func_name.__class__ == str # i.e.: bytes on py2 and str on py3 if not pydevd_file_utils.exists(filename): sys.stderr.write('pydev debugger: warning: trying to add breakpoint'\ ' to file that does not exist: %s (will have no effect)\n' % (filename,)) sys.stderr.flush() return if breakpoint_type == 'python-line': added_breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy, hit_condition=hit_condition, is_logpoint=is_logpoint) breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint supported_type = True else: result = None plugin = py_db.get_plugin_lazy_init() if plugin is not None: result = plugin.add_breakpoint('add_line_breakpoint', py_db, breakpoint_type, filename, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint) if result is not None: supported_type = True added_breakpoint, breakpoints = result file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint else: supported_type = False if not supported_type: raise NameError(breakpoint_type) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n' % (filename, line, func_name)) sys.stderr.flush() if filename in file_to_id_to_breakpoint: id_to_pybreakpoint = file_to_id_to_breakpoint[filename] else: id_to_pybreakpoint = file_to_id_to_breakpoint[filename] = {} id_to_pybreakpoint[breakpoint_id] = added_breakpoint py_db.consolidate_breakpoints(filename, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() py_db.on_breakpoints_changed()
def in_project_roots(self, received_filename): ''' Note: don't call directly. Use PyDb.in_project_scope (there's no caching here and it doesn't handle all possibilities for knowing whether a project is actually in the scope, it just handles the heuristics based on the absolute_normalized_filename without the actual frame). ''' DEBUG = False if received_filename.startswith(USER_CODE_BASENAMES_STARTING_WITH): if DEBUG: pydev_log.debug( 'In in_project_roots - user basenames - starts with %s (%s)', received_filename, USER_CODE_BASENAMES_STARTING_WITH) return True if received_filename.startswith(LIBRARY_CODE_BASENAMES_STARTING_WITH): if DEBUG: pydev_log.debug( 'Not in in_project_roots - library basenames - starts with %s (%s)', received_filename, LIBRARY_CODE_BASENAMES_STARTING_WITH) return False project_roots = self._get_project_roots( ) # roots are absolute/normalized. absolute_normalized_filename = self._absolute_normalized_path( received_filename) found_in_project = [] for root in project_roots: if root and absolute_normalized_filename.startswith(root): if DEBUG: pydev_log.debug('In project: %s (%s)', absolute_normalized_filename, root) found_in_project.append(root) found_in_library = [] library_roots = self._get_library_roots() for root in library_roots: if root and absolute_normalized_filename.startswith(root): found_in_library.append(root) if DEBUG: pydev_log.debug('In library: %s (%s)', absolute_normalized_filename, root) else: if DEBUG: pydev_log.debug('Not in library: %s (%s)', absolute_normalized_filename, root) if not project_roots: # If we have no project roots configured, consider it being in the project # roots if it's not found in site-packages (because we have defaults for those # and not the other way around). in_project = not found_in_library if DEBUG: pydev_log.debug('Final in project (no project roots): %s (%s)', absolute_normalized_filename, in_project) else: in_project = False if found_in_project: if not found_in_library: if DEBUG: pydev_log.debug( 'Final in project (in_project and not found_in_library): %s (True)', absolute_normalized_filename) in_project = True else: # Found in both, let's see which one has the bigger path matched. if max(len(x) for x in found_in_project) > max( len(x) for x in found_in_library): in_project = True if DEBUG: pydev_log.debug( 'Final in project (found in both): %s (%s)', absolute_normalized_filename, in_project) return in_project
def stop_on_unhandled_exception(py_db, thread, additional_info, arg): from _pydevd_bundle.pydevd_frame import handle_breakpoint_condition, handle_breakpoint_expression exctype, value, tb = arg if exctype in (KeyboardInterrupt, SystemExit): return break_on_uncaught_exceptions = py_db.break_on_uncaught_exceptions if break_on_uncaught_exceptions: exception_breakpoint = get_exception_breakpoint( exctype, break_on_uncaught_exceptions) else: exception_breakpoint = None original_excepthook(exctype, value, tb) disable_excepthook() # Avoid printing the exception for the second time. if not exception_breakpoint: return if tb is None: # sometimes it can be None, e.g. with GTK return frames = [] user_frame = None while tb: frame = tb.tb_frame if exception_breakpoint.ignore_libraries and py_db.in_project_scope( frame.f_code.co_filename): user_frame = tb.tb_frame frames.append(tb.tb_frame) tb = tb.tb_next frames_byid = dict([(id(frame), frame) for frame in frames]) if exception_breakpoint.ignore_libraries and user_frame is not None: frame = user_frame else: frame = frames[-1] add_exception_to_frame(frame, arg) if exception_breakpoint.condition is not None: eval_result = handle_breakpoint_condition(py_db, additional_info, exception_breakpoint, frame) if not eval_result: return if exception_breakpoint.expression is not None: handle_breakpoint_expression(exception_breakpoint, additional_info, frame) try: additional_info.pydev_message = exception_breakpoint.qname except: additional_info.pydev_message = exception_breakpoint.qname.encode( 'utf-8') additional_info.pydev_message = 'python-%s' % additional_info.pydev_message pydev_log.debug('Handling post-mortem stop on exception breakpoint %s' % (exception_breakpoint.qname, )) py_db.stop_on_unhandled_exception(thread, frame, frames_byid, arg)
def _on_run(self): try: content_len = -1 while not self.killReceived: try: line = self._read_line() if len(line) == 0: self.handle_except() return # Finished communication. if line.startswith(b'Content-Length:'): content_len = int(line.strip().split(b':', 1)[1]) continue if content_len != -1: # If we previously received a content length, read until a '\r\n'. if line == b'\r\n': json_contents = self._read(content_len) content_len = -1 if len(json_contents) == 0: self.handle_except() return # Finished communication. # We just received a json message, let's process it. self.process_net_command_json(self.global_debugger_holder.global_dbg, json_contents) continue else: # No content len, regular line-based protocol message (remove trailing new-line). if line.endswith(b'\n\n'): line = line[:-2] elif line.endswith(b'\n'): line = line[:-1] elif line.endswith(b'\r'): line = line[:-1] except: if not self.killReceived: traceback.print_exc() self.handle_except() return # Finished communication. # Note: the java backend is always expected to pass utf-8 encoded strings. We now work with unicode # internally and thus, we may need to convert to the actual encoding where needed (i.e.: filenames # on python 2 may need to be converted to the filesystem encoding). if hasattr(line, 'decode'): line = line.decode('utf-8') if DebugInfoHolder.DEBUG_RECORD_SOCKET_READS: sys.stderr.write(u'debugger: received >>%s<<\n' % (line,)) sys.stderr.flush() args = line.split(u'\t', 2) try: cmd_id = int(args[0]) pydev_log.debug('Received command: %s %s\n' % (ID_TO_MEANING.get(str(cmd_id), '???'), line,)) self.process_command(cmd_id, int(args[1]), args[2]) except: if traceback is not None and sys is not None: # Could happen at interpreter shutdown traceback.print_exc() sys.stderr.write("Can't process net command: %s\n" % line) sys.stderr.flush() except: if not self.killReceived: if traceback is not None: # Could happen at interpreter shutdown traceback.print_exc() self.handle_except()
def trace_dispatch(self, frame, event, arg): # ENDIF main_debugger, filename, info, thread, frame_skips_cache, frame_cache_key = self._args # print('frame trace_dispatch %s %s %s %s %s' % (frame.f_lineno, frame.f_code.co_name, frame.f_code.co_filename, event, info.pydev_step_cmd)) # The thread can be already suspended by another function, e.g. built-in breakpoint hook. if info.is_tracing: return None try: info.is_tracing = True line = frame.f_lineno line_cache_key = (frame_cache_key, line) if main_debugger._finish_debugging_session: if event != 'call': frame.f_trace = NO_FTRACE return None # IFDEF CYTHON # if event == 'opcode': # instructions = self._get_instructions(frame) # for i, inst in enumerate(instructions): # if inst.offset == frame.f_lasti: # opname, arg, argval = inst.opname, inst.arg, str(inst.argval) # print('frame trace_dispatch %s %s %s %s %s %s %s %s' % (frame.f_lineno, frame.f_lasti, frame.f_code.co_name, # frame.f_code.co_filename, event, opname, arg, argval)) # try: # self._bytecode_offset = instructions[i + 1].offset # except IndexError: # break # return self.trace_dispatch # ENDIF plugin_manager = main_debugger.plugin is_exception_event = event == 'exception' has_exception_breakpoints = main_debugger.break_on_caught_exceptions or main_debugger.has_plugin_exception_breaks \ or main_debugger.stop_on_failed_tests if is_exception_event: if has_exception_breakpoints: should_stop, frame = self.should_stop_on_exception( frame, event, arg) if should_stop: self.handle_exception(frame, event, arg) # No need to reset frame.f_trace to keep the same trace function. return self.trace_dispatch is_line = False is_return = False is_call = False else: is_line = event == 'line' is_return = event == 'return' is_call = event == 'call' if not is_line and not is_return and not is_call: # Unexpected: just keep the same trace func. # No need to reset frame.f_trace to keep the same trace function. return self.trace_dispatch need_signature_trace_return = False if main_debugger.signature_factory is not None: if is_call: need_signature_trace_return = send_signature_call_trace( main_debugger, frame, filename) elif is_return: send_signature_return_trace(main_debugger, frame, filename, arg) stop_frame = info.pydev_step_stop step_cmd = info.pydev_step_cmd is_generator_or_coroutime = frame.f_code.co_flags & 0xa0 # 0xa0 == CO_GENERATOR = 0x20 | CO_COROUTINE = 0x80 breakpoints_for_file = main_debugger.breakpoints.get(filename) if not is_exception_event: if is_generator_or_coroutime: if is_return: # Dealing with coroutines and generators: # When in a coroutine we change the perceived event to the debugger because # a call, StopIteration exception and return are usually just pausing/unpausing it. returns_cache_key = (frame_cache_key, 'returns') return_lines = frame_skips_cache.get(returns_cache_key) if return_lines is None: # Note: we're collecting the return lines by inspecting the bytecode as # there are multiple returns and multiple stop iterations when awaiting and # it doesn't give any clear indication when a coroutine or generator is # finishing or just pausing. return_lines = set() for x in main_debugger.collect_return_info( frame.f_code): # Note: cython does not support closures in cpdefs (so we can't use # a list comprehension). return_lines.add(x.return_line) frame_skips_cache[returns_cache_key] = return_lines if line not in return_lines: # Not really a return (coroutine/generator paused). return self.trace_dispatch elif is_call: # Don't stop when calling coroutines, we will on other event anyway if necessary. return self.trace_dispatch can_skip = False if info.pydev_state == 1: # STATE_RUN = 1 # we can skip if: # - we have no stop marked # - we should make a step return/step over and we're not in the current frame # CMD_STEP_RETURN = 109, CMD_STEP_OVER = 108 can_skip = (step_cmd == -1 and stop_frame is None) \ or (step_cmd in (109, 108) and stop_frame is not frame) if can_skip: if plugin_manager is not None and main_debugger.has_plugin_line_breaks: can_skip = not plugin_manager.can_not_skip( main_debugger, self, frame, info) # CMD_STEP_OVER = 108 if can_skip and main_debugger.show_return_values and info.pydev_step_cmd == 108 and frame.f_back is info.pydev_step_stop: # trace function for showing return values after step over can_skip = False # 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 # also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway, # so, that's why the additional checks are there. if not breakpoints_for_file: if can_skip: if has_exception_breakpoints: frame.f_trace = self.trace_exception return self.trace_exception else: if need_signature_trace_return: frame.f_trace = self.trace_return return self.trace_return else: if not is_call: frame.f_trace = NO_FTRACE return None else: # When cached, 0 means we don't have a breakpoint and 1 means we have. if can_skip: breakpoints_in_line_cache = frame_skips_cache.get( line_cache_key, -1) if breakpoints_in_line_cache == 0: # No need to reset frame.f_trace to keep the same trace function. return self.trace_dispatch breakpoints_in_frame_cache = frame_skips_cache.get( frame_cache_key, -1) if breakpoints_in_frame_cache != -1: # Gotten from cache. has_breakpoint_in_frame = breakpoints_in_frame_cache == 1 else: has_breakpoint_in_frame = False # Checks the breakpoint to see if there is a context match in some function curr_func_name = frame.f_code.co_name # global context is set with an empty name if curr_func_name in ('?', '<module>', '<lambda>'): curr_func_name = '' for breakpoint in dict_iter_values( breakpoints_for_file ): # jython does not support itervalues() # will match either global or some function if breakpoint.func_name in ('None', curr_func_name): has_breakpoint_in_frame = True break # Cache the value (1 or 0 or -1 for default because of cython). if has_breakpoint_in_frame: frame_skips_cache[frame_cache_key] = 1 else: frame_skips_cache[frame_cache_key] = 0 if can_skip and not has_breakpoint_in_frame: if has_exception_breakpoints: frame.f_trace = self.trace_exception return self.trace_exception else: if need_signature_trace_return: frame.f_trace = self.trace_return return self.trace_return else: if not is_call: frame.f_trace = NO_FTRACE return None # We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame # print('NOT skipped: %s %s %s %s' % (frame.f_lineno, frame.f_code.co_name, event, frame.__class__.__name__)) try: flag = False # return is not taken into account for breakpoint hit because we'd have a double-hit in this case # (one for the line and the other for the return). stop_info = {} breakpoint = None exist_result = False stop = False bp_type = None smart_stop_frame = info.pydev_smart_step_context.smart_step_stop context_start_line = info.pydev_smart_step_context.start_line context_end_line = info.pydev_smart_step_context.end_line is_within_context = context_start_line <= line <= context_end_line if not is_return and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None and line in breakpoints_for_file: breakpoint = breakpoints_for_file[line] new_frame = frame stop = True if step_cmd == CMD_STEP_OVER: if stop_frame is frame and (is_line or is_return): stop = False # we don't stop on breakpoint if we have to stop by step-over (it will be processed later) elif is_generator_or_coroutime and frame.f_back and frame.f_back is stop_frame: stop = False # we don't stop on breakpoint if stepping is active and we enter a `genexpr` or coroutine context elif step_cmd == CMD_SMART_STEP_INTO and ( frame.f_back is smart_stop_frame and is_within_context): stop = False elif plugin_manager is not None and main_debugger.has_plugin_line_breaks: result = plugin_manager.get_breakpoint( main_debugger, self, frame, event, self._args) if result: exist_result = True flag, breakpoint, new_frame, bp_type = result if breakpoint: # ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint # lets do the conditional stuff here if stop or exist_result: eval_result = False if breakpoint.has_condition: eval_result = handle_breakpoint_condition( main_debugger, info, breakpoint, new_frame) if breakpoint.expression is not None: handle_breakpoint_expression( breakpoint, info, new_frame) if breakpoint.is_logpoint and info.pydev_message is not None and len( info.pydev_message) > 0: cmd = main_debugger.cmd_factory.make_io_message( info.pydev_message + os.linesep, '1') main_debugger.writer.add_command(cmd) if breakpoint.has_condition and not eval_result: # No need to reset frame.f_trace to keep the same trace function. return self.trace_dispatch if is_call and frame.f_code.co_name in ('<module>', '<lambda>'): # If we find a call for a module, it means that the module is being imported/executed for the # first time. In this case we have to ignore this hit as it may later duplicated by a # line event at the same place (so, if there's a module with a print() in the first line # the user will hit that line twice, which is not what we want). # # As for lambda, as it only has a single statement, it's not interesting to trace # its call and later its line event as they're usually in the same line. # No need to reset frame.f_trace to keep the same trace function. return self.trace_dispatch else: # if the frame is traced after breakpoint stop, # but the file should be ignored while stepping because of filters if step_cmd != -1: if main_debugger.is_filter_enabled and main_debugger.is_ignored_by_filters( filename): # ignore files matching stepping filters # No need to reset frame.f_trace to keep the same trace function. return self.trace_dispatch if main_debugger.is_filter_libraries and not main_debugger.in_project_scope( filename): # ignore library files while stepping # No need to reset frame.f_trace to keep the same trace function. return self.trace_dispatch if main_debugger.show_return_values or main_debugger.remove_return_values_flag: self.manage_return_values(main_debugger, frame, event, arg) if stop: self.set_suspend( thread, CMD_SET_BREAK, suspend_other_threads=breakpoint and breakpoint.suspend_policy == "ALL", ) elif flag and plugin_manager is not None: result = plugin_manager.suspend(main_debugger, thread, frame, bp_type) if result: frame = result # if thread has a suspend flag, we suspend with a busy wait if info.pydev_state == STATE_SUSPEND: self.do_wait_suspend(thread, frame, event, arg) # No need to reset frame.f_trace to keep the same trace function. return self.trace_dispatch else: if not breakpoint and is_line: # No stop from anyone and no breakpoint found in line (cache that). frame_skips_cache[line_cache_key] = 0 except KeyboardInterrupt: self.clear_run_state(info) raise except: traceback.print_exc() raise # step handling. We stop when we hit the right frame try: should_skip = 0 if pydevd_dont_trace.should_trace_hook is not None: if self.should_skip == -1: # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times). # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code # Which will be handled by this frame is read-only, so, we can cache it safely. if not pydevd_dont_trace.should_trace_hook( frame, filename): # -1, 0, 1 to be Cython-friendly should_skip = self.should_skip = 1 else: should_skip = self.should_skip = 0 else: should_skip = self.should_skip plugin_stop = False if should_skip: stop = False elif step_cmd == CMD_SMART_STEP_INTO: stop = False if smart_stop_frame is frame: if not is_within_context or not IS_CPYTHON: # We don't stop on jumps in multiline statements, which the Python interpreter does in some cases, # if we they happen in smart step into context. info.pydev_func_name = '.invalid.' # Must match the type in cython stop = True # act as if we did a step into if is_line or is_exception_event: curr_func_name = frame.f_code.co_name # global context is set with an empty name if curr_func_name in ( '?', '<module>') or curr_func_name is None: curr_func_name = '' if smart_stop_frame and smart_stop_frame is frame.f_back: if curr_func_name == info.pydev_func_name and not IS_CPYTHON: # for implementations other than CPython we don't perform any additional checks stop = True else: try: if curr_func_name != info.pydev_func_name and frame.f_back: # try to find function call name using bytecode analysis curr_func_name = find_last_call_name( frame.f_back) if curr_func_name == info.pydev_func_name: stop = find_last_func_call_order(frame.f_back, context_start_line) \ == info.pydev_smart_step_context.call_order except: pydev_log.debug( "Exception while handling smart step into in frame tracer, step into will be performed instead." ) info.pydev_smart_step_context.reset() stop = True # act as if we did a step into # we have to check this case for situations when a user has tried to step into a native function or method, # e.g. `len()`, `list.append()`, etc and this was the only call in a return statement if smart_stop_frame is frame and is_return: stop = True elif step_cmd == CMD_STEP_INTO: stop = is_line or is_return if plugin_manager is not None: result = plugin_manager.cmd_step_into( main_debugger, frame, event, self._args, stop_info, stop) if result: stop, plugin_stop = result elif step_cmd == CMD_STEP_INTO_MY_CODE: if main_debugger.in_project_scope( frame.f_code.co_filename): stop = is_line elif step_cmd in (CMD_STEP_OVER, CMD_STEP_INTO_COROUTINE): stop = stop_frame is frame if stop: if is_line: # the only case we shouldn't stop on a line, is when we traversing though asynchronous framework machinery if step_cmd == CMD_STEP_INTO_COROUTINE: stop = main_debugger.in_project_scope( frame.f_code.co_filename) elif is_return: stop = frame.f_back and main_debugger.in_project_scope( frame.f_back.f_code.co_filename) if not stop: back = frame.f_back if back: info.pydev_step_stop = back if main_debugger.in_project_scope( frame.f_code.co_filename): # we are returning from the project scope, step over should always lead to the project scope if is_generator_or_coroutime and step_cmd == CMD_STEP_OVER: # setting ad hoc command to ensure we will skip line stops in an asynchronous framework info.pydev_step_cmd = CMD_STEP_INTO_COROUTINE else: # we were already outside the project scope because of step into or breakpoint, it's ok to stop # if we are not chopping a way through an asynchronous framework stop = not step_cmd == CMD_STEP_INTO_COROUTINE else: # if there's no back frame, we just stop as soon as possible info.pydev_step_cmd = CMD_STEP_INTO info.pydev_step_stop = None else: stop = False if CMD_STEP_OVER and plugin_manager is not None: result = plugin_manager.cmd_step_over( main_debugger, frame, event, self._args, stop_info, stop) if result: stop, plugin_stop = result elif step_cmd == CMD_STEP_RETURN: stop = is_return and stop_frame is frame else: stop = False if stop and step_cmd != -1 and is_return and IS_PY3K and hasattr( frame, "f_back"): f_code = getattr(frame.f_back, 'f_code', None) if f_code is not None: back_filename = os.path.basename(f_code.co_filename) file_type = get_file_type(back_filename) if file_type == PYDEV_FILE: stop = False if plugin_stop: stopped_on_plugin = plugin_manager.stop( main_debugger, frame, event, self._args, stop_info, arg, step_cmd) elif stop: if is_line: self.set_suspend(thread, step_cmd) self.do_wait_suspend(thread, frame, event, arg) else: # return event back = frame.f_back if back is not None: # When we get to the pydevd run function, the debugging has actually finished for the main thread # (note that it can still go on for other threads, but for this one, we just make it finish) # So, just setting it to None should be OK _, back_filename, base = get_abs_path_real_path_and_base_from_frame( back) if (base, back.f_code.co_name) in (DEBUG_START, DEBUG_START_PY3K): back = None elif base == TRACE_PROPERTY: # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging) # if we're in a return, we want it to appear to the user in the previous frame! if not is_call: frame.f_trace = NO_FTRACE return None elif pydevd_dont_trace.should_trace_hook is not None: if not pydevd_dont_trace.should_trace_hook( back, back_filename): # In this case, we'll have to skip the previous one because it shouldn't be traced. # Also, we have to reset the tracing, because if the parent's parent (or some # other parent) has to be traced and it's not currently, we wouldn't stop where # we should anymore (so, a step in/over/return may not stop anywhere if no parent is traced). # Related test: _debugger_case17a.py main_debugger.set_trace_for_frame_and_parents( back) if not is_call: frame.f_trace = NO_FTRACE return None if back is not None: # if we're in a return, we want it to appear to the user in the previous frame! self.set_suspend(thread, step_cmd) self.do_wait_suspend(thread, back, event, arg) else: # in jython we may not have a back frame self.clear_run_state(info) except KeyboardInterrupt: self.clear_run_state(info) raise except: try: traceback.print_exc() info.pydev_step_cmd = -1 except: if not is_call: frame.f_trace = NO_FTRACE return None # if we are quitting, let's stop the tracing if not main_debugger.quitting: # No need to reset frame.f_trace to keep the same trace function. return self.trace_dispatch else: if not is_call: frame.f_trace = NO_FTRACE return None finally: info.is_tracing = False
def _patch_threading_to_hide_pydevd_threads(): ''' Patches the needed functions on the `threading` module so that the pydevd threads are hidden. Note that we patch the functions __code__ to avoid issues if some code had already imported those variables prior to the patching. ''' found_load_names = _collect_load_names(threading.enumerate) # i.e.: we'll only apply the patching if the function seems to be what we expect. new_threading_enumerate = None if found_load_names == set( ('_active_limbo_lock', '_limbo', '_active', 'values', 'list')): pydev_log.debug( 'Applying patching to hide pydevd threads (Py3 version).') def new_threading_enumerate(): with _active_limbo_lock: ret = list(_active.values()) + list(_limbo.values()) return [ t for t in ret if not getattr(t, 'is_pydev_daemon_thread', False) ] elif found_load_names == set( ('_active_limbo_lock', '_limbo', '_active', 'values')): pydev_log.debug( 'Applying patching to hide pydevd threads (Py2 version).') def new_threading_enumerate(): with _active_limbo_lock: ret = _active.values() + _limbo.values() return [ t for t in ret if not getattr(t, 'is_pydev_daemon_thread', False) ] else: pydev_log.info( 'Unable to hide pydevd threads. Found names in threading.enumerate: %s', found_load_names) if new_threading_enumerate is not None: def pydevd_saved_threading_enumerate(): with threading._active_limbo_lock: return list(threading._active.values()) + list( threading._limbo.values()) _pydev_saved_modules.pydevd_saved_threading_enumerate = pydevd_saved_threading_enumerate threading.enumerate.__code__ = new_threading_enumerate.__code__ # We also need to patch the active count (to match what we have in the enumerate). def new_active_count(): # Note: as this will be executed in the `threading` module, `enumerate` will # actually be threading.enumerate. return len(enumerate()) threading.active_count.__code__ = new_active_count.__code__ # When shutting down, Python (on some versions) may do something as: # # def _pickSomeNonDaemonThread(): # for t in enumerate(): # if not t.daemon and t.is_alive(): # return t # return None # # But in this particular case, we do want threads with `is_pydev_daemon_thread` to appear # explicitly due to the pydevd `CheckAliveThread` (because we want the shutdown to wait on it). # So, it can't rely on the `enumerate` for that anymore as it's patched to not return pydevd threads. if hasattr(threading, '_pickSomeNonDaemonThread'): def new_pick_some_non_daemon_thread(): with _active_limbo_lock: # Ok for py2 and py3. threads = list(_active.values()) + list(_limbo.values()) for t in threads: if not t.daemon and t.is_alive(): return t return None threading._pickSomeNonDaemonThread.__code__ = new_pick_some_non_daemon_thread.__code__
def patch_args(args, is_exec=False): ''' :param list args: Arguments to patch. :param bool is_exec: If it's an exec, the current process will be replaced (this means we have to keep the same ppid). ''' try: pydev_log.debug("Patching args: %s", args) original_args = args args = remove_quotes_from_args(args) from pydevd import SetupHolder new_args = [] if len(args) == 0: return original_args if is_python(args[0]): ind_c = get_c_option_index(args) if ind_c != -1: host, port = _get_host_port() if port is not None: new_args.extend(args) new_args[ind_c + 1] = _get_python_c_args( host, port, ind_c, args, SetupHolder.setup) return quote_args(new_args) else: # Check for Python ZIP Applications and don't patch the args for them. # Assumes the first non `-<flag>` argument is what we need to check. # There's probably a better way to determine this but it works for most cases. continue_next = False for i in range(1, len(args)): if continue_next: continue_next = False continue arg = args[i] if arg.startswith(_get_str_type_compatible(arg, '-')): # Skip the next arg too if this flag expects a value. continue_next = arg in _get_str_type_compatible( arg, ['-m', '-W', '-X']) continue dot = _get_str_type_compatible(arg, '.') extensions = _get_str_type_compatible( arg, ['zip', 'pyz', 'pyzw']) if arg.rsplit(dot)[-1] in extensions: pydev_log.debug('Executing a PyZip, returning') return original_args break new_args.append(args[0]) else: pydev_log.debug("Process is not python, returning.") return original_args i = 1 # Original args should be something as: # ['X:\\pysrc\\pydevd.py', '--multiprocess', '--print-in-debugger-startup', # '--vm_type', 'python', '--client', '127.0.0.1', '--port', '56352', '--file', 'x:\\snippet1.py'] from _pydevd_bundle.pydevd_command_line_handling import setup_to_argv original = setup_to_argv( _get_setup_updated_with_protocol_and_ppid( SetupHolder.setup, is_exec=is_exec)) + ['--file'] module_name = None m_flag = _get_str_type_compatible(args[i], '-m') while i < len(args): if args[i] == m_flag: # Always insert at pos == 1 (i.e.: pydevd "--module" --multiprocess ...) original.insert(1, '--module') elif args[i].startswith(m_flag): # Case where the user does: python -mmodule_name (using a single parameter). original.insert(1, '--module') module_name = args[i][2:] else: if args[i].startswith(_get_str_type_compatible(args[i], '-')): new_args.append(args[i]) else: break i += 1 # Note: undoing https://github.com/Elizaveta239/PyDev.Debugger/commit/053c9d6b1b455530bca267e7419a9f63bf51cddf # (i >= len(args) instead of i < len(args)) # in practice it'd raise an exception here and would return original args, which is not what we want... providing # a proper fix for https://youtrack.jetbrains.com/issue/PY-9767 elsewhere. if i < len(args) and _is_managed_arg( args[i]): # no need to add pydevd twice return original_args for x in original: new_args.append(x) if x == _get_str_type_compatible(x, '--file'): break if module_name is not None: new_args.append(module_name) while i < len(args): new_args.append(args[i]) i += 1 return quote_args(new_args) except: pydev_log.exception('Error patching args') return original_args
def set_library_roots(self, roots): self._library_roots = self._fix_roots(roots) pydev_log.debug("LIBRARY_ROOTS %s\n" % roots)
import types from _pydev_bundle import pydev_log from _pydevd_bundle import pydevd_trace_api try: from pydevd_plugins import django_debug except: django_debug = None pydev_log.debug('Unable to load django_debug plugin') try: from pydevd_plugins import jinja2_debug except: jinja2_debug = None pydev_log.debug('Unable to load jinja2_debug plugin') def load_plugins(): plugins = [] if django_debug is not None: plugins.append(django_debug) if jinja2_debug is not None: plugins.append(jinja2_debug) return plugins def bind_func_to_method(func, obj, method_name): bound_method = types.MethodType(func, obj) setattr(obj, method_name, bound_method)
def should_stop_on_exception(self, frame, event, arg): # ENDIF # main_debugger, _filename, info, _thread = self._args main_debugger = self._args[0] info = self._args[2] should_stop = False # STATE_SUSPEND = 2 if info.pydev_state != 2: #and breakpoint is not None: exception, value, trace = arg if trace is not None and hasattr(trace, 'tb_next'): # on jython trace is None on the first event and it may not have a tb_next. exception_breakpoint = get_exception_breakpoint( exception, main_debugger.break_on_caught_exceptions) if exception_breakpoint is not None: if exception_breakpoint.condition is not None: eval_result = handle_breakpoint_condition( main_debugger, info, exception_breakpoint, frame) if not eval_result: return False, frame if exception_breakpoint.ignore_libraries: if not main_debugger.is_exception_trace_in_project_scope( trace): pydev_log.debug( "Ignore exception %s in library %s -- (%s)" % (exception, frame.f_code.co_filename, frame.f_code.co_name)) return False, frame if ignore_exception_trace(trace): return False, frame was_just_raised = just_raised(trace) if was_just_raised: if main_debugger.skip_on_exceptions_thrown_in_same_context: # Option: Don't break if an exception is caught in the same function from which it is thrown return False, frame if exception_breakpoint.notify_on_first_raise_only: if main_debugger.skip_on_exceptions_thrown_in_same_context: # In this case we never stop if it was just raised, so, to know if it was the first we # need to check if we're in the 2nd method. if not was_just_raised and not just_raised( trace.tb_next): return False, frame # I.e.: we stop only when we're at the caller of a method that throws an exception else: if not was_just_raised: return False, frame # I.e.: we stop only when it was just raised # If it got here we should stop. should_stop = True try: info.pydev_message = exception_breakpoint.qname except: info.pydev_message = exception_breakpoint.qname.encode( 'utf-8') # Always add exception to frame (must remove later after we proceed). add_exception_to_frame(frame, (exception, value, trace)) else: # No regular exception breakpoint, let's see if some plugin handles it. try: if main_debugger.plugin is not None: result = main_debugger.plugin.exception_break( main_debugger, self, frame, self._args, arg) if result: should_stop, frame = result except: should_stop = False if should_stop: if exception_breakpoint is not None and exception_breakpoint.expression is not None: handle_breakpoint_expression(exception_breakpoint, info, frame) return should_stop, frame
def log_debug(msg): pydev_log.debug(msg)
def process_net_command(py_db, cmd_id, seq, text): '''Processes a command received from the Java side @param cmd_id: the id of the command @param seq: the sequence of the command @param text: the text received in the command @note: this method is run as a big switch... after doing some tests, it's not clear whether changing it for a dict id --> function call will have better performance result. A simple test with xrange(10000000) showed that the gains from having a fast access to what should be executed are lost because of the function call in a way that if we had 10 elements in the switch the if..elif are better -- but growing the number of choices makes the solution with the dispatch look better -- so, if this gets more than 20-25 choices at some time, it may be worth refactoring it (actually, reordering the ifs so that the ones used mostly come before probably will give better performance). ''' # print(ID_TO_MEANING[str(cmd_id)], repr(text)) py_db._main_lock.acquire() try: try: cmd = None if cmd_id == CMD_RUN: py_db.ready_to_run = True elif cmd_id == CMD_SET_PROTOCOL: expected = (NetCommand.HTTP_PROTOCOL, NetCommand.QUOTED_LINE_PROTOCOL) text = text.strip() assert text.strip( ) in expected, 'Protocol (%s) should be one of: %s' % ( text, expected) NetCommand.protocol = text cmd = py_db.cmd_factory.make_protocol_set_message(seq) elif cmd_id == CMD_VERSION: # response is version number # ide_os should be 'WINDOWS' or 'UNIX'. # Default based on server process (although ideally the IDE should # provide it). if IS_WINDOWS: ide_os = 'WINDOWS' else: ide_os = 'UNIX' # Breakpoints can be grouped by 'LINE' or by 'ID'. breakpoints_by = 'LINE' splitted = text.split('\t') if len(splitted) == 1: _local_version = splitted elif len(splitted) == 2: _local_version, ide_os = splitted elif len(splitted) == 3: _local_version, ide_os, breakpoints_by = splitted if breakpoints_by == 'ID': py_db._set_breakpoints_with_id = True else: py_db._set_breakpoints_with_id = False pydevd_file_utils.set_ide_os(ide_os) cmd = py_db.cmd_factory.make_version_message(seq) elif cmd_id == CMD_LIST_THREADS: # response is a list of threads cmd = py_db.cmd_factory.make_list_threads_message(seq) elif cmd_id == CMD_GET_THREAD_STACK: # Receives a thread_id and a given timeout, which is the time we should # wait to the provide the stack if a given thread is still not suspended. if '\t' in text: thread_id, timeout = text.split('\t') timeout = float(timeout) else: thread_id = text timeout = .5 # Default timeout is .5 seconds # If it's already suspended, get it right away. internal_get_thread_stack = InternalGetThreadStack( seq, thread_id, py_db, set_additional_thread_info, timeout=timeout) if internal_get_thread_stack.can_be_executed_by( get_current_thread_id(threading.current_thread())): internal_get_thread_stack.do_it(py_db) else: py_db.post_internal_command(internal_get_thread_stack, '*') elif cmd_id == CMD_THREAD_SUSPEND: # Yes, thread suspend is done at this point, not through an internal command. threads = [] suspend_all = text.strip() == '*' if suspend_all: threads = pydevd_utils.get_non_pydevd_threads() elif text.startswith('__frame__:'): sys.stderr.write("Can't suspend tasklet: %s\n" % (text, )) else: threads = [pydevd_find_thread_by_id(text)] for t in threads: if t is None: continue py_db.set_suspend( t, CMD_THREAD_SUSPEND, suspend_other_threads=suspend_all, is_pause=True, ) # Break here (even if it's suspend all) as py_db.set_suspend will # take care of suspending other threads. break elif cmd_id == CMD_THREAD_RUN: threads = [] if text.strip() == '*': threads = pydevd_utils.get_non_pydevd_threads() elif text.startswith('__frame__:'): sys.stderr.write("Can't make tasklet run: %s\n" % (text, )) else: threads = [pydevd_find_thread_by_id(text)] for t in threads: if t is None: continue additional_info = set_additional_thread_info(t) additional_info.pydev_step_cmd = -1 additional_info.pydev_step_stop = None additional_info.pydev_state = STATE_RUN elif cmd_id == CMD_STEP_INTO or cmd_id == CMD_STEP_OVER or cmd_id == CMD_STEP_RETURN or \ cmd_id == CMD_STEP_INTO_MY_CODE: # we received some command to make a single step t = pydevd_find_thread_by_id(text) if t: thread_id = get_thread_id(t) int_cmd = InternalStepThread(thread_id, cmd_id) py_db.post_internal_command(int_cmd, thread_id) elif text.startswith('__frame__:'): sys.stderr.write("Can't make tasklet step command: %s\n" % (text, )) elif cmd_id in (CMD_RUN_TO_LINE, CMD_SET_NEXT_STATEMENT, CMD_SMART_STEP_INTO): if cmd_id == CMD_SMART_STEP_INTO: # we received a smart step into command thread_id, frame_id, line, func_name, call_order, start_line, end_line = text.split( '\t', 6) else: # we received some command to make a single step thread_id, line, func_name = text.split('\t', 2) if func_name == "None": # global context func_name = '' t = pydevd_find_thread_by_id(thread_id) if t: if cmd_id == CMD_SMART_STEP_INTO: int_cmd = InternalSmartStepInto( thread_id, frame_id, cmd_id, func_name, line, call_order, start_line, end_line, seq) else: int_cmd = InternalSetNextStatementThread( thread_id, cmd_id, line, func_name, seq) py_db.post_internal_command(int_cmd, thread_id) elif thread_id.startswith('__frame__:'): sys.stderr.write( "Can't set next statement in tasklet: %s\n" % (thread_id, )) elif cmd_id == CMD_RELOAD_CODE: # we received some command to make a reload of a module module_name = text.strip() thread_id = '*' # Any thread # Note: not going for the main thread because in this case it'd only do the load # when we stopped on a breakpoint. int_cmd = ReloadCodeCommand(module_name, thread_id) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_CHANGE_VARIABLE: # the text is: thread\tstackframe\tFRAME|GLOBAL\tattribute_to_change\tvalue_to_change try: thread_id, frame_id, scope, attr_and_value = text.split( '\t', 3) tab_index = attr_and_value.rindex('\t') attr = attr_and_value[0:tab_index].replace('\t', '.') value = attr_and_value[tab_index + 1:] int_cmd = InternalChangeVariable(seq, thread_id, frame_id, scope, attr, value) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_VARIABLE: # we received some command to get a variable # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tattributes* try: thread_id, frame_id, scopeattrs = text.split('\t', 2) if scopeattrs.find( '\t') != -1: # there are attributes beyond scope scope, attrs = scopeattrs.split('\t', 1) else: scope, attrs = (scopeattrs, None) int_cmd = InternalGetVariable(seq, thread_id, frame_id, scope, attrs) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_ARRAY: # we received some command to get an array variable # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tname\ttemp\troffs\tcoffs\trows\tcols\tformat try: roffset, coffset, rows, cols, format, thread_id, frame_id, scopeattrs = text.split( '\t', 7) if scopeattrs.find( '\t') != -1: # there are attributes beyond scope scope, attrs = scopeattrs.split('\t', 1) else: scope, attrs = (scopeattrs, None) int_cmd = InternalGetArray(seq, roffset, coffset, rows, cols, format, thread_id, frame_id, scope, attrs) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_SHOW_RETURN_VALUES: try: show_return_values = text.split('\t')[1] if int(show_return_values) == 1: py_db.show_return_values = True else: if py_db.show_return_values: # We should remove saved return values py_db.remove_return_values_flag = True py_db.show_return_values = False pydev_log.debug("Show return values: %s\n" % py_db.show_return_values) except: traceback.print_exc() elif cmd_id == CMD_SET_UNIT_TEST_DEBUGGING_MODE: py_db.set_unit_tests_debugging_mode() elif cmd_id == CMD_LOAD_FULL_VALUE: try: thread_id, frame_id, scopeattrs = text.split('\t', 2) vars = scopeattrs.split(NEXT_VALUE_SEPARATOR) int_cmd = InternalLoadFullValue(seq, thread_id, frame_id, vars) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_COMPLETIONS: # we received some command to get a variable # the text is: thread_id\tframe_id\tactivation token try: thread_id, frame_id, scope, act_tok = text.split('\t', 3) int_cmd = InternalGetCompletions(seq, thread_id, frame_id, act_tok) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_DESCRIPTION: try: thread_id, frame_id, expression = text.split('\t', 2) int_cmd = InternalGetDescription(seq, thread_id, frame_id, expression) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_FRAME: thread_id, frame_id, scope = text.split('\t', 2) int_cmd = InternalGetFrame(seq, thread_id, frame_id) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_SET_BREAK: # func name: 'None': match anything. Empty: match global, specified: only method context. # command to add some breakpoint. # text is file\tline. Add to breakpoints dictionary suspend_policy = "NONE" # Can be 'NONE' or 'ALL' is_logpoint = False hit_condition = None if py_db._set_breakpoints_with_id: try: try: breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint, suspend_policy = text.split( '\t', 9) except ValueError: # not enough values to unpack # No suspend_policy passed (use default). breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint = text.split( '\t', 8) is_logpoint = is_logpoint == 'True' except ValueError: # not enough values to unpack breakpoint_id, type, file, line, func_name, condition, expression = text.split( '\t', 6) breakpoint_id = int(breakpoint_id) line = int(line) # We must restore new lines and tabs as done in # AbstractDebugTarget.breakpointAdded condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n'). \ replace("@_@TAB_CHAR@_@", '\t').strip() expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n'). \ replace("@_@TAB_CHAR@_@", '\t').strip() else: # Note: this else should be removed after PyCharm migrates to setting # breakpoints by id (and ideally also provides func_name). type, file, line, func_name, suspend_policy, condition, expression = text.split( '\t', 6) # If we don't have an id given for each breakpoint, consider # the id to be the line. breakpoint_id = line = int(line) condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n'). \ replace("@_@TAB_CHAR@_@", '\t').strip() expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n'). \ replace("@_@TAB_CHAR@_@", '\t').strip() if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. file = file.encode(file_system_encoding) if pydevd_file_utils.is_real_file(file): file = pydevd_file_utils.norm_file_to_server(file) if not pydevd_file_utils.exists(file): sys.stderr.write( 'pydev debugger: warning: trying to add breakpoint' ' to file that does not exist: %s (will have no effect)\n' % (file, )) sys.stderr.flush() if condition is not None and (len(condition) <= 0 or condition == "None"): condition = None if expression is not None and (len(expression) <= 0 or expression == "None"): expression = None if hit_condition is not None and (len(hit_condition) <= 0 or hit_condition == "None"): hit_condition = None if type == 'python-line': breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy, hit_condition=hit_condition, is_logpoint=is_logpoint) breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint supported_type = True else: result = None plugin = py_db.get_plugin_lazy_init() if plugin is not None: result = plugin.add_breakpoint( 'add_line_breakpoint', py_db, type, file, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint) if result is not None: supported_type = True breakpoint, breakpoints = result file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint else: supported_type = False if not supported_type: if type == 'jupyter-line': return else: raise NameError(type) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: pydev_log.debug( 'Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name.encode('utf-8'))) sys.stderr.flush() if file in file_to_id_to_breakpoint: id_to_pybreakpoint = file_to_id_to_breakpoint[file] else: id_to_pybreakpoint = file_to_id_to_breakpoint[file] = {} id_to_pybreakpoint[breakpoint_id] = breakpoint py_db.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks( ) if py_db.has_plugin_line_breaks: py_db.frame_eval_func = None py_db.on_breakpoints_changed() elif cmd_id == CMD_REMOVE_BREAK: #command to remove some breakpoint #text is type\file\tid. Remove from breakpoints dictionary breakpoint_type, file, breakpoint_id = text.split('\t', 2) if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. file = file.encode(file_system_encoding) if pydevd_file_utils.is_real_file(file): file = pydevd_file_utils.norm_file_to_server(file) try: breakpoint_id = int(breakpoint_id) except ValueError: pydev_log.error( 'Error removing breakpoint. Expected breakpoint_id to be an int. Found: %s' % (breakpoint_id, )) else: file_to_id_to_breakpoint = None if breakpoint_type == 'python-line': breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint elif py_db.get_plugin_lazy_init() is not None: result = py_db.plugin.get_breakpoints( py_db, breakpoint_type) if result is not None: file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint breakpoints = result if file_to_id_to_breakpoint is None: pydev_log.error( 'Error removing breakpoint. Cant handle breakpoint of type %s' % breakpoint_type) else: try: id_to_pybreakpoint = file_to_id_to_breakpoint.get( file, {}) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: existing = id_to_pybreakpoint[breakpoint_id] sys.stderr.write( 'Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % (file, existing.line, existing.func_name.encode('utf-8'), breakpoint_id)) del id_to_pybreakpoint[breakpoint_id] py_db.consolidate_breakpoints( file, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks( ) except KeyError: pydev_log.error( "Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n" % (file, breakpoint_id, dict_keys(id_to_pybreakpoint))) py_db.on_breakpoints_changed(removed=True) elif cmd_id == CMD_EVALUATE_EXPRESSION or cmd_id == CMD_EXEC_EXPRESSION: #command to evaluate the given expression #text is: thread\tstackframe\tLOCAL\texpression temp_name = "" try: thread_id, frame_id, scope, expression, trim, temp_name = text.split( '\t', 5) except ValueError: thread_id, frame_id, scope, expression, trim = text.split( '\t', 4) int_cmd = InternalEvaluateExpression( seq, thread_id, frame_id, expression, cmd_id == CMD_EXEC_EXPRESSION, int(trim) == 1, temp_name) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_CONSOLE_EXEC: #command to exec expression in console, in case expression is only partially valid 'False' is returned #text is: thread\tstackframe\tLOCAL\texpression thread_id, frame_id, scope, expression = text.split('\t', 3) int_cmd = InternalConsoleExec(seq, thread_id, frame_id, expression) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_SET_PY_EXCEPTION: # Command which receives set of exceptions on which user wants to break the debugger # text is: # # break_on_uncaught; # break_on_caught; # skip_on_exceptions_thrown_in_same_context; # ignore_exceptions_thrown_in_lines_with_ignore_exception; # ignore_libraries; # TypeError;ImportError;zipimport.ZipImportError; # # i.e.: true;true;true;true;true;TypeError;ImportError;zipimport.ZipImportError; # # This API is optional and works 'in bulk' -- it's possible # to get finer-grained control with CMD_ADD_EXCEPTION_BREAK/CMD_REMOVE_EXCEPTION_BREAK # which allows setting caught/uncaught per exception. splitted = text.split(';') py_db.break_on_uncaught_exceptions = {} py_db.break_on_caught_exceptions = {} if len(splitted) >= 5: if splitted[0] == 'true': break_on_uncaught = True else: break_on_uncaught = False if splitted[1] == 'true': break_on_caught = True else: break_on_caught = False if splitted[2] == 'true': py_db.skip_on_exceptions_thrown_in_same_context = True else: py_db.skip_on_exceptions_thrown_in_same_context = False if splitted[3] == 'true': py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = True else: py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = False if splitted[4] == 'true': ignore_libraries = True else: ignore_libraries = False for exception_type in splitted[5:]: exception_type = exception_type.strip() if not exception_type: continue exception_breakpoint = py_db.add_break_on_exception( exception_type, condition=None, expression=None, notify_on_handled_exceptions=break_on_caught, notify_on_unhandled_exceptions=break_on_uncaught, notify_on_first_raise_only=True, ignore_libraries=ignore_libraries, ) py_db.on_breakpoints_changed() else: sys.stderr.write( "Error when setting exception list. Received: %s\n" % (text, )) elif cmd_id == CMD_GET_FILE_CONTENTS: if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. text = text.encode(file_system_encoding) if os.path.exists(text): f = open(text, 'r') try: source = f.read() finally: f.close() cmd = py_db.cmd_factory.make_get_file_contents(seq, source) elif cmd_id == CMD_SET_PROPERTY_TRACE: # Command which receives whether to trace property getter/setter/deleter # text is feature_state(true/false);disable_getter/disable_setter/disable_deleter if text != "": splitted = text.split(';') if len(splitted) >= 3: if py_db.disable_property_trace is False and splitted[ 0] == 'true': # Replacing property by custom property only when the debugger starts pydevd_traceproperty.replace_builtin_property() py_db.disable_property_trace = True # Enable/Disable tracing of the property getter if splitted[1] == 'true': py_db.disable_property_getter_trace = True else: py_db.disable_property_getter_trace = False # Enable/Disable tracing of the property setter if splitted[2] == 'true': py_db.disable_property_setter_trace = True else: py_db.disable_property_setter_trace = False # Enable/Disable tracing of the property deleter if splitted[3] == 'true': py_db.disable_property_deleter_trace = True else: py_db.disable_property_deleter_trace = False else: # User hasn't configured any settings for property tracing pass elif cmd_id == CMD_ADD_EXCEPTION_BREAK: # Note that this message has some idiosyncrasies... # # notify_on_handled_exceptions can be 0, 1 or 2 # 0 means we should not stop on handled exceptions. # 1 means we should stop on handled exceptions showing it on all frames where the exception passes. # 2 means we should stop on handled exceptions but we should only notify about it once. # # To ignore_libraries properly, besides setting ignore_libraries to 1, the IDE_PROJECT_ROOTS environment # variable must be set (so, we'll ignore anything not below IDE_PROJECT_ROOTS) -- this is not ideal as # the environment variable may not be properly set if it didn't start from the debugger (we should # create a custom message for that). # # There are 2 global settings which can only be set in CMD_SET_PY_EXCEPTION. Namely: # # py_db.skip_on_exceptions_thrown_in_same_context # - If True, we should only show the exception in a caller, not where it was first raised. # # py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception # - If True exceptions thrown in lines with '@IgnoreException' will not be shown. condition = "" expression = "" if text.find('\t') != -1: try: exception, condition, expression, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split( '\t', 5) except: exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split( '\t', 3) else: exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text, 0, 0, 0 condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n').replace( "@_@TAB_CHAR@_@", '\t').strip() if condition is not None and (len(condition) == 0 or condition == "None"): condition = None expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n').replace( "@_@TAB_CHAR@_@", '\t').strip() if expression is not None and (len(expression) == 0 or expression == "None"): expression = None if exception.find('-') != -1: breakpoint_type, exception = exception.split('-') else: breakpoint_type = 'python' if breakpoint_type == 'python': exception_breakpoint = py_db.add_break_on_exception( exception, condition=condition, expression=expression, notify_on_handled_exceptions=int( notify_on_handled_exceptions) > 0, notify_on_unhandled_exceptions=int( notify_on_unhandled_exceptions) == 1, notify_on_first_raise_only=int( notify_on_handled_exceptions) == 2, ignore_libraries=int(ignore_libraries) > 0) if exception_breakpoint is not None: py_db.on_breakpoints_changed() else: supported_type = False plugin = py_db.get_plugin_lazy_init() if plugin is not None: supported_type = plugin.add_breakpoint( 'add_exception_breakpoint', py_db, breakpoint_type, exception) if supported_type: py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks( ) py_db.on_breakpoints_changed() else: raise NameError(breakpoint_type) elif cmd_id == CMD_REMOVE_EXCEPTION_BREAK: exception = text if exception.find('-') != -1: exception_type, exception = exception.split('-') else: exception_type = 'python' if exception_type == 'python': try: cp = py_db.break_on_uncaught_exceptions.copy() cp.pop(exception, None) py_db.break_on_uncaught_exceptions = cp cp = py_db.break_on_caught_exceptions.copy() cp.pop(exception, None) py_db.break_on_caught_exceptions = cp except: pydev_log.debug("Error while removing exception %s" % sys.exc_info()[0]) else: supported_type = False # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove # anything from it anyways). plugin = py_db.plugin if plugin is not None: supported_type = plugin.remove_exception_breakpoint( py_db, exception_type, exception) if supported_type: py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks( ) else: raise NameError(exception_type) py_db.on_breakpoints_changed(removed=True) elif cmd_id == CMD_LOAD_SOURCE: path = text try: if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. path = path.encode(file_system_encoding) path = pydevd_file_utils.norm_file_to_server(path) f = open(path, 'r') source = f.read() cmd = py_db.cmd_factory.make_load_source_message( seq, source) except: cmd = py_db.cmd_factory.make_error_message( seq, pydevd_tracing.get_exception_traceback_str()) elif cmd_id == CMD_ADD_DJANGO_EXCEPTION_BREAK: exception = text plugin = py_db.get_plugin_lazy_init() if plugin is not None: plugin.add_breakpoint('add_exception_breakpoint', py_db, 'django', exception) py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks( ) py_db.on_breakpoints_changed() elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK: exception = text # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove # anything from it anyways). plugin = py_db.plugin if plugin is not None: plugin.remove_exception_breakpoint(py_db, 'django', exception) py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks( ) py_db.on_breakpoints_changed(removed=True) elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION: # Command which takes care for the debug console communication if text != "": thread_id, frame_id, console_command = text.split('\t', 2) console_command, line = console_command.split('\t') if console_command == 'EVALUATE': int_cmd = InternalEvaluateConsoleExpression( seq, thread_id, frame_id, line, buffer_output=True) elif console_command == 'EVALUATE_UNBUFFERED': int_cmd = InternalEvaluateConsoleExpression( seq, thread_id, frame_id, line, buffer_output=False) elif console_command == 'GET_COMPLETIONS': int_cmd = InternalConsoleGetCompletions( seq, thread_id, frame_id, line) else: raise ValueError('Unrecognized command: %s' % (console_command, )) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_RUN_CUSTOM_OPERATION: # Command which runs a custom operation if text != "": try: location, custom = text.split('||', 1) except: sys.stderr.write( 'Custom operation now needs a || separator. Found: %s\n' % (text, )) raise thread_id, frame_id, scopeattrs = location.split('\t', 2) if scopeattrs.find( '\t') != -1: # there are attributes beyond scope scope, attrs = scopeattrs.split('\t', 1) else: scope, attrs = (scopeattrs, None) # : style: EXECFILE or EXEC # : encoded_code_or_file: file to execute or code # : fname: name of function to be executed in the resulting namespace style, encoded_code_or_file, fnname = custom.split('\t', 3) int_cmd = InternalRunCustomOperation( seq, thread_id, frame_id, scope, attrs, style, encoded_code_or_file, fnname) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_IGNORE_THROWN_EXCEPTION_AT: if text: replace = 'REPLACE:' # Not all 3.x versions support u'REPLACE:', so, doing workaround. if not IS_PY3K: replace = unicode(replace) if text.startswith(replace): text = text[8:] py_db.filename_to_lines_where_exceptions_are_ignored.clear( ) if text: for line in text.split( '||' ): # Can be bulk-created (one in each line) filename, line_number = line.split('|') if not IS_PY3K: filename = filename.encode( file_system_encoding) filename = pydevd_file_utils.norm_file_to_server( filename) if os.path.exists(filename): lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored.get( filename) if lines_ignored is None: lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored[ filename] = {} lines_ignored[int(line_number)] = 1 else: sys.stderr.write( 'pydev debugger: warning: trying to ignore exception thrown' ' on file that does not exist: %s (will have no effect)\n' % (filename, )) elif cmd_id == CMD_ENABLE_DONT_TRACE: if text: true_str = 'true' # Not all 3.x versions support u'str', so, doing workaround. if not IS_PY3K: true_str = unicode(true_str) mode = text.strip() == true_str pydevd_dont_trace.trace_filter(mode) elif cmd_id == CMD_PROCESS_CREATED_MSG_RECEIVED: original_seq = int(text) event = py_db.process_created_msg_received_events.pop( original_seq, None) if event: event.set() elif cmd_id == CMD_REDIRECT_OUTPUT: if text: py_db.enable_output_redirection('STDOUT' in text, 'STDERR' in text) elif cmd_id == CMD_GET_NEXT_STATEMENT_TARGETS: thread_id, frame_id = text.split('\t', 1) int_cmd = InternalGetNextStatementTargets( seq, thread_id, frame_id) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_SET_PROJECT_ROOTS: pydevd_utils.set_project_roots(text.split(u'\t')) elif cmd_id == CMD_THREAD_DUMP_TO_STDERR: pydevd_utils.dump_threads() elif cmd_id == CMD_STOP_ON_START: py_db.stop_on_start = text.strip() in ('True', 'true', '1') elif cmd_id == CMD_PYDEVD_JSON_CONFIG: # Expected to receive a json string as: # { # 'skip_suspend_on_breakpoint_exception': [<exception names where we should suspend>], # 'skip_print_breakpoint_exception': [<exception names where we should print>], # 'multi_threads_single_notification': bool, # } msg = json.loads(text.strip()) if 'skip_suspend_on_breakpoint_exception' in msg: py_db.skip_suspend_on_breakpoint_exception = tuple( get_exception_class(x) for x in msg['skip_suspend_on_breakpoint_exception']) if 'skip_print_breakpoint_exception' in msg: py_db.skip_print_breakpoint_exception = tuple( get_exception_class(x) for x in msg['skip_print_breakpoint_exception']) if 'multi_threads_single_notification' in msg: py_db.multi_threads_single_notification = msg[ 'multi_threads_single_notification'] elif cmd_id == CMD_GET_EXCEPTION_DETAILS: thread_id = text t = pydevd_find_thread_by_id(thread_id) frame = None if t and not getattr(t, 'pydev_do_not_trace', None): additional_info = set_additional_thread_info(t) frame = additional_info.get_topmost_frame(t) try: cmd = py_db.cmd_factory.make_get_exception_details_message( seq, thread_id, frame) finally: frame = None t = None elif cmd_id == CMD_GET_SMART_STEP_INTO_VARIANTS: thread_id, frame_id, start_line, end_line = text.split('\t', 3) int_cmd = InternalGetSmartStepIntoVariants( seq, thread_id, frame_id, start_line, end_line) py_db.post_internal_command(int_cmd, thread_id) # Powerful DataViewer commands elif cmd_id == CMD_DATAVIEWER_ACTION: # format: thread_id frame_id name temp try: thread_id, frame_id, var, action, args = text.split( '\t', 4) args = args.split('\t') int_cmd = InternalDataViewerAction(seq, thread_id, frame_id, var, action, args) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() else: #I have no idea what this is all about cmd = py_db.cmd_factory.make_error_message( seq, "unexpected command " + str(cmd_id)) if cmd is not None: py_db.writer.add_command(cmd) del cmd except Exception: traceback.print_exc() try: from StringIO import StringIO except ImportError: from io import StringIO stream = StringIO() traceback.print_exc(file=stream) cmd = py_db.cmd_factory.make_error_message( seq, "Unexpected exception in process_net_command.\nInitial params: %s. Exception: %s" % (((cmd_id, seq, text), stream.getvalue()))) py_db.writer.add_command(cmd) finally: py_db._main_lock.release()
def create_source_reference_for_frame_id(frame_id, original_filename): source_reference = _next_source_reference() pydev_log.debug('Created frame id source reference: %s for frame id: %s (%s)', source_reference, frame_id, original_filename) _source_reference_to_frame_id[source_reference] = frame_id return source_reference
def log_debug(msg): from _pydev_bundle import pydev_log pydev_log.debug(msg)
def should_stop_on_exception(self, frame, event, arg): # ENDIF # main_debugger, _filename, info, _thread = self._args main_debugger = self._args[0] info = self._args[2] should_stop = False # STATE_SUSPEND = 2 if info.pydev_state != 2: # and breakpoint is not None: exception, value, trace = arg if trace is not None and hasattr(trace, 'tb_next'): # on jython trace is None on the first event and it may not have a tb_next. should_stop = False exception_breakpoint = None try: if main_debugger.plugin is not None: result = main_debugger.plugin.exception_break( main_debugger, self, frame, self._args, arg) if result: should_stop, frame = result except: pydev_log.exception() if not should_stop: # It was not handled by any plugin, lets check exception breakpoints. exception_breakpoint = main_debugger.get_exception_breakpoint( exception, main_debugger.break_on_caught_exceptions) if exception_breakpoint is not None: if exception is SystemExit and main_debugger.ignore_system_exit_code( value): return False, frame if exception in (GeneratorExit, StopIteration): # These exceptions are control-flow related (they work as a generator # pause), so, we shouldn't stop on them. return False, frame if exception_breakpoint.condition is not None: eval_result = main_debugger.handle_breakpoint_condition( info, exception_breakpoint, frame) if not eval_result: return False, frame if main_debugger.exclude_exception_by_filter( exception_breakpoint, trace, False): pydev_log.debug( "Ignore exception %s in library %s -- (%s)" % (exception, frame.f_code.co_filename, frame.f_code.co_name)) return False, frame if ignore_exception_trace(trace): return False, frame was_just_raised = just_raised(trace) if was_just_raised: if main_debugger.skip_on_exceptions_thrown_in_same_context: # Option: Don't break if an exception is caught in the same function from which it is thrown return False, frame if exception_breakpoint.notify_on_first_raise_only: if main_debugger.skip_on_exceptions_thrown_in_same_context: # In this case we never stop if it was just raised, so, to know if it was the first we # need to check if we're in the 2nd method. if not was_just_raised and not just_raised( trace.tb_next): return False, frame # I.e.: we stop only when we're at the caller of a method that throws an exception else: if not was_just_raised: return False, frame # I.e.: we stop only when it was just raised # If it got here we should stop. should_stop = True try: info.pydev_message = exception_breakpoint.qname except: info.pydev_message = exception_breakpoint.qname.encode( 'utf-8') if should_stop: # Always add exception to frame (must remove later after we proceed). add_exception_to_frame(frame, (exception, value, trace)) if exception_breakpoint is not None and exception_breakpoint.expression is not None: main_debugger.handle_breakpoint_expression( exception_breakpoint, info, frame) return should_stop, frame
def add_breakpoint( self, py_db, filename, breakpoint_type, breakpoint_id, line, condition, func_name, expression, suspend_policy, hit_condition, is_logpoint): ''' :param str filename: Note: must be already translated for the server. :param str breakpoint_type: One of: 'python-line', 'django-line', 'jinja2-line'. :param int breakpoint_id: :param int line: :param condition: Either None or the condition to activate the breakpoint. :param str func_name: If "None" (str), may hit in any context. Empty string will hit only top level. Any other value must match the scope of the method to be matched. :param str expression: None or the expression to be evaluated. :param suspend_policy: Either "NONE" (to suspend only the current thread when the breakpoint is hit) or "ALL" (to suspend all threads when a breakpoint is hit). :param str hit_condition: An expression where `@HIT@` will be replaced by the number of hits. i.e.: `@HIT@ == x` or `@HIT@ >= x` :param bool is_logpoint: If True and an expression is passed, pydevd will create an io message command with the result of the evaluation. :return int: :see: ADD_BREAKPOINT_NO_ERROR = 0 :see: ADD_BREAKPOINT_FILE_NOT_FOUND = 1 :see: ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS = 2 ''' assert filename.__class__ == str # i.e.: bytes on py2 and str on py3 assert func_name.__class__ == str # i.e.: bytes on py2 and str on py3 if not pydevd_file_utils.exists(filename): return self.ADD_BREAKPOINT_FILE_NOT_FOUND error_code = self.ADD_BREAKPOINT_NO_ERROR if ( py_db.is_files_filter_enabled and not py_db.get_require_module_for_filters() and py_db.apply_files_filter(self._DummyFrame(filename), filename, False) ): # Note that if `get_require_module_for_filters()` returns False, we don't do this check. # This is because we don't have the module name given a file at this point (in # runtime it's gotten from the frame.f_globals). # An option could be calculate it based on the filename and current sys.path, # but on some occasions that may be wrong (for instance with `__main__` or if # the user dynamically changes the PYTHONPATH). # Note: depending on the use-case, filters may be changed, so, keep on going and add the # breakpoint even with the error code. error_code = self.ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS if breakpoint_type == 'python-line': added_breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy, hit_condition=hit_condition, is_logpoint=is_logpoint) breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint supported_type = True else: result = None plugin = py_db.get_plugin_lazy_init() if plugin is not None: result = plugin.add_breakpoint('add_line_breakpoint', py_db, breakpoint_type, filename, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint) if result is not None: supported_type = True added_breakpoint, breakpoints = result file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint else: supported_type = False if not supported_type: raise NameError(breakpoint_type) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n', filename, line, func_name) if filename in file_to_id_to_breakpoint: id_to_pybreakpoint = file_to_id_to_breakpoint[filename] else: id_to_pybreakpoint = file_to_id_to_breakpoint[filename] = {} id_to_pybreakpoint[breakpoint_id] = added_breakpoint py_db.consolidate_breakpoints(filename, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() py_db.on_breakpoints_changed() return error_code
def should_stop_on_exception(self, frame, event, arg): # ENDIF # main_debugger, _filename, info, _thread = self._args main_debugger = self._args[0] info = self._args[2] flag = False # STATE_SUSPEND = 2 if info.pydev_state != 2: #and breakpoint is not None: exception, value, trace = arg if trace is not None: #on jython trace is None on the first event exception_breakpoint = get_exception_breakpoint( exception, main_debugger.break_on_caught_exceptions) if exception_breakpoint is not None: add_exception_to_frame(frame, (exception, value, trace)) if exception_breakpoint.condition is not None: eval_result = handle_breakpoint_condition(main_debugger, info, exception_breakpoint, frame) if not eval_result: return False, frame if exception_breakpoint.ignore_libraries: if exception_breakpoint.notify_on_first_raise_only: if main_debugger.first_appearance_in_scope(trace): add_exception_to_frame(frame, (exception, value, trace)) try: info.pydev_message = exception_breakpoint.qname except: info.pydev_message = exception_breakpoint.qname.encode('utf-8') flag = True else: pydev_log.debug("Ignore exception %s in library %s" % (exception, frame.f_code.co_filename)) flag = False else: if not exception_breakpoint.notify_on_first_raise_only or just_raised(trace): add_exception_to_frame(frame, (exception, value, trace)) try: info.pydev_message = exception_breakpoint.qname except: info.pydev_message = exception_breakpoint.qname.encode('utf-8') flag = True else: flag = False else: try: if main_debugger.plugin is not None: result = main_debugger.plugin.exception_break(main_debugger, self, frame, self._args, arg) if result: flag, frame = result except: flag = False if flag: if exception_breakpoint is not None and exception_breakpoint.expression is not None: handle_breakpoint_expression(exception_breakpoint, info, frame) else: remove_exception_from_frame(frame) return flag, frame
def should_stop_on_exception(self, frame, event, arg): # ENDIF # main_debugger, _filename, info, _thread = self._args main_debugger = self._args[0] info = self._args[2] should_stop = False # STATE_SUSPEND = 2 if info.pydev_state != 2: # and breakpoint is not None: exception, value, trace = arg if trace is not None and hasattr(trace, 'tb_next'): # on jython trace is None on the first event and it may not have a tb_next. exception_breakpoint = get_exception_breakpoint( exception, main_debugger.break_on_caught_exceptions) if exception_breakpoint is not None: if exception_breakpoint.condition is not None: eval_result = handle_breakpoint_condition(main_debugger, info, exception_breakpoint, frame) if not eval_result: return False, frame if exception_breakpoint.ignore_libraries: if not main_debugger.is_exception_trace_in_project_scope(trace): pydev_log.debug("Ignore exception %s in library %s -- (%s)" % (exception, frame.f_code.co_filename, frame.f_code.co_name)) return False, frame if ignore_exception_trace(trace): return False, frame was_just_raised = just_raised(trace) if was_just_raised: if main_debugger.skip_on_exceptions_thrown_in_same_context: # Option: Don't break if an exception is caught in the same function from which it is thrown return False, frame if exception_breakpoint.notify_on_first_raise_only: if main_debugger.skip_on_exceptions_thrown_in_same_context: # In this case we never stop if it was just raised, so, to know if it was the first we # need to check if we're in the 2nd method. if not was_just_raised and not just_raised(trace.tb_next): return False, frame # I.e.: we stop only when we're at the caller of a method that throws an exception else: if not was_just_raised: return False, frame # I.e.: we stop only when it was just raised # If it got here we should stop. should_stop = True try: info.pydev_message = exception_breakpoint.qname except: info.pydev_message = exception_breakpoint.qname.encode('utf-8') # Always add exception to frame (must remove later after we proceed). add_exception_to_frame(frame, (exception, value, trace)) else: # No regular exception breakpoint, let's see if some plugin handles it. try: if main_debugger.plugin is not None: result = main_debugger.plugin.exception_break(main_debugger, self, frame, self._args, arg) if result: should_stop, frame = result except: should_stop = False if should_stop: if exception_breakpoint is not None and exception_breakpoint.expression is not None: handle_breakpoint_expression(exception_breakpoint, info, frame) return should_stop, frame
def process_net_command(py_db, cmd_id, seq, text): '''Processes a command received from the Java side @param cmd_id: the id of the command @param seq: the sequence of the command @param text: the text received in the command @note: this method is run as a big switch... after doing some tests, it's not clear whether changing it for a dict id --> function call will have better performance result. A simple test with xrange(10000000) showed that the gains from having a fast access to what should be executed are lost because of the function call in a way that if we had 10 elements in the switch the if..elif are better -- but growing the number of choices makes the solution with the dispatch look better -- so, if this gets more than 20-25 choices at some time, it may be worth refactoring it (actually, reordering the ifs so that the ones used mostly come before probably will give better performance). ''' # print(ID_TO_MEANING[str(cmd_id)], repr(text)) py_db._main_lock.acquire() try: try: cmd = None if cmd_id == CMD_RUN: py_db.ready_to_run = True elif cmd_id == CMD_SET_PROTOCOL: expected = (NetCommand.HTTP_PROTOCOL, NetCommand.QUOTED_LINE_PROTOCOL) text = text.strip() assert text.strip() in expected, 'Protocol (%s) should be one of: %s' % ( text, expected) NetCommand.protocol = text cmd = py_db.cmd_factory.make_protocol_set_message(seq) elif cmd_id == CMD_VERSION: # response is version number # ide_os should be 'WINDOWS' or 'UNIX'. # Default based on server process (although ideally the IDE should # provide it). if IS_WINDOWS: ide_os = 'WINDOWS' else: ide_os = 'UNIX' # Breakpoints can be grouped by 'LINE' or by 'ID'. breakpoints_by = 'LINE' splitted = text.split('\t') if len(splitted) == 1: _local_version = splitted elif len(splitted) == 2: _local_version, ide_os = splitted elif len(splitted) == 3: _local_version, ide_os, breakpoints_by = splitted if breakpoints_by == 'ID': py_db._set_breakpoints_with_id = True else: py_db._set_breakpoints_with_id = False pydevd_file_utils.set_ide_os(ide_os) cmd = py_db.cmd_factory.make_version_message(seq) elif cmd_id == CMD_LIST_THREADS: # response is a list of threads cmd = py_db.cmd_factory.make_list_threads_message(seq) elif cmd_id == CMD_GET_THREAD_STACK: # Receives a thread_id and a given timeout, which is the time we should # wait to the provide the stack if a given thread is still not suspended. if '\t' in text: thread_id, timeout = text.split('\t') timeout = float(timeout) else: thread_id = text timeout = .5 # Default timeout is .5 seconds # If it's already suspended, get it right away. internal_get_thread_stack = InternalGetThreadStack(seq, thread_id, py_db, set_additional_thread_info, timeout=timeout) if internal_get_thread_stack.can_be_executed_by(get_current_thread_id(threading.current_thread())): internal_get_thread_stack.do_it(py_db) else: py_db.post_internal_command(internal_get_thread_stack, '*') elif cmd_id == CMD_THREAD_SUSPEND: # Yes, thread suspend is done at this point, not through an internal command. threads = [] suspend_all = text.strip() == '*' if suspend_all: threads = pydevd_utils.get_non_pydevd_threads() elif text.startswith('__frame__:'): sys.stderr.write("Can't suspend tasklet: %s\n" % (text,)) else: threads = [pydevd_find_thread_by_id(text)] for t in threads: if t is None: continue py_db.set_suspend( t, CMD_THREAD_SUSPEND, suspend_other_threads=suspend_all, is_pause=True, ) # Break here (even if it's suspend all) as py_db.set_suspend will # take care of suspending other threads. break elif cmd_id == CMD_THREAD_RUN: threads = [] if text.strip() == '*': threads = pydevd_utils.get_non_pydevd_threads() elif text.startswith('__frame__:'): sys.stderr.write("Can't make tasklet run: %s\n" % (text,)) else: threads = [pydevd_find_thread_by_id(text)] for t in threads: if t is None: continue additional_info = set_additional_thread_info(t) additional_info.pydev_step_cmd = -1 additional_info.pydev_step_stop = None additional_info.pydev_state = STATE_RUN elif cmd_id == CMD_STEP_INTO or cmd_id == CMD_STEP_OVER or cmd_id == CMD_STEP_RETURN or \ cmd_id == CMD_STEP_INTO_MY_CODE: # we received some command to make a single step t = pydevd_find_thread_by_id(text) if t: thread_id = get_thread_id(t) int_cmd = InternalStepThread(thread_id, cmd_id) py_db.post_internal_command(int_cmd, thread_id) elif text.startswith('__frame__:'): sys.stderr.write("Can't make tasklet step command: %s\n" % (text,)) elif cmd_id == CMD_RUN_TO_LINE or cmd_id == CMD_SET_NEXT_STATEMENT or cmd_id == CMD_SMART_STEP_INTO: # we received some command to make a single step thread_id, line, func_name = text.split('\t', 2) t = pydevd_find_thread_by_id(thread_id) if t: int_cmd = InternalSetNextStatementThread(thread_id, cmd_id, line, func_name) py_db.post_internal_command(int_cmd, thread_id) elif thread_id.startswith('__frame__:'): sys.stderr.write("Can't set next statement in tasklet: %s\n" % (thread_id,)) elif cmd_id == CMD_RELOAD_CODE: # we received some command to make a reload of a module module_name = text.strip() thread_id = '*' # Any thread # Note: not going for the main thread because in this case it'd only do the load # when we stopped on a breakpoint. int_cmd = ReloadCodeCommand(module_name, thread_id) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_CHANGE_VARIABLE: # the text is: thread\tstackframe\tFRAME|GLOBAL\tattribute_to_change\tvalue_to_change try: thread_id, frame_id, scope, attr_and_value = text.split('\t', 3) tab_index = attr_and_value.rindex('\t') attr = attr_and_value[0:tab_index].replace('\t', '.') value = attr_and_value[tab_index + 1:] int_cmd = InternalChangeVariable(seq, thread_id, frame_id, scope, attr, value) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_VARIABLE: # we received some command to get a variable # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tattributes* try: thread_id, frame_id, scopeattrs = text.split('\t', 2) if scopeattrs.find('\t') != -1: # there are attributes beyond scope scope, attrs = scopeattrs.split('\t', 1) else: scope, attrs = (scopeattrs, None) int_cmd = InternalGetVariable(seq, thread_id, frame_id, scope, attrs) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_ARRAY: # we received some command to get an array variable # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tname\ttemp\troffs\tcoffs\trows\tcols\tformat try: roffset, coffset, rows, cols, format, thread_id, frame_id, scopeattrs = text.split('\t', 7) if scopeattrs.find('\t') != -1: # there are attributes beyond scope scope, attrs = scopeattrs.split('\t', 1) else: scope, attrs = (scopeattrs, None) int_cmd = InternalGetArray(seq, roffset, coffset, rows, cols, format, thread_id, frame_id, scope, attrs) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_SHOW_RETURN_VALUES: try: show_return_values = text.split('\t')[1] if int(show_return_values) == 1: py_db.show_return_values = True else: if py_db.show_return_values: # We should remove saved return values py_db.remove_return_values_flag = True py_db.show_return_values = False pydev_log.debug("Show return values: %s\n" % py_db.show_return_values) except: traceback.print_exc() elif cmd_id == CMD_LOAD_FULL_VALUE: try: thread_id, frame_id, scopeattrs = text.split('\t', 2) vars = scopeattrs.split(NEXT_VALUE_SEPARATOR) int_cmd = InternalLoadFullValue(seq, thread_id, frame_id, vars) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_COMPLETIONS: # we received some command to get a variable # the text is: thread_id\tframe_id\tactivation token try: thread_id, frame_id, scope, act_tok = text.split('\t', 3) int_cmd = InternalGetCompletions(seq, thread_id, frame_id, act_tok) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_DESCRIPTION: try: thread_id, frame_id, expression = text.split('\t', 2) int_cmd = InternalGetDescription(seq, thread_id, frame_id, expression) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_FRAME: thread_id, frame_id, scope = text.split('\t', 2) int_cmd = InternalGetFrame(seq, thread_id, frame_id) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_SET_BREAK: # func name: 'None': match anything. Empty: match global, specified: only method context. # command to add some breakpoint. # text is file\tline. Add to breakpoints dictionary suspend_policy = "NONE" # Can be 'NONE' or 'ALL' is_logpoint = False hit_condition = None if py_db._set_breakpoints_with_id: try: try: breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint, suspend_policy = text.split('\t', 9) except ValueError: # not enough values to unpack # No suspend_policy passed (use default). breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint = text.split('\t', 8) is_logpoint = is_logpoint == 'True' except ValueError: # not enough values to unpack breakpoint_id, type, file, line, func_name, condition, expression = text.split('\t', 6) breakpoint_id = int(breakpoint_id) line = int(line) # We must restore new lines and tabs as done in # AbstractDebugTarget.breakpointAdded condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n').\ replace("@_@TAB_CHAR@_@", '\t').strip() expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n').\ replace("@_@TAB_CHAR@_@", '\t').strip() else: # Note: this else should be removed after PyCharm migrates to setting # breakpoints by id (and ideally also provides func_name). type, file, line, func_name, suspend_policy, condition, expression = text.split('\t', 6) # If we don't have an id given for each breakpoint, consider # the id to be the line. breakpoint_id = line = int(line) condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n'). \ replace("@_@TAB_CHAR@_@", '\t').strip() expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n'). \ replace("@_@TAB_CHAR@_@", '\t').strip() if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. file = file.encode(file_system_encoding) file = pydevd_file_utils.norm_file_to_server(file) if not pydevd_file_utils.exists(file): sys.stderr.write('pydev debugger: warning: trying to add breakpoint'\ ' to file that does not exist: %s (will have no effect)\n' % (file,)) sys.stderr.flush() if condition is not None and (len(condition) <= 0 or condition == "None"): condition = None if expression is not None and (len(expression) <= 0 or expression == "None"): expression = None if hit_condition is not None and (len(hit_condition) <= 0 or hit_condition == "None"): hit_condition = None if type == 'python-line': breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy, hit_condition=hit_condition, is_logpoint=is_logpoint) breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint supported_type = True else: result = None plugin = py_db.get_plugin_lazy_init() if plugin is not None: result = plugin.add_breakpoint('add_line_breakpoint', py_db, type, file, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint) if result is not None: supported_type = True breakpoint, breakpoints = result file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint else: supported_type = False if not supported_type: raise NameError(type) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name.encode('utf-8'))) sys.stderr.flush() if file in file_to_id_to_breakpoint: id_to_pybreakpoint = file_to_id_to_breakpoint[file] else: id_to_pybreakpoint = file_to_id_to_breakpoint[file] = {} id_to_pybreakpoint[breakpoint_id] = breakpoint py_db.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() py_db.on_breakpoints_changed() elif cmd_id == CMD_REMOVE_BREAK: #command to remove some breakpoint #text is type\file\tid. Remove from breakpoints dictionary breakpoint_type, file, breakpoint_id = text.split('\t', 2) if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. file = file.encode(file_system_encoding) file = pydevd_file_utils.norm_file_to_server(file) try: breakpoint_id = int(breakpoint_id) except ValueError: pydev_log.error('Error removing breakpoint. Expected breakpoint_id to be an int. Found: %s' % (breakpoint_id,)) else: file_to_id_to_breakpoint = None if breakpoint_type == 'python-line': breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint elif py_db.get_plugin_lazy_init() is not None: result = py_db.plugin.get_breakpoints(py_db, breakpoint_type) if result is not None: file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint breakpoints = result if file_to_id_to_breakpoint is None: pydev_log.error('Error removing breakpoint. Cant handle breakpoint of type %s' % breakpoint_type) else: try: id_to_pybreakpoint = file_to_id_to_breakpoint.get(file, {}) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: existing = id_to_pybreakpoint[breakpoint_id] sys.stderr.write('Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % ( file, existing.line, existing.func_name.encode('utf-8'), breakpoint_id)) del id_to_pybreakpoint[breakpoint_id] py_db.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() except KeyError: pydev_log.error("Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n" % ( file, breakpoint_id, dict_keys(id_to_pybreakpoint))) py_db.on_breakpoints_changed(removed=True) elif cmd_id == CMD_EVALUATE_EXPRESSION or cmd_id == CMD_EXEC_EXPRESSION: #command to evaluate the given expression #text is: thread\tstackframe\tLOCAL\texpression temp_name = "" try: thread_id, frame_id, scope, expression, trim, temp_name = text.split('\t', 5) except ValueError: thread_id, frame_id, scope, expression, trim = text.split('\t', 4) int_cmd = InternalEvaluateExpression(seq, thread_id, frame_id, expression, cmd_id == CMD_EXEC_EXPRESSION, int(trim) == 1, temp_name) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_CONSOLE_EXEC: #command to exec expression in console, in case expression is only partially valid 'False' is returned #text is: thread\tstackframe\tLOCAL\texpression thread_id, frame_id, scope, expression = text.split('\t', 3) int_cmd = InternalConsoleExec(seq, thread_id, frame_id, expression) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_SET_PY_EXCEPTION: # Command which receives set of exceptions on which user wants to break the debugger # text is: # # break_on_uncaught; # break_on_caught; # skip_on_exceptions_thrown_in_same_context; # ignore_exceptions_thrown_in_lines_with_ignore_exception; # ignore_libraries; # TypeError;ImportError;zipimport.ZipImportError; # # i.e.: true;true;true;true;true;TypeError;ImportError;zipimport.ZipImportError; # # This API is optional and works 'in bulk' -- it's possible # to get finer-grained control with CMD_ADD_EXCEPTION_BREAK/CMD_REMOVE_EXCEPTION_BREAK # which allows setting caught/uncaught per exception. splitted = text.split(';') py_db.break_on_uncaught_exceptions = {} py_db.break_on_caught_exceptions = {} if len(splitted) >= 5: if splitted[0] == 'true': break_on_uncaught = True else: break_on_uncaught = False if splitted[1] == 'true': break_on_caught = True else: break_on_caught = False if splitted[2] == 'true': py_db.skip_on_exceptions_thrown_in_same_context = True else: py_db.skip_on_exceptions_thrown_in_same_context = False if splitted[3] == 'true': py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = True else: py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = False if splitted[4] == 'true': ignore_libraries = True else: ignore_libraries = False for exception_type in splitted[5:]: exception_type = exception_type.strip() if not exception_type: continue exception_breakpoint = py_db.add_break_on_exception( exception_type, condition=None, expression=None, notify_on_handled_exceptions=break_on_caught, notify_on_unhandled_exceptions=break_on_uncaught, notify_on_first_raise_only=True, ignore_libraries=ignore_libraries, ) py_db.on_breakpoints_changed() else: sys.stderr.write("Error when setting exception list. Received: %s\n" % (text,)) elif cmd_id == CMD_GET_FILE_CONTENTS: if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. text = text.encode(file_system_encoding) if os.path.exists(text): f = open(text, 'r') try: source = f.read() finally: f.close() cmd = py_db.cmd_factory.make_get_file_contents(seq, source) elif cmd_id == CMD_SET_PROPERTY_TRACE: # Command which receives whether to trace property getter/setter/deleter # text is feature_state(true/false);disable_getter/disable_setter/disable_deleter if text != "": splitted = text.split(';') if len(splitted) >= 3: if py_db.disable_property_trace is False and splitted[0] == 'true': # Replacing property by custom property only when the debugger starts pydevd_traceproperty.replace_builtin_property() py_db.disable_property_trace = True # Enable/Disable tracing of the property getter if splitted[1] == 'true': py_db.disable_property_getter_trace = True else: py_db.disable_property_getter_trace = False # Enable/Disable tracing of the property setter if splitted[2] == 'true': py_db.disable_property_setter_trace = True else: py_db.disable_property_setter_trace = False # Enable/Disable tracing of the property deleter if splitted[3] == 'true': py_db.disable_property_deleter_trace = True else: py_db.disable_property_deleter_trace = False else: # User hasn't configured any settings for property tracing pass elif cmd_id == CMD_ADD_EXCEPTION_BREAK: # Note that this message has some idiosyncrasies... # # notify_on_handled_exceptions can be 0, 1 or 2 # 0 means we should not stop on handled exceptions. # 1 means we should stop on handled exceptions showing it on all frames where the exception passes. # 2 means we should stop on handled exceptions but we should only notify about it once. # # To ignore_libraries properly, besides setting ignore_libraries to 1, the IDE_PROJECT_ROOTS environment # variable must be set (so, we'll ignore anything not below IDE_PROJECT_ROOTS) -- this is not ideal as # the environment variable may not be properly set if it didn't start from the debugger (we should # create a custom message for that). # # There are 2 global settings which can only be set in CMD_SET_PY_EXCEPTION. Namely: # # py_db.skip_on_exceptions_thrown_in_same_context # - If True, we should only show the exception in a caller, not where it was first raised. # # py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception # - If True exceptions thrown in lines with '@IgnoreException' will not be shown. condition = "" expression = "" if text.find('\t') != -1: try: exception, condition, expression, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split('\t', 5) except: exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split('\t', 3) else: exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text, 0, 0, 0 condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n').replace("@_@TAB_CHAR@_@", '\t').strip() if condition is not None and (len(condition) == 0 or condition == "None"): condition = None expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n').replace("@_@TAB_CHAR@_@", '\t').strip() if expression is not None and (len(expression) == 0 or expression == "None"): expression = None if exception.find('-') != -1: breakpoint_type, exception = exception.split('-') else: breakpoint_type = 'python' if breakpoint_type == 'python': exception_breakpoint = py_db.add_break_on_exception( exception, condition=condition, expression=expression, notify_on_handled_exceptions=int(notify_on_handled_exceptions) > 0, notify_on_unhandled_exceptions=int(notify_on_unhandled_exceptions) == 1, notify_on_first_raise_only=int(notify_on_handled_exceptions) == 2, ignore_libraries=int(ignore_libraries) > 0 ) if exception_breakpoint is not None: py_db.on_breakpoints_changed() else: supported_type = False plugin = py_db.get_plugin_lazy_init() if plugin is not None: supported_type = plugin.add_breakpoint('add_exception_breakpoint', py_db, breakpoint_type, exception) if supported_type: py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks() py_db.on_breakpoints_changed() else: raise NameError(breakpoint_type) elif cmd_id == CMD_REMOVE_EXCEPTION_BREAK: exception = text if exception.find('-') != -1: exception_type, exception = exception.split('-') else: exception_type = 'python' if exception_type == 'python': try: cp = py_db.break_on_uncaught_exceptions.copy() cp.pop(exception, None) py_db.break_on_uncaught_exceptions = cp cp = py_db.break_on_caught_exceptions.copy() cp.pop(exception, None) py_db.break_on_caught_exceptions = cp except: pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0]) else: supported_type = False # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove # anything from it anyways). plugin = py_db.plugin if plugin is not None: supported_type = plugin.remove_exception_breakpoint(py_db, exception_type, exception) if supported_type: py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks() else: raise NameError(exception_type) py_db.on_breakpoints_changed(remove=True) elif cmd_id == CMD_LOAD_SOURCE: path = text try: if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. path = path.encode(file_system_encoding) path = pydevd_file_utils.norm_file_to_server(path) f = open(path, 'r') source = f.read() cmd = py_db.cmd_factory.make_load_source_message(seq, source) except: cmd = py_db.cmd_factory.make_error_message(seq, pydevd_tracing.get_exception_traceback_str()) elif cmd_id == CMD_ADD_DJANGO_EXCEPTION_BREAK: exception = text plugin = py_db.get_plugin_lazy_init() if plugin is not None: plugin.add_breakpoint('add_exception_breakpoint', py_db, 'django', exception) py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks() py_db.on_breakpoints_changed() elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK: exception = text # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove # anything from it anyways). plugin = py_db.plugin if plugin is not None: plugin.remove_exception_breakpoint(py_db, 'django', exception) py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks() py_db.on_breakpoints_changed(removed=True) elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION: # Command which takes care for the debug console communication if text != "": thread_id, frame_id, console_command = text.split('\t', 2) console_command, line = console_command.split('\t') if console_command == 'EVALUATE': int_cmd = InternalEvaluateConsoleExpression( seq, thread_id, frame_id, line, buffer_output=True) elif console_command == 'EVALUATE_UNBUFFERED': int_cmd = InternalEvaluateConsoleExpression( seq, thread_id, frame_id, line, buffer_output=False) elif console_command == 'GET_COMPLETIONS': int_cmd = InternalConsoleGetCompletions(seq, thread_id, frame_id, line) else: raise ValueError('Unrecognized command: %s' % (console_command,)) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_RUN_CUSTOM_OPERATION: # Command which runs a custom operation if text != "": try: location, custom = text.split('||', 1) except: sys.stderr.write('Custom operation now needs a || separator. Found: %s\n' % (text,)) raise thread_id, frame_id, scopeattrs = location.split('\t', 2) if scopeattrs.find('\t') != -1: # there are attributes beyond scope scope, attrs = scopeattrs.split('\t', 1) else: scope, attrs = (scopeattrs, None) # : style: EXECFILE or EXEC # : encoded_code_or_file: file to execute or code # : fname: name of function to be executed in the resulting namespace style, encoded_code_or_file, fnname = custom.split('\t', 3) int_cmd = InternalRunCustomOperation(seq, thread_id, frame_id, scope, attrs, style, encoded_code_or_file, fnname) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_IGNORE_THROWN_EXCEPTION_AT: if text: replace = 'REPLACE:' # Not all 3.x versions support u'REPLACE:', so, doing workaround. if not IS_PY3K: replace = unicode(replace) if text.startswith(replace): text = text[8:] py_db.filename_to_lines_where_exceptions_are_ignored.clear() if text: for line in text.split('||'): # Can be bulk-created (one in each line) filename, line_number = line.split('|') if not IS_PY3K: filename = filename.encode(file_system_encoding) filename = pydevd_file_utils.norm_file_to_server(filename) if os.path.exists(filename): lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored.get(filename) if lines_ignored is None: lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored[filename] = {} lines_ignored[int(line_number)] = 1 else: sys.stderr.write('pydev debugger: warning: trying to ignore exception thrown'\ ' on file that does not exist: %s (will have no effect)\n' % (filename,)) elif cmd_id == CMD_ENABLE_DONT_TRACE: if text: true_str = 'true' # Not all 3.x versions support u'str', so, doing workaround. if not IS_PY3K: true_str = unicode(true_str) mode = text.strip() == true_str pydevd_dont_trace.trace_filter(mode) elif cmd_id == CMD_REDIRECT_OUTPUT: if text: py_db.enable_output_redirection('STDOUT' in text, 'STDERR' in text) elif cmd_id == CMD_GET_NEXT_STATEMENT_TARGETS: thread_id, frame_id = text.split('\t', 1) int_cmd = InternalGetNextStatementTargets(seq, thread_id, frame_id) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_SET_PROJECT_ROOTS: pydevd_utils.set_project_roots(text.split(u'\t')) elif cmd_id == CMD_THREAD_DUMP_TO_STDERR: pydevd_utils.dump_threads() elif cmd_id == CMD_STOP_ON_START: py_db.stop_on_start = text.strip() in ('True', 'true', '1') elif cmd_id == CMD_PYDEVD_JSON_CONFIG: # Expected to receive a json string as: # { # 'skip_suspend_on_breakpoint_exception': [<exception names where we should suspend>], # 'skip_print_breakpoint_exception': [<exception names where we should print>], # 'multi_threads_single_notification': bool, # } msg = json.loads(text.strip()) if 'skip_suspend_on_breakpoint_exception' in msg: py_db.skip_suspend_on_breakpoint_exception = tuple( get_exception_class(x) for x in msg['skip_suspend_on_breakpoint_exception']) if 'skip_print_breakpoint_exception' in msg: py_db.skip_print_breakpoint_exception = tuple( get_exception_class(x) for x in msg['skip_print_breakpoint_exception']) if 'multi_threads_single_notification' in msg: py_db.multi_threads_single_notification = msg['multi_threads_single_notification'] elif cmd_id == CMD_GET_EXCEPTION_DETAILS: thread_id = text t = pydevd_find_thread_by_id(thread_id) frame = None if t and not getattr(t, 'pydev_do_not_trace', None): additional_info = set_additional_thread_info(t) frame = additional_info.get_topmost_frame(t) try: cmd = py_db.cmd_factory.make_get_exception_details_message(seq, thread_id, frame) finally: frame = None t = None else: #I have no idea what this is all about cmd = py_db.cmd_factory.make_error_message(seq, "unexpected command " + str(cmd_id)) if cmd is not None: py_db.writer.add_command(cmd) del cmd except Exception: traceback.print_exc() try: from StringIO import StringIO except ImportError: from io import StringIO stream = StringIO() traceback.print_exc(file=stream) cmd = py_db.cmd_factory.make_error_message( seq, "Unexpected exception in process_net_command.\nInitial params: %s. Exception: %s" % ( ((cmd_id, seq, text), stream.getvalue()) ) ) py_db.writer.add_command(cmd) finally: py_db._main_lock.release()
def process_net_command(py_db, cmd_id, seq, text): '''Processes a command received from the Java side @param cmd_id: the id of the command @param seq: the sequence of the command @param text: the text received in the command @note: this method is run as a big switch... after doing some tests, it's not clear whether changing it for a dict id --> function call will have better performance result. A simple test with xrange(10000000) showed that the gains from having a fast access to what should be executed are lost because of the function call in a way that if we had 10 elements in the switch the if..elif are better -- but growing the number of choices makes the solution with the dispatch look better -- so, if this gets more than 20-25 choices at some time, it may be worth refactoring it (actually, reordering the ifs so that the ones used mostly come before probably will give better performance). ''' # print(ID_TO_MEANING[str(cmd_id)], repr(text)) py_db._main_lock.acquire() try: try: cmd = None if cmd_id == CMD_RUN: py_db.ready_to_run = True elif cmd_id == CMD_VERSION: # response is version number # ide_os should be 'WINDOWS' or 'UNIX'. ide_os = 'WINDOWS' # Breakpoints can be grouped by 'LINE' or by 'ID'. breakpoints_by = 'LINE' splitted = text.split('\t') if len(splitted) == 1: _local_version = splitted elif len(splitted) == 2: _local_version, ide_os = splitted elif len(splitted) == 3: _local_version, ide_os, breakpoints_by = splitted if breakpoints_by == 'ID': py_db._set_breakpoints_with_id = True else: py_db._set_breakpoints_with_id = False pydevd_file_utils.set_ide_os(ide_os) cmd = py_db.cmd_factory.make_version_message(seq) elif cmd_id == CMD_LIST_THREADS: # response is a list of threads cmd = py_db.cmd_factory.make_list_threads_message(seq) elif cmd_id == CMD_THREAD_KILL: int_cmd = InternalTerminateThread(text) py_db.post_internal_command(int_cmd, text) elif cmd_id == CMD_THREAD_SUSPEND: # Yes, thread suspend is still done at this point, not through an internal command! t = pydevd_find_thread_by_id(text) if t and not hasattr(t, 'pydev_do_not_trace'): additional_info = None try: additional_info = t.additional_info except AttributeError: pass # that's ok, no info currently set if additional_info is not None: for frame in additional_info.iter_frames(t): py_db.set_trace_for_frame_and_parents(frame, overwrite_prev_trace=True) del frame py_db.set_suspend(t, CMD_THREAD_SUSPEND) elif text.startswith('__frame__:'): sys.stderr.write("Can't suspend tasklet: %s\n" % (text,)) elif cmd_id == CMD_THREAD_RUN: t = pydevd_find_thread_by_id(text) if t: t.additional_info.pydev_step_cmd = -1 t.additional_info.pydev_step_stop = None t.additional_info.pydev_state = STATE_RUN elif text.startswith('__frame__:'): sys.stderr.write("Can't make tasklet run: %s\n" % (text,)) elif cmd_id == CMD_STEP_INTO or cmd_id == CMD_STEP_OVER or cmd_id == CMD_STEP_RETURN or \ cmd_id == CMD_STEP_INTO_MY_CODE: # we received some command to make a single step t = pydevd_find_thread_by_id(text) if t: thread_id = get_thread_id(t) int_cmd = InternalStepThread(thread_id, cmd_id) py_db.post_internal_command(int_cmd, thread_id) elif text.startswith('__frame__:'): sys.stderr.write("Can't make tasklet step command: %s\n" % (text,)) elif cmd_id == CMD_RUN_TO_LINE or cmd_id == CMD_SET_NEXT_STATEMENT or cmd_id == CMD_SMART_STEP_INTO: # we received some command to make a single step thread_id, line, func_name = text.split('\t', 2) t = pydevd_find_thread_by_id(thread_id) if t: int_cmd = InternalSetNextStatementThread(thread_id, cmd_id, line, func_name) py_db.post_internal_command(int_cmd, thread_id) elif thread_id.startswith('__frame__:'): sys.stderr.write("Can't set next statement in tasklet: %s\n" % (thread_id,)) elif cmd_id == CMD_RELOAD_CODE: # we received some command to make a reload of a module module_name = text.strip() thread_id = '*' # Any thread # Note: not going for the main thread because in this case it'd only do the load # when we stopped on a breakpoint. # for tid, t in py_db._running_thread_ids.items(): #Iterate in copy # thread_name = t.getName() # # print thread_name, get_thread_id(t) # #Note: if possible, try to reload on the main thread # if thread_name == 'MainThread': # thread_id = tid int_cmd = ReloadCodeCommand(module_name, thread_id) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_CHANGE_VARIABLE: # the text is: thread\tstackframe\tFRAME|GLOBAL\tattribute_to_change\tvalue_to_change try: thread_id, frame_id, scope, attr_and_value = text.split('\t', 3) tab_index = attr_and_value.rindex('\t') attr = attr_and_value[0:tab_index].replace('\t', '.') value = attr_and_value[tab_index + 1:] int_cmd = InternalChangeVariable(seq, thread_id, frame_id, scope, attr, value) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_VARIABLE: # we received some command to get a variable # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tattributes* try: thread_id, frame_id, scopeattrs = text.split('\t', 2) if scopeattrs.find('\t') != -1: # there are attributes beyond scope scope, attrs = scopeattrs.split('\t', 1) else: scope, attrs = (scopeattrs, None) int_cmd = InternalGetVariable(seq, thread_id, frame_id, scope, attrs) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_ARRAY: # we received some command to get an array variable # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tname\ttemp\troffs\tcoffs\trows\tcols\tformat try: roffset, coffset, rows, cols, format, thread_id, frame_id, scopeattrs = text.split('\t', 7) if scopeattrs.find('\t') != -1: # there are attributes beyond scope scope, attrs = scopeattrs.split('\t', 1) else: scope, attrs = (scopeattrs, None) int_cmd = InternalGetArray(seq, roffset, coffset, rows, cols, format, thread_id, frame_id, scope, attrs) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_SHOW_RETURN_VALUES: try: show_return_values = text.split('\t')[1] if int(show_return_values) == 1: py_db.show_return_values = True else: if py_db.show_return_values: # We should remove saved return values py_db.remove_return_values_flag = True py_db.show_return_values = False pydev_log.debug("Show return values: %s\n" % py_db.show_return_values) except: traceback.print_exc() elif cmd_id == CMD_GET_COMPLETIONS: # we received some command to get a variable # the text is: thread_id\tframe_id\tactivation token try: thread_id, frame_id, scope, act_tok = text.split('\t', 3) int_cmd = InternalGetCompletions(seq, thread_id, frame_id, act_tok) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_DESCRIPTION: try: thread_id, frame_id, expression = text.split('\t', 2) int_cmd = InternalGetDescription(seq, thread_id, frame_id, expression) py_db.post_internal_command(int_cmd, thread_id) except: traceback.print_exc() elif cmd_id == CMD_GET_FRAME: thread_id, frame_id, scope = text.split('\t', 2) int_cmd = InternalGetFrame(seq, thread_id, frame_id) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_SET_BREAK: # func name: 'None': match anything. Empty: match global, specified: only method context. # command to add some breakpoint. # text is file\tline. Add to breakpoints dictionary suspend_policy = "NONE" if py_db._set_breakpoints_with_id: breakpoint_id, type, file, line, func_name, condition, expression = text.split('\t', 6) breakpoint_id = int(breakpoint_id) line = int(line) # We must restore new lines and tabs as done in # AbstractDebugTarget.breakpointAdded condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n').\ replace("@_@TAB_CHAR@_@", '\t').strip() expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n').\ replace("@_@TAB_CHAR@_@", '\t').strip() else: #Note: this else should be removed after PyCharm migrates to setting #breakpoints by id (and ideally also provides func_name). type, file, line, func_name, suspend_policy, condition, expression = text.split('\t', 6) # If we don't have an id given for each breakpoint, consider # the id to be the line. breakpoint_id = line = int(line) condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n'). \ replace("@_@TAB_CHAR@_@", '\t').strip() expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n'). \ replace("@_@TAB_CHAR@_@", '\t').strip() if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. file = file.encode(file_system_encoding) file = pydevd_file_utils.norm_file_to_server(file) if not pydevd_file_utils.exists(file): sys.stderr.write('pydev debugger: warning: trying to add breakpoint'\ ' to file that does not exist: %s (will have no effect)\n' % (file,)) sys.stderr.flush() if len(condition) <= 0 or condition is None or condition == "None": condition = None if len(expression) <= 0 or expression is None or expression == "None": expression = None if type == 'python-line': breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy) breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint supported_type = True else: result = None plugin = py_db.get_plugin_lazy_init() if plugin is not None: result = plugin.add_breakpoint('add_line_breakpoint', py_db, type, file, line, condition, expression, func_name) if result is not None: supported_type = True breakpoint, breakpoints = result file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint else: supported_type = False if not supported_type: raise NameError(type) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name.encode('utf-8'))) sys.stderr.flush() if dict_contains(file_to_id_to_breakpoint, file): id_to_pybreakpoint = file_to_id_to_breakpoint[file] else: id_to_pybreakpoint = file_to_id_to_breakpoint[file] = {} id_to_pybreakpoint[breakpoint_id] = breakpoint py_db.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() py_db.set_tracing_for_untraced_contexts(overwrite_prev_trace=True) elif cmd_id == CMD_REMOVE_BREAK: #command to remove some breakpoint #text is type\file\tid. Remove from breakpoints dictionary breakpoint_type, file, breakpoint_id = text.split('\t', 2) if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. file = file.encode(file_system_encoding) file = pydevd_file_utils.norm_file_to_server(file) try: breakpoint_id = int(breakpoint_id) except ValueError: pydev_log.error('Error removing breakpoint. Expected breakpoint_id to be an int. Found: %s' % (breakpoint_id,)) else: file_to_id_to_breakpoint = None if breakpoint_type == 'python-line': breakpoints = py_db.breakpoints file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint elif py_db.get_plugin_lazy_init() is not None: result = py_db.plugin.get_breakpoints(py_db, breakpoint_type) if result is not None: file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint breakpoints = result if file_to_id_to_breakpoint is None: pydev_log.error('Error removing breakpoint. Cant handle breakpoint of type %s' % breakpoint_type) else: try: id_to_pybreakpoint = file_to_id_to_breakpoint.get(file, {}) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: existing = id_to_pybreakpoint[breakpoint_id] sys.stderr.write('Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % ( file, existing.line, existing.func_name.encode('utf-8'), breakpoint_id)) del id_to_pybreakpoint[breakpoint_id] py_db.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints) if py_db.plugin is not None: py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks() except KeyError: pydev_log.error("Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n" % ( file, breakpoint_id, dict_keys(id_to_pybreakpoint))) elif cmd_id == CMD_EVALUATE_EXPRESSION or cmd_id == CMD_EXEC_EXPRESSION: #command to evaluate the given expression #text is: thread\tstackframe\tLOCAL\texpression temp_name = "" try: thread_id, frame_id, scope, expression, trim, temp_name = text.split('\t', 5) except ValueError: thread_id, frame_id, scope, expression, trim = text.split('\t', 4) int_cmd = InternalEvaluateExpression(seq, thread_id, frame_id, expression, cmd_id == CMD_EXEC_EXPRESSION, int(trim) == 1, temp_name) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_CONSOLE_EXEC: #command to exec expression in console, in case expression is only partially valid 'False' is returned #text is: thread\tstackframe\tLOCAL\texpression thread_id, frame_id, scope, expression = text.split('\t', 3) int_cmd = InternalConsoleExec(seq, thread_id, frame_id, expression) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_SET_PY_EXCEPTION: # Command which receives set of exceptions on which user wants to break the debugger # text is: break_on_uncaught;break_on_caught;TypeError;ImportError;zipimport.ZipImportError; # This API is optional and works 'in bulk' -- it's possible # to get finer-grained control with CMD_ADD_EXCEPTION_BREAK/CMD_REMOVE_EXCEPTION_BREAK # which allows setting caught/uncaught per exception. # splitted = text.split(';') py_db.break_on_uncaught_exceptions = {} py_db.break_on_caught_exceptions = {} added = [] if len(splitted) >= 4: if splitted[0] == 'true': break_on_uncaught = True else: break_on_uncaught = False if splitted[1] == 'true': break_on_caught = True else: break_on_caught = False if splitted[2] == 'true': py_db.break_on_exceptions_thrown_in_same_context = True else: py_db.break_on_exceptions_thrown_in_same_context = False if splitted[3] == 'true': py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = True else: py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = False for exception_type in splitted[4:]: exception_type = exception_type.strip() if not exception_type: continue exception_breakpoint = py_db.add_break_on_exception( exception_type, notify_always=break_on_caught, notify_on_terminate=break_on_uncaught, notify_on_first_raise_only=False, ) if exception_breakpoint is None: continue added.append(exception_breakpoint) py_db.update_after_exceptions_added(added) else: sys.stderr.write("Error when setting exception list. Received: %s\n" % (text,)) elif cmd_id == CMD_GET_FILE_CONTENTS: if not IS_PY3K: # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding. text = text.encode(file_system_encoding) if os.path.exists(text): f = open(text, 'r') try: source = f.read() finally: f.close() cmd = py_db.cmd_factory.make_get_file_contents(seq, source) elif cmd_id == CMD_SET_PROPERTY_TRACE: # Command which receives whether to trace property getter/setter/deleter # text is feature_state(true/false);disable_getter/disable_setter/disable_deleter if text != "": splitted = text.split(';') if len(splitted) >= 3: if py_db.disable_property_trace is False and splitted[0] == 'true': # Replacing property by custom property only when the debugger starts pydevd_traceproperty.replace_builtin_property() py_db.disable_property_trace = True # Enable/Disable tracing of the property getter if splitted[1] == 'true': py_db.disable_property_getter_trace = True else: py_db.disable_property_getter_trace = False # Enable/Disable tracing of the property setter if splitted[2] == 'true': py_db.disable_property_setter_trace = True else: py_db.disable_property_setter_trace = False # Enable/Disable tracing of the property deleter if splitted[3] == 'true': py_db.disable_property_deleter_trace = True else: py_db.disable_property_deleter_trace = False else: # User hasn't configured any settings for property tracing pass elif cmd_id == CMD_ADD_EXCEPTION_BREAK: if text.find('\t') != -1: exception, notify_always, notify_on_terminate, ignore_libraries = text.split('\t', 3) else: exception, notify_always, notify_on_terminate, ignore_libraries = text, 0, 0, 0 if exception.find('-') != -1: breakpoint_type, exception = exception.split('-') else: breakpoint_type = 'python' if breakpoint_type == 'python': if int(notify_always) == 1: pydev_log.warn("Deprecated parameter: 'notify always' policy removed in PyCharm\n") exception_breakpoint = py_db.add_break_on_exception( exception, notify_always=int(notify_always) > 0, notify_on_terminate = int(notify_on_terminate) == 1, notify_on_first_raise_only=int(notify_always) == 2, ignore_libraries=int(ignore_libraries) > 0 ) if exception_breakpoint is not None: py_db.update_after_exceptions_added([exception_breakpoint]) else: supported_type = False plugin = py_db.get_plugin_lazy_init() if plugin is not None: supported_type = plugin.add_breakpoint('add_exception_breakpoint', py_db, breakpoint_type, exception) if supported_type: py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks() else: raise NameError(breakpoint_type) elif cmd_id == CMD_REMOVE_EXCEPTION_BREAK: exception = text if exception.find('-') != -1: exception_type, exception = exception.split('-') else: exception_type = 'python' if exception_type == 'python': try: cp = py_db.break_on_uncaught_exceptions.copy() dict_pop(cp, exception, None) py_db.break_on_uncaught_exceptions = cp cp = py_db.break_on_caught_exceptions.copy() dict_pop(cp, exception, None) py_db.break_on_caught_exceptions = cp except: pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0]) update_exception_hook(py_db) else: supported_type = False # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove # anything from it anyways). plugin = py_db.plugin if plugin is not None: supported_type = plugin.remove_exception_breakpoint(py_db, exception_type, exception) if supported_type: py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks() else: raise NameError(exception_type) elif cmd_id == CMD_LOAD_SOURCE: path = text try: f = open(path, 'r') source = f.read() py_db.cmd_factory.make_load_source_message(seq, source, py_db) except: return py_db.cmd_factory.make_error_message(seq, pydevd_tracing.get_exception_traceback_str()) elif cmd_id == CMD_ADD_DJANGO_EXCEPTION_BREAK: exception = text plugin = py_db.get_plugin_lazy_init() if plugin is not None: plugin.add_breakpoint('add_exception_breakpoint', py_db, 'django', exception) py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks() elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK: exception = text # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove # anything from it anyways). plugin = py_db.plugin if plugin is not None: plugin.remove_exception_breakpoint(py_db, 'django', exception) py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks() elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION: # Command which takes care for the debug console communication if text != "": thread_id, frame_id, console_command = text.split('\t', 2) console_command, line = console_command.split('\t') if console_command == 'EVALUATE': int_cmd = InternalEvaluateConsoleExpression( seq, thread_id, frame_id, line, buffer_output=True) elif console_command == 'EVALUATE_UNBUFFERED': int_cmd = InternalEvaluateConsoleExpression( seq, thread_id, frame_id, line, buffer_output=False) elif console_command == 'GET_COMPLETIONS': int_cmd = InternalConsoleGetCompletions(seq, thread_id, frame_id, line) else: raise ValueError('Unrecognized command: %s' % (console_command,)) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_RUN_CUSTOM_OPERATION: # Command which runs a custom operation if text != "": try: location, custom = text.split('||', 1) except: sys.stderr.write('Custom operation now needs a || separator. Found: %s\n' % (text,)) raise thread_id, frame_id, scopeattrs = location.split('\t', 2) if scopeattrs.find('\t') != -1: # there are attributes beyond scope scope, attrs = scopeattrs.split('\t', 1) else: scope, attrs = (scopeattrs, None) # : style: EXECFILE or EXEC # : encoded_code_or_file: file to execute or code # : fname: name of function to be executed in the resulting namespace style, encoded_code_or_file, fnname = custom.split('\t', 3) int_cmd = InternalRunCustomOperation(seq, thread_id, frame_id, scope, attrs, style, encoded_code_or_file, fnname) py_db.post_internal_command(int_cmd, thread_id) elif cmd_id == CMD_IGNORE_THROWN_EXCEPTION_AT: if text: replace = 'REPLACE:' # Not all 3.x versions support u'REPLACE:', so, doing workaround. if not IS_PY3K: replace = unicode(replace) if text.startswith(replace): text = text[8:] py_db.filename_to_lines_where_exceptions_are_ignored.clear() if text: for line in text.split('||'): # Can be bulk-created (one in each line) filename, line_number = line.split('|') if not IS_PY3K: filename = filename.encode(file_system_encoding) filename = pydevd_file_utils.norm_file_to_server(filename) if os.path.exists(filename): lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored.get(filename) if lines_ignored is None: lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored[filename] = {} lines_ignored[int(line_number)] = 1 else: sys.stderr.write('pydev debugger: warning: trying to ignore exception thrown'\ ' on file that does not exist: %s (will have no effect)\n' % (filename,)) elif cmd_id == CMD_ENABLE_DONT_TRACE: if text: true_str = 'true' # Not all 3.x versions support u'str', so, doing workaround. if not IS_PY3K: true_str = unicode(true_str) mode = text.strip() == true_str pydevd_dont_trace.trace_filter(mode) else: #I have no idea what this is all about cmd = py_db.cmd_factory.make_error_message(seq, "unexpected command " + str(cmd_id)) if cmd is not None: py_db.writer.add_command(cmd) del cmd except Exception: traceback.print_exc() from _pydev_bundle.pydev_imports import StringIO stream = StringIO() traceback.print_exc(file=stream) cmd = py_db.cmd_factory.make_error_message( seq, "Unexpected exception in process_net_command.\nInitial params: %s. Exception: %s" % ( ((cmd_id, seq, text), stream.getvalue()) ) ) py_db.writer.add_command(cmd) finally: py_db._main_lock.release()
def _map_file_to_client(filename, cache=norm_filename_to_client_container): # The result of this method will be passed to eclipse # So, this would be 'NormFileFromPythonToEclipse' try: return cache[filename] except KeyError: abs_path = absolute_path(filename) translated_proper_case = get_path_with_real_case(abs_path) translated_normalized = normcase(abs_path) path_mapping_applied = False if translated_normalized.lower() != translated_proper_case.lower(): if DEBUG_CLIENT_SERVER_TRANSLATION: pydev_log.critical( 'pydev debugger: translated_normalized changed path (from: %s to %s)', translated_proper_case, translated_normalized) for i, (eclipse_prefix, python_prefix) in enumerate(paths_from_eclipse_to_python): if translated_normalized.startswith(python_prefix): if DEBUG_CLIENT_SERVER_TRANSLATION: pydev_log.critical( 'pydev debugger: replacing to client: %s', translated_normalized) # Note: use the non-normalized version. eclipse_prefix = initial_paths[i][0] translated = eclipse_prefix + translated_proper_case[ len(python_prefix):] if DEBUG_CLIENT_SERVER_TRANSLATION: pydev_log.critical( 'pydev debugger: sent to client: %s', translated) path_mapping_applied = True break else: if DEBUG_CLIENT_SERVER_TRANSLATION: pydev_log.critical( 'pydev debugger: to client: unable to find matching prefix for: %s in %s', translated_normalized, [x[1] for x in paths_from_eclipse_to_python]) translated = translated_proper_case if eclipse_sep != python_sep: translated = translated.replace(python_sep, eclipse_sep) translated = _path_to_expected_str(translated) # The resulting path is not in the python process, so, we cannot do a normalize the path here, # only at the beginning of this method. cache[filename] = (translated, path_mapping_applied) if translated not in _client_filename_in_utf8_to_source_reference: if path_mapping_applied: source_reference = 0 else: source_reference = _next_source_reference() pydev_log.debug( 'Created source reference: %s for untranslated path: %s', source_reference, filename) _client_filename_in_utf8_to_source_reference[ translated] = source_reference _source_reference_to_server_filename[ source_reference] = filename return (translated, path_mapping_applied)
def do_kill_pydev_thread(self): if not self._kill_received: pydev_log.debug('%s received kill signal', self.name) self._kill_received = True