Thu, 13 Feb 2020 19:27:10 +0100
Continued with the multiprocess debugger.
# -*- coding: utf-8 -*- # Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a function to patch QProcess to support debugging of the process. """ import os _debugClient = None def _isPythonProgram(program, arguments): """ Protected function to check, if program is a Python interpreter and arguments don't include '-m'. @param program program to be executed @type str @param arguments list of command line arguments @type list of str @return flag indicating a python program and a tuple containing the interpreter to be used and the arguments @rtype tuple of (bool, tuple of (str, list of str)) """ prog = program.lower() ok = ( ("python" in prog and arguments[0] != '-m') or "pypy" in prog ) return ok, (program, arguments[:]) def patchQProcess(module, debugClient): """ Function to patch the QtCore module's QProcess. @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 class QProcessWrapper(module.QProcess): """ Wrapper class for *.QProcess. """ _origQProcessStartDetached = module.QProcess.startDetached def __init__(self, parent=None): """ Constructor """ super(QProcessWrapper, self).__init__(parent) @classmethod def modifyArgs(cls, arguments, multiprocessSupport): """ Private method to modify the arguments given to the start method. @param arguments list of program arguments @type list of str @return modified argument list @rtype list of str """ (wd, host, port, exceptions, tracePython, redirect, noencoding) = _debugClient.startOptions[:7] modifiedArguments = [ os.path.join(os.path.dirname(__file__), "DebugClient.py"), "-h", host, "-p", str(port), "--no-passive", ] if wd: modifiedArguments.extend(["-w", wd]) if not exceptions: modifiedArguments.append("-e") if tracePython: modifiedArguments.append("-t") if not redirect: modifiedArguments.append("-n") if noencoding: modifiedArguments.append("--no-encoding") if multiprocessSupport: modifiedArguments.append("--multiprocess") modifiedArguments.append("--") # end the arguments for DebugClient modifiedArguments.extend(arguments) return modifiedArguments ################################################################### ## Handling of 'start(...)' below ################################################################### def start(self, *args, **kwargs): """ Public method to start the process. This method patches the arguments such, that a debug client is started for the Python script. A Python script is assumed, if the program to be started contains the string 'python'. @param args arguments of the start call @type list @param kwargs keyword arguments of the start call @type dict """ if ( _debugClient.debugging and _debugClient.multiprocessSupport and ((len(args) >= 2 and isinstance(args[1], list)) or (len(args) == 1 and not isinstance(args[0], str)) or len(args) == 0) ): if len(args) >= 2: program = args[0] arguments = args[1] if len(args) > 2: mode = args[2] else: mode = module.QIODevice.ReadWrite else: program = self.program() arguments = self.arguments() if len(args) == 1: mode = args[0] else: mode = module.QIODevice.ReadWrite ok, (program, arguments) = _isPythonProgram(program, arguments) if ( ok and ( not os.path.basename(arguments[0]) in _debugClient.noDebugList ) ): newArgs = self.modifyArgs( arguments, _debugClient.multiprocessSupport) super(QProcessWrapper, self).start(program, newArgs, mode) else: super(QProcessWrapper, self).start(*args, **kwargs) else: super(QProcessWrapper, self).start(*args, **kwargs) ################################################################### ## Handling of 'startDetached(...)' below ################################################################### def startDetached(self, *args, **kwargs): """ Public method to start the detached process. This method patches the arguments such, that a debug client is started for the Python script. A Python script is assumed, if the program to be started contains the string 'python'. @param args arguments of the start call @type list @param kwargs keyword arguments of the start call @type dict @return flag indicating a successful start @rtype bool """ if isinstance(self, str): return QProcessWrapper.startDetachedStatic( self, *args) else: return self.__startDetached(*args, **kwargs) def __startDetached(self, *args, **kwargs): """ Private method to start the detached process. This method patches the arguments such, that a debug client is started for the Python script. A Python script is assumed, if the program to be started contains the string 'python'. @param args arguments of the start call @type list @param kwargs keyword arguments of the start call @type dict @return flag indicating a successful start @rtype bool """ if ( _debugClient.debugging and _debugClient.multiprocessSupport and len(args) == 0 ): program = self.program() arguments = self.arguments() wd = self.workingDirectory() ok, (program, arguments) = _isPythonProgram(program, arguments) if ok: return QProcessWrapper.startDetachedStatic( program, arguments, wd) else: return super(QProcessWrapper, self).startDetached( *args, **kwargs) else: return super(QProcessWrapper, self).startDetached( *args, **kwargs) @staticmethod def startDetachedStatic(*args, **kwargs): """ Static method to start the detached process. This method patches the arguments such, that a debug client is started for the Python script. A Python script is assumed, if the program to be started contains the string 'python'. @param args arguments of the start call @type list @param kwargs keyword arguments of the start call @type dict @return flag indicating a successful start @rtype bool """ if ( _debugClient.debugging and _debugClient.multiprocessSupport and (len(args) >= 2 and isinstance(args[1], list)) ): program = args[0] arguments = args[1] if len(args) >= 3: wd = args[2] else: wd = "" ok, (program, arguments) = _isPythonProgram(program, arguments) if ok: newArgs = QProcessWrapper.modifyArgs( arguments, _debugClient.multiprocessSupport) return QProcessWrapper._origQProcessStartDetached( program, newArgs, wd) else: return QProcessWrapper._origQProcessStartDetached( *args, **kwargs) else: return QProcessWrapper._origQProcessStartDetached( *args, **kwargs) _debugClient = debugClient module.QProcess = QProcessWrapper