import os from _pydevd_bundle import pydevd_vars from _pydevd_bundle.pydevd_breakpoints import LineBreakpoint from _pydevd_bundle.pydevd_comm import CMD_SET_BREAK, CMD_ADD_EXCEPTION_BREAK from _pydevd_bundle.pydevd_constants import dict_iter_items, get_thread_id, JUPYTER_SUSPEND, dict_keys from _pydevd_bundle.pydevd_frame_utils import FCode, add_exception_to_frame class JupyterLineBreakpoint(LineBreakpoint): def __init__(self, file, line, condition, func_name, expression, hit_condition=None, is_logpoint=False): LineBreakpoint.__init__(self, line, condition, func_name, expression, hit_condition=hit_condition, is_logpoint=is_logpoint) self.file = file self.cell_file = None def is_triggered(self, template_frame_file, template_frame_line): return self.file == template_frame_file and self.line == template_frame_line def __str__(self): return "JupyterLineBreakpoint: %s-%d-%s" % (self.file, self.line, self.cell_file) def __repr__(self): return '' % (self.file, self.line, self.condition, self.func_name, self.expression, self.cell_file) def add_line_breakpoint(plugin, pydb, type, file, line, condition, expression, func_name, hit_condition=None, is_logpoint=False): if type == 'jupyter-line': breakpoint = JupyterLineBreakpoint(file, line, condition, func_name, expression, hit_condition=hit_condition, is_logpoint=is_logpoint) if not hasattr(pydb, 'jupyter_breakpoints'): _init_plugin_breaks(pydb) return breakpoint, pydb.jupyter_breakpoints return None def _init_plugin_breaks(pydb): pydb.jupyter_exception_break = {} pydb.jupyter_breakpoints = {} def add_exception_breakpoint(plugin, pydb, type, exception): if type == 'jupyter': if not hasattr(pydb, 'jupyter_exception_break'): _init_plugin_breaks(pydb) pydb.jupyter_exception_break[exception] = True pydb.set_tracing_for_untraced_contexts() return True return False def remove_exception_breakpoint(plugin, pydb, type, exception): if type == 'jupyter': try: del pydb.jupyter_exception_break[exception] return True except: pass return False def get_breakpoints(plugin, pydb, type): if type == 'jupyter-line': return pydb.jupyter_breakpoints return None def change_variable(plugin, frame, attr, expression): return False def has_exception_breaks(plugin): if len(plugin.main_debugger.jupyter_exception_break) > 0: return True return False #======================================================================================================================= # Jupyter Step Commands #======================================================================================================================= def has_line_breaks(plugin): for file, breakpoints in dict_iter_items(plugin.main_debugger.jupyter_breakpoints): if len(breakpoints) > 0: return True return False def can_not_skip(plugin, pydb, frame, info): step_cmd = info.pydev_step_cmd if step_cmd == 108 and _is_equals(frame, _get_stop_frame(info)): return True if pydb.jupyter_breakpoints: filename = frame.f_code.co_filename cell_info = pydb.cell_info if filename in cell_info.jupyter_cell_name_to_id: cell_id = cell_info.jupyter_cell_name_to_id[filename] if cell_id in pydb.jupyter_breakpoints: line_to_bp = pydb.jupyter_breakpoints[cell_id] if len(line_to_bp) > 0: return True return False def _is_jupyter_suspended(thread): return thread.additional_info.suspend_type == JUPYTER_SUSPEND def cmd_step_into(plugin, pydb, frame, event, args, stop_info, stop): plugin_stop = False thread = args[3] if _is_jupyter_suspended(thread): stop = False filename = frame.f_code.co_filename if _is_inside_jupyter_cell(frame, pydb) and not filename.endswith("iostream.py"): stop_info['jupyter_stop'] = event == "line" plugin_stop = stop_info['jupyter_stop'] return stop, plugin_stop def _is_equals(frame, other_frame): # We can't compare frames directly, because Jupyter compiles ast nodes # in cell separately. At the same time, the frame filename is unique and stays # the same within a cell. return frame.f_code.co_filename == other_frame.f_code.co_filename \ and ((frame.f_code.co_name.startswith('', file_name) self.f_lineno = frame.f_lineno self.f_back = frame self.f_globals = frame.f_globals self.f_locals = frame.f_locals self.f_trace = None