eric6/DebugClients/Python/QProcessExtension.py

Wed, 12 Feb 2020 20:04:31 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 12 Feb 2020 20:04:31 +0100
branch
multi_processing
changeset 7410
401791e6f50f
parent 7409
1413bfe73d41
child 7411
6d8dcb3551b3
permissions
-rw-r--r--

Continued with the multiprocess debugger. Implemented QProcess.startDetached() wrapper.

# -*- 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


# TODO: extend this with first line logic
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'
    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:
                    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

eric ide

mercurial