def add_custom_frame(frame, name, thread_id): ''' It's possible to show paused frames by adding a custom frame through this API (it's intended to be used for coroutines, but could potentially be used for generators too). :param frame: The topmost frame to be shown paused when a thread with thread.ident == thread_id is paused. :param name: The name to be shown for the custom thread in the UI. :param thread_id: The thread id to which this frame is related (must match thread.ident). :return: str Returns the custom thread id which will be used to show the given frame paused. ''' with CustomFramesContainer.custom_frames_lock: curr_thread_id = get_current_thread_id(threading.current_thread()) next_id = CustomFramesContainer._next_frame_id = CustomFramesContainer._next_frame_id + 1 # Note: the frame id kept contains an id and thread information on the thread where the frame was added # so that later on we can check if the frame is from the current thread by doing frame_id.endswith('|'+thread_id). frame_custom_thread_id = '__frame__:%s|%s' % (next_id, curr_thread_id) if DEBUG: sys.stderr.write( 'add_custom_frame: %s (%s) %s %s\n' % (frame_custom_thread_id, get_abs_path_real_path_and_base_from_frame(frame)[-1], frame.f_lineno, frame.f_code.co_name)) CustomFramesContainer.custom_frames[ frame_custom_thread_id] = CustomFrame(name, frame, thread_id) CustomFramesContainer._py_db_command_thread_event.set() return frame_custom_thread_id
def _pydev_needs_stop_at_break(line): ''' We separate the functionality into 2 functions so that we can generate a bytecode which generates a spurious line change so that we can do: if _pydev_needs_stop_at_break(): # Set line to line -1 _pydev_stop_at_break() # then, proceed to go to the current line # (which will then trigger a line event). ''' t = threading.current_thread() try: additional_info = t.additional_info except: additional_info = set_additional_thread_info(t) if additional_info.is_tracing: return False additional_info.is_tracing += 1 try: frame = sys._getframe(1) # print('pydev needs stop at break?', line, 'curr line', frame.f_lineno, 'curr trace', frame.f_trace) if frame.f_trace is not None: # i.e.: this frame is already being traced, thus, we don't need to use programmatic breakpoints. return False py_db = get_global_debugger() if py_db is None: return False 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) canonical_normalized_filename = abs_path_real_path_and_base[1] try: python_breakpoint = py_db.breakpoints[ canonical_normalized_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 False if python_breakpoint: # print('YES') return True finally: additional_info.is_tracing -= 1 return False
def _pydev_stop_at_break(line): frame = sys._getframe(1) # print('pydevd SET TRACING at ', line, 'curr line', frame.f_lineno) t = threading.current_thread() try: additional_info = t.additional_info except: additional_info = set_additional_thread_info(t) if additional_info.is_tracing: return additional_info.is_tracing += 1 try: py_db = get_global_debugger() if py_db is None: return pydev_log.debug( "Setting f_trace due to frame eval mode in file: %s on line %s", frame.f_code.co_filename, line) 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: frame.f_trace = py_db.get_thread_local_trace_func() finally: additional_info.is_tracing -= 1
def dump_frames(thread_id): sys.stdout.write('dumping frames\n') if thread_id != get_current_thread_id(threading.current_thread()): raise VariableError("find_frame: must execute on same thread") frame = get_frame() for frame in iter_frames(frame): sys.stdout.write('%s\n' % pickle.dumps(frame))
def get_interpreter(): try: interpreterInterface = getattr(__builtin__, 'interpreter') except AttributeError: interpreterInterface = InterpreterInterface(None, None, threading.current_thread()) __builtin__.interpreter = interpreterInterface sys.stderr.write(interpreterInterface.get_greeting_msg()) sys.stderr.flush() return interpreterInterface
def start_server(host, port, client_port): # replace exit (see comments on method) # note that this does not work in jython!!! (sys method can't be replaced). sys.exit = do_exit interpreter = InterpreterInterface(host, client_port, threading.current_thread()) start_new_thread(start_console_server, (host, port, interpreter)) process_exec_queue(interpreter)
def do_connect_to_debugger(): try: # Try to import the packages needed to attach the debugger import pydevd from _pydev_bundle._pydev_saved_modules import threading except: # This happens on Jython embedded in host eclipse traceback.print_exc() sys.stderr.write('pydevd is not available, cannot connect\n') from _pydevd_bundle.pydevd_constants import set_thread_id from _pydev_bundle import pydev_localhost set_thread_id(threading.current_thread(), "console_main") VIRTUAL_FRAME_ID = "1" # matches PyStackFrameConsole.java VIRTUAL_CONSOLE_ID = "console_main" # matches PyThreadConsole.java f = FakeFrame() f.f_back = None f.f_globals = { } # As globals=locals here, let's simply let it empty (and save a bit of network traffic). f.f_locals = self.get_namespace() self.debugger = pydevd.PyDB() self.debugger.add_fake_frame(thread_id=VIRTUAL_CONSOLE_ID, frame_id=VIRTUAL_FRAME_ID, frame=f) try: pydevd.apply_debugger_options(debugger_options) self.debugger.connect(pydev_localhost.get_localhost(), debuggerPort) self.debugger.prepare_to_run() self.debugger.disable_tracing() except: traceback.print_exc() sys.stderr.write('Failed to connect to target debugger.\n') # Register to process commands when idle self.debugrunning = False try: import pydevconsole pydevconsole.set_debug_hook( self.debugger.process_internal_commands) except: traceback.print_exc() sys.stderr.write( 'Version of Python does not support debuggable Interactive Console.\n' )
def new_func(py_db, frame, expression, is_exec): if py_db is None: # Only for testing... pydev_log.critical('_evaluate_with_timeouts called without py_db!') return original_func(py_db, frame, expression, is_exec) warn_evaluation_timeout = pydevd_constants.PYDEVD_WARN_EVALUATION_TIMEOUT curr_thread = threading.current_thread() def on_warn_evaluation_timeout(): py_db.writer.add_command( py_db.cmd_factory.make_evaluation_timeout_msg( py_db, expression, curr_thread)) timeout_tracker = py_db.timeout_tracker # : :type timeout_tracker: TimeoutTracker with timeout_tracker.call_on_timeout(warn_evaluation_timeout, on_warn_evaluation_timeout): return _run_with_unblock_threads(original_func, py_db, curr_thread, frame, expression, is_exec)
def run(self): created_pydb_daemon = self.py_db.created_pydb_daemon_threads created_pydb_daemon[self] = 1 try: try: if IS_JYTHON and not isinstance(threading.current_thread(), threading._MainThread): # we shouldn't update sys.modules for the main thread, cause it leads to the second importing 'threading' # module, and the new instance of main thread is created ss = JyCore.PySystemState() # Note: Py.setSystemState() affects only the current thread. JyCore.Py.setSystemState(ss) self._stop_trace() self._on_run() except: if sys is not None and pydev_log_exception is not None: pydev_log_exception() finally: del created_pydb_daemon[self]
def __call__(self): # We monkey-patch the thread creation so that this function is called in the new thread. At this point # we notify of its creation and start tracing it. py_db = get_global_debugger() thread_id = None if py_db is not None: # Note: if this is a thread from threading.py, we're too early in the boostrap process (because we mocked # the start_new_thread internal machinery and thread._bootstrap has not finished), so, the code below needs # to make sure that we use the current thread bound to the original function and not use # threading.current_thread() unless we're sure it's a dummy thread. t = getattr(self.original_func, '__self__', getattr(self.original_func, 'im_self', None)) if not isinstance(t, threading.Thread): # This is not a threading.Thread but a Dummy thread (so, get it as a dummy thread using # currentThread). t = threading.current_thread() if not getattr(t, 'is_pydev_daemon_thread', False): thread_id = get_current_thread_id(t) py_db.notify_thread_created(thread_id, t) _on_set_trace_for_new_thread(py_db) if getattr(py_db, 'thread_analyser', None) is not None: try: from _pydevd_bundle.pydevd_concurrency_analyser.pydevd_concurrency_logger import log_new_thread log_new_thread(py_db, t) except: sys.stderr.write( "Failed to detect new thread for visualization") try: ret = self.original_func(*self.args, **self.kwargs) finally: if thread_id is not None: if py_db is not None: # At thread shutdown we only have pydevd-related code running (which shouldn't # be tracked). py_db.disable_tracing() py_db.notify_thread_not_alive(thread_id) return ret
def create_interrupt_this_thread_callback(): ''' The idea here is returning a callback that when called will generate a KeyboardInterrupt in the thread that called this function. If this is the main thread, this means that it'll emulate a Ctrl+C (which may stop I/O and sleep operations). For other threads, this will call PyThreadState_SetAsyncExc to raise a KeyboardInterrupt before the next instruction (so, it won't really interrupt I/O or sleep operations). :return callable: Returns a callback that will interrupt the current thread (this may be called from an auxiliary thread). ''' tid = thread_get_ident() if is_current_thread_main_thread(): main_thread = threading.current_thread() def raise_on_this_thread(): pydev_log.debug('Callback to interrupt main thread.') pydevd_utils.interrupt_main_thread(main_thread) else: # Note: this works in the sense that it can stop some cpu-intensive slow operation, # but we can't really interrupt the thread out of some sleep or I/O operation # (this will only be raised when Python is about to execute the next instruction). def raise_on_this_thread(): if IS_CPYTHON: pydev_log.debug('Interrupt thread: %s', tid) ctypes.pythonapi.PyThreadState_SetAsyncExc( ctypes.c_long(tid), ctypes.py_object(KeyboardInterrupt)) else: pydev_log.debug( 'It is only possible to interrupt non-main threads in CPython.' ) return raise_on_this_thread
def getVariable(dbg, thread_id, frame_id, scope, attrs): """ returns the value of a variable :scope: can be BY_ID, EXPRESSION, GLOBAL, LOCAL, FRAME BY_ID means we'll traverse the list of all objects alive to get the object. :attrs: after reaching the proper scope, we have to get the attributes until we find the proper location (i.e.: obj\tattr1\tattr2) :note: when BY_ID is used, the frame_id is considered the id of the object to find and not the frame (as we don't care about the frame in this case). """ if scope == 'BY_ID': if thread_id != get_current_thread_id(threading.current_thread()): raise VariableError("getVariable: must execute on same thread") try: import gc objects = gc.get_objects() except: pass # Not all python variants have it. else: frame_id = int(frame_id) for var in objects: if id(var) == frame_id: if attrs is not None: attrList = attrs.split('\t') for k in attrList: _type, _type_name, resolver = get_type(var) var = resolver.resolve(var, k) return var # If it didn't return previously, we coudn't find it by id (i.e.: alrceady garbage collected). sys.stderr.write('Unable to find object with id: %s\n' % (frame_id, )) return None frame = dbg.find_frame(thread_id, frame_id) if frame is None: return {} if attrs is not None: attrList = attrs.split('\t') else: attrList = [] for attr in attrList: attr.replace("@_@TAB_CHAR@_@", '\t') if scope == 'EXPRESSION': for count in range(len(attrList)): if count == 0: # An Expression can be in any scope (globals/locals), therefore it needs to evaluated as an expression var = evaluate_expression(dbg, frame, attrList[count], False) else: _type, _type_name, resolver = get_type(var) var = resolver.resolve(var, attrList[count]) else: if scope == "GLOBAL": var = frame.f_globals del attrList[ 0] # globals are special, and they get a single dummy unused attribute else: # in a frame access both locals and globals as Python does var = {} var.update(frame.f_globals) var.update(frame.f_locals) for k in attrList: _type, _type_name, resolver = get_type(var) var = resolver.resolve(var, k) return var
def set_trace_in_qt(): from _pydevd_bundle.pydevd_comm import get_global_debugger py_db = get_global_debugger() if py_db is not None: threading.current_thread() # Create the dummy thread for qt. py_db.enable_tracing()
if int(port) == 0 and int(client_port) == 0: (h, p) = pydev_localhost.get_socket_name() client_port = p host = pydev_localhost.get_localhost() #replace exit (see comments on method) #note that this does not work in jython!!! (sys method can't be replaced). sys.exit = skip_successful_exit connect_status_queue = _queue.Queue() interpreter = InterpreterInterface( host, int(client_port), threading.current_thread(), connect_status_queue=connect_status_queue) server_thread = threading.Thread(target=start_console_server, name='ServerThread', args=(host, int(port), interpreter)) server_thread.daemon = True server_thread.start() sys.stdin = StdIn(interpreter, host, client_port, sys.stdin) init_mpl_in_console(interpreter) try: success = connect_status_queue.get(True, 60) if not success:
def is_current_thread_main_thread(): if hasattr(threading, 'main_thread'): return threading.current_thread() is threading.main_thread() else: return isinstance(threading.current_thread(), threading._MainThread)