From d9e2d895eb5d8f88a6c79a6ec0d14c76a5762e25 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Mon, 23 Nov 2015 19:10:58 +0300 Subject: [PATCH] Updates from PyDev.Debugger --- python/helpers/pydev/pydev_monkey.py | 152 ++++++++++++++++++--------- 1 file changed, 101 insertions(+), 51 deletions(-) diff --git a/python/helpers/pydev/pydev_monkey.py b/python/helpers/pydev/pydev_monkey.py index ec50430df530..74050b1afdce 100644 --- a/python/helpers/pydev/pydev_monkey.py +++ b/python/helpers/pydev/pydev_monkey.py @@ -1,16 +1,62 @@ +# License: EPL import os import sys import traceback -import pydev_log +try: + xrange +except: + xrange = range + +#=============================================================================== +# Things that are dependent on having the pydevd debugger +#=============================================================================== +def log_debug(msg): + import pydev_log + pydev_log.debug(msg) + +def log_error_once(msg): + import pydev_log + pydev_log.error_once(msg) pydev_src_dir = os.path.dirname(__file__) -from pydevd_constants import xrange +def _get_python_c_args(host, port, indC, args): + return ("import sys; sys.path.append(r'%s'); import pydevd; " + "pydevd.settrace(host='%s', port=%s, suspend=False, trace_only_current_thread=False, patch_multiprocessing=True); %s" + ) % ( + pydev_src_dir, + host, + port, + args[indC + 1]) +def _get_host_port(): + import pydevd + host, port = pydevd.dispatch() + return host, port + +def _is_managed_arg(arg): + if arg.endswith('pydevd.py'): + return True + return False + +def _on_forked_process(): + import pydevd + pydevd.threadingCurrentThread().__pydevd_main_thread = True + pydevd.settrace_forked() + +def _on_set_trace_for_new_thread(): + from pydevd_comm import GetGlobalDebugger + global_debugger = GetGlobalDebugger() + if global_debugger is not None: + global_debugger.SetTrace(global_debugger.trace_dispatch) + +#=============================================================================== +# Things related to monkey-patching +#=============================================================================== def is_python(path): if path.endswith("'") or path.endswith('"'): - path = path[1:len(path)-1] + path = path[1:len(path) - 1] filename = os.path.basename(path).lower() for name in ['python', 'jython', 'pypy']: if filename.find(name) != -1: @@ -20,7 +66,7 @@ def is_python(path): def patch_args(args): try: - pydev_log.debug("Patching args: %s"% str(args)) + log_debug("Patching args: %s"% str(args)) import sys new_args = [] @@ -35,19 +81,16 @@ def patch_args(args): indC = -1 if indC != -1: - import pydevd - host, port = pydevd.dispatch() + host, port = _get_host_port() if port is not None: new_args.extend(args) - new_args[indC + 1] = ("import sys; sys.path.append(r'%s'); import pydevd; " - "pydevd.settrace(host='%s', port=%s, suspend=False, trace_only_current_thread=False, patch_multiprocessing=True); %s") % ( - pydev_src_dir, host, port, args[indC + 1]) + new_args[indC + 1] = _get_python_c_args(host, port, indC, args) return new_args else: new_args.append(args[0]) else: - pydev_log.debug("Process is not python, returning.") + log_debug("Process is not python, returning.") return args i = 1 @@ -58,7 +101,7 @@ def patch_args(args): break i += 1 - if i < len(args) and args[i].endswith('pydevd.py'): #no need to add pydevd twice + if i < len(args) and _is_managed_arg(args[i]): # no need to add pydevd twice return args for x in sys.original_argv: @@ -108,7 +151,7 @@ def str_to_args_windows(args): for i in xrange(args_len): ch = args[i] if (ch == '\\'): - backslashes+=1 + backslashes += 1 continue elif (backslashes != 0): if ch == '"': @@ -122,16 +165,16 @@ def str_to_args_windows(args): buf += '"' backslashes = 0 continue - # else fall through to switch + # else fall through to switch else: # false alarm, treat passed backslashes literally... if (state == DEFAULT): state = ARG while backslashes > 0: - backslashes-=1 + backslashes -= 1 buf += '\\' - # fall through to switch + # fall through to switch if ch in (' ', '\t'): if (state == DEFAULT): # skip @@ -156,9 +199,10 @@ def str_to_args_windows(args): # Two consecutive double quotes inside a double-quoted argument are interpreted as # a single double quote. buf += '"' - i+=1 + i += 1 elif len(buf) == 0: - # empty string on Windows platform. Account for bug in constructor of JDK's java.lang.ProcessImpl. + # empty string on Windows platform. Account for bug in constructor of + # JDK's java.lang.ProcessImpl. result.append("\"\"") state = DEFAULT else: @@ -180,7 +224,7 @@ def patch_arg_str_win(arg_str): if not is_python(args[0]): return arg_str arg_str = args_to_str(patch_args(args)) - pydev_log.debug("New args: %s" % arg_str) + log_debug("New args: %s" % arg_str) return arg_str def monkey_patch_module(module, funcname, create_func): @@ -196,11 +240,9 @@ def monkey_patch_os(funcname, create_func): def warn_multiproc(): - import pydev_log - - pydev_log.error_once( - "pydev debugger: New process is launching (breakpoints won't work in the new process).\n" - "pydev debugger: To debug that process please enable 'Attach to subprocess automatically while debugging?' option in the debugger settings.\n") + log_error_once( + "pydev debugger: New process is launching (breakpoints won't work in the new process).\n" + "pydev debugger: To debug that process please enable 'Attach to subprocess automatically while debugging?' option in the debugger settings.\n") def create_warn_multiproc(original_name): @@ -226,6 +268,7 @@ os.execlpe(file, arg0, arg1, ..., env) return getattr(os, original_name)(path, *args) return new_execl + def create_execv(original_name): def new_execv(path, args): ''' @@ -236,6 +279,7 @@ os.execvp(file, args) return getattr(os, original_name)(path, patch_args(args)) return new_execv + def create_execve(original_name): """ os.execve(path, args, env) @@ -258,6 +302,7 @@ os.spawnlp(mode, file, arg0, arg1, ...) return getattr(os, original_name)(mode, path, *args) return new_spawnl + def create_spawnv(original_name): def new_spawnv(mode, path, args): ''' @@ -268,6 +313,7 @@ os.spawnvp(mode, file, args) return getattr(os, original_name)(mode, path, patch_args(args)) return new_spawnv + def create_spawnve(original_name): """ os.spawnve(mode, path, args, env) @@ -278,6 +324,7 @@ os.spawnvpe(mode, file, args, env) return getattr(os, original_name)(mode, path, patch_args(args), env) return new_spawnve + def create_fork_exec(original_name): """ _posixsubprocess.fork_exec(args, executable_list, close_fds, ... (13 more)) @@ -288,6 +335,7 @@ _posixsubprocess.fork_exec(args, executable_list, close_fds, ... (13 more)) return getattr(_posixsubprocess, original_name)(args, *other_args) return new_fork_exec + def create_CreateProcess(original_name): """ CreateProcess(*args, **kwargs) @@ -300,6 +348,7 @@ CreateProcess(*args, **kwargs) return getattr(_subprocess, original_name)(appName, patch_arg_str_win(commandLine), *args) return new_CreateProcess + def create_CreateProcessWarnMultiproc(original_name): """ CreateProcess(*args, **kwargs) @@ -313,27 +362,26 @@ CreateProcess(*args, **kwargs) return getattr(_subprocess, original_name)(*args) return new_CreateProcess + def create_fork(original_name): def new_fork(): import os - child_process = getattr(os, original_name)() # fork + child_process = getattr(os, original_name)() # fork if not child_process: - import pydevd - pydevd.threadingCurrentThread().__pydevd_main_thread = True - - pydevd.settrace_forked() + _on_forked_process() return child_process return new_fork + def patch_new_process_functions(): -#os.execl(path, arg0, arg1, ...) -#os.execle(path, arg0, arg1, ..., env) -#os.execlp(file, arg0, arg1, ...) -#os.execlpe(file, arg0, arg1, ..., env) -#os.execv(path, args) -#os.execve(path, args, env) -#os.execvp(file, args) -#os.execvpe(file, args, env) + # os.execl(path, arg0, arg1, ...) + # os.execle(path, arg0, arg1, ..., env) + # os.execlp(file, arg0, arg1, ...) + # os.execlpe(file, arg0, arg1, ..., env) + # os.execv(path, args) + # os.execve(path, args, env) + # os.execvp(file, args) + # os.execvpe(file, args, env) monkey_patch_os('execl', create_execl) monkey_patch_os('execle', create_execl) monkey_patch_os('execlp', create_execl) @@ -343,14 +391,14 @@ def patch_new_process_functions(): monkey_patch_os('execvp', create_execv) monkey_patch_os('execvpe', create_execve) -#os.spawnl(mode, path, ...) -#os.spawnle(mode, path, ..., env) -#os.spawnlp(mode, file, ...) -#os.spawnlpe(mode, file, ..., env) -#os.spawnv(mode, path, args) -#os.spawnve(mode, path, args, env) -#os.spawnvp(mode, file, args) -#os.spawnvpe(mode, file, args, env) + # os.spawnl(mode, path, ...) + # os.spawnle(mode, path, ..., env) + # os.spawnlp(mode, file, ...) + # os.spawnlpe(mode, file, ..., env) + # os.spawnv(mode, path, args) + # os.spawnve(mode, path, args, env) + # os.spawnvp(mode, file, args) + # os.spawnvpe(mode, file, args, env) monkey_patch_os('spawnl', create_spawnl) monkey_patch_os('spawnle', create_spawnl) @@ -369,7 +417,7 @@ def patch_new_process_functions(): except ImportError: pass else: - #Windows + # Windows try: import _subprocess except ImportError: @@ -403,7 +451,7 @@ def patch_new_process_functions_with_warning(): except ImportError: pass else: - #Windows + # Windows try: import _subprocess except ImportError: @@ -411,7 +459,6 @@ def patch_new_process_functions_with_warning(): monkey_patch_module(_subprocess, 'CreateProcess', create_CreateProcessWarnMultiproc) - class _NewThreadStartupWithTrace: def __init__(self, original_func, args, kwargs): @@ -420,10 +467,9 @@ class _NewThreadStartupWithTrace: self.kwargs = kwargs def __call__(self): + _on_set_trace_for_new_thread() from pydevd_comm import GetGlobalDebugger global_debugger = GetGlobalDebugger() - if global_debugger is not None: - global_debugger.SetTrace(global_debugger.trace_dispatch) if global_debugger.thread_analyser is not None: # we can detect start_new_thread only here @@ -435,6 +481,7 @@ class _NewThreadStartupWithTrace: return self.original_func(*self.args, **self.kwargs) + class _NewThreadStartupWithoutTrace: def __init__(self, original_func, args, kwargs): @@ -447,6 +494,7 @@ class _NewThreadStartupWithoutTrace: _UseNewThreadStartup = _NewThreadStartupWithTrace + def _get_threading_modules_to_patch(): threading_modules_to_patch = [] try: @@ -460,7 +508,6 @@ def _get_threading_modules_to_patch(): threading_modules_to_patch = _get_threading_modules_to_patch() - def patch_thread_module(thread): if getattr(thread, '_original_start_new_thread', None) is None: @@ -468,7 +515,6 @@ def patch_thread_module(thread): else: _original_start_new_thread = thread._original_start_new_thread - class ClassWithPydevStartNewThread: def pydev_start_new_thread(self, function, args=(), kwargs={}): @@ -496,10 +542,12 @@ def patch_thread_module(thread): except: pass + def patch_thread_modules(): for t in threading_modules_to_patch: patch_thread_module(t) + def undo_patch_thread_modules(): for t in threading_modules_to_patch: try: @@ -512,6 +560,7 @@ def undo_patch_thread_modules(): except: pass + def disable_trace_thread_modules(): ''' Can be used to temporarily stop tracing threads created with thread.start_new_thread. @@ -527,6 +576,7 @@ def enable_trace_thread_modules(): global _UseNewThreadStartup _UseNewThreadStartup = _NewThreadStartupWithTrace + def get_original_start_new_thread(threading_module): try: return threading_module._original_start_new_thread