--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric6/DebugClients/Python/MultiprocessingExtension.py Sat May 02 14:35:03 2020 +0200 @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a function to patch multiprocessing.Process to support +debugging of the process. +""" + +import sys +import traceback + +_debugClient = None +_originalProcess = None +_originalBootstrap = None + + + +def patchMultiprocessing(module, debugClient): + """ + Function to patch the multiprocessing module. + + @param module reference to the imported module to be patched + @type module + @param debugClient reference to the debug client object + @type DebugClient + """ # __IGNORE_WARNING_D234__ + global _debugClient, _originalProcess, _originalBootstrap + + _debugClient = debugClient + + if sys.version_info >= (3, 4): + _originalProcess = module.process.BaseProcess + else: + _originalProcess = module.Process + _originalBootstrap = _originalProcess._bootstrap + + class ProcessWrapper(_originalProcess): + """ + Wrapper class for multiprocessing.Process. + """ + def _bootstrap(self, *args, **kwargs): + """ + Wrapper around _bootstrap to start debugger. + + @param args function arguments + @type list + @param kwargs keyword only arguments + @type dict + @return exit code of the process + @rtype int + """ + if ( + _debugClient.debugging and + _debugClient.multiprocessSupport + ): + try: + (wd, host, port, exceptions, tracePython, redirect, + noencoding) = _debugClient.startOptions[:7] + _debugClient.startDebugger( + sys.argv[0], host=host, port=port, + exceptions=exceptions, tracePython=tracePython, + redirect=redirect, passive=False, + multiprocessSupport=True + ) + except Exception: + print("Exception during multiprocessing bootstrap init:") + traceback.print_exc(file=sys.stdout) + sys.stdout.flush() + raise + + return _originalBootstrap(self, *args, **kwargs) + + if sys.version_info >= (3, 4): + _originalProcess._bootstrap = ProcessWrapper._bootstrap + else: + module.Process = ProcessWrapper + +## if sys.version_info >= (3, 4): +## _originalProcess = module.Process +#### _originalProcess = module.process.BaseProcess +## else: +## _originalProcess = module.Process +## class ProcessWrapper(_originalProcess): +## def __init__(self, *args, **kwargs): +## super(ProcessWrapper, self).__init__(*args, **kwargs) +## self._run = self.run +## self.run = self._bootstrap_eric6 +## # Class attributes are not transfered to new process. Therefore make a +## # copy as instance attribute +## self._options = _debugClient.startOptions +## +## def _bootstrap_eric6(self): +## """ +## Bootstrap for threading, which reports exceptions correctly. +## +## @param run the run method of threading.Thread +## @type method pointer +## """ +## from DebugClient import DebugClient +## self.debugClient = DebugClient() +## +## (_wd, host, port, exceptions, tracePython, redirect, +## noencoding) = self._options[:7] +## +## args = sys.argv +## self.debugClient.name = self.name +## +## self.debugClient.startDebugger(args[0], host, port, +## exceptions=exceptions, +## tracePython=tracePython, +## redirect=redirect) +## +## try: +## self._run() +## except Exception: +## excinfo = sys.exc_info() +## self.debugClient.user_exception(excinfo, True) +## finally: +## sys.settrace(None) +## +## if sys.version_info >= (3, 4): +## module.Process = ProcessWrapper +#### module.process.BaseProcess = ProcessWrapper +## else: +## module.Process = ProcessWrapper