⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 process.py

📁 Wxpython Implemented on Windows CE, Source code
💻 PY
📖 第 1 页 / 共 5 页
字号:
        #           "C:\foo\"bar" arg1 arg2
        idx = cmd.replace('\\"', 'XX').find('"', 1)
        if idx == -1:
            raise ProcessError("Malformed command: %r" % cmd)
        first, rest = cmd[1:idx], cmd[idx+1:]
        rest = rest.lstrip()
    else:
        if ' ' in cmd:
            first, rest = cmd.split(' ', 1)
        else:
            first, rest = cmd, ""

    # Ensure the first arg is a valid path to the appropriate file.
    import which
    if os.sep in first:
        altpath = [os.path.dirname(first)]
        firstbase = os.path.basename(first)
        candidates = list(which.which(firstbase, path=altpath))
    elif env:
        altpath = _getPathFromEnv(env)
        if altpath:
            candidates = list(which.which(first, altpath.split(os.pathsep)))
        else:
            candidates = list(which.which(first))
    else:
        candidates = list(which.which(first))
    if candidates:
        return _joinArgv( [candidates[0]] ) + ' ' + rest
    else:
        raise ProcessError("Could not find an appropriate leading command "\
                           "for: %r" % cmd)


if sys.platform.startswith("win"):
    def _SaferCreateProcess(appName,        # app name
                            cmd,            # command line 
                            processSA,      # process security attributes 
                            threadSA,       # thread security attributes 
                            inheritHandles, # are handles are inherited
                            creationFlags,  # creation flags 
                            env,            # environment
                            cwd,            # current working directory
                            si):            # STARTUPINFO pointer
        """If CreateProcess fails from environment type inconsistency then
        fix that and try again.
        
        win32process.CreateProcess requires that all environment keys and
        values either be all ASCII or all unicode. Try to remove this burden
        from the user of process.py.
        """
        isWin9x = win32api.GetVersionEx()[3] == VER_PLATFORM_WIN32_WINDOWS
        # On Win9x all keys and values of 'env' must be ASCII (XXX
        # Actually this is probably only true if the Unicode support
        # libraries, which are not installed by default, are not
        # installed). On other Windows flavours all keys and values of
        # 'env' must all be ASCII *or* all Unicode. We will try to
        # automatically convert to the appropriate type, issuing a
        # warning if such an automatic conversion is necessary.

        #XXX Komodo 2.0 Beta 1 hack. This requirement should be
        #    pushed out to Komodo code using process.py. Or should it?
        if isWin9x and env:
            aenv = {}
            for key, value in env.items():
                aenv[str(key)] = str(value)
            env = aenv
        
        log.debug("""\
_SaferCreateProcess(appName=%r,
                    cmd=%r,
                    env=%r,
                    cwd=%r)
    os.getcwd(): %r
""", appName, cmd, env, cwd, os.getcwd())
        try:
            hProcess, hThread, processId, threadId\
                = win32process.CreateProcess(appName, cmd, processSA,
                                             threadSA, inheritHandles,
                                             creationFlags, env, cwd, si)
        except TypeError, ex:
            if ex.args == ('All dictionary items must be strings, or all must be unicode',):
                # Try again with an all unicode environment.
                #XXX Would be nice if didn't have to depend on the error
                #    string to catch this.
                #XXX Removing this warning for 2.3 release. See bug
                #    23215. The right fix is to correct the PHPAppInfo
                #    stuff to heed the warning.
                #import warnings
                #warnings.warn('env: ' + str(ex), stacklevel=4)
                if isWin9x and env:
                    aenv = {}
                    try:
                        for key, value in env.items():
                            aenv[str(key)] = str(value)
                    except UnicodeError, ex:
                        raise ProcessError(str(ex))
                    env = aenv
                elif env:
                    uenv = {}
                    for key, val in env.items():
                        try:
                            uenv[unicode(key)] = unicode(val)   # default encoding
                        except UnicodeError:
                            try:
                                uenv[unicode(key, 'iso-8859-1')] = unicode(val, 'iso-8859-1')   # backup encoding
                            except UnicodeError:
                                log.warn('Skipping environment variable "%s" in execution process: unable to convert to unicode using either the default encoding or ISO-8859-1' % (key))
                    env = uenv
                hProcess, hThread, processId, threadId\
                    = win32process.CreateProcess(appName, cmd, processSA,
                                                 threadSA, inheritHandles,
                                                 creationFlags, env, cwd,
                                                 si)
            else:
                raise
        return hProcess, hThread, processId, threadId


# Maintain references to all spawned ProcessProxy objects to avoid hangs.
#   Otherwise, if the user lets the a ProcessProxy object go out of
#   scope before the process has terminated, it is possible to get a
#   hang (at least it *used* to be so when we had the
#   win32api.CloseHandle(<stdin handle>) call in the __del__() method).
#   XXX Is this hang possible on Linux as well?
# A reference is removed from this list when the process's .wait or
# .kill method is called.
# XXX Should an atexit() handler be registered to kill all curently
#     running processes? Else *could* get hangs, n'est ce pas?
def _registerProcess(process):
    global _processes
    log.info("_registerprocess(process=%r)", process)

    # Clean up zombie processes.
    #   If the user does not call .wait() or .kill() on processes then
    #   the ProcessProxy object will not get cleaned up until Python
    #   exits and _processes goes out of scope. Under heavy usage that
    #   is a big memory waste. Cleaning up here alleviates that.
    for p in _processes[:]: # use copy of _process, because we may modifiy it
        try:
            # poll to see if is process still running
            if sys.platform.startswith("win"):
                timeout = 0
            else:
                timeout = os.WNOHANG
            p.wait(timeout)
            _unregisterProcess(p)
        except ProcessError, ex:
            if ex.errno == ProcessProxy.WAIT_TIMEOUT:
                pass
            else:
                raise
        
    _processes.append(process)

def _unregisterProcess(process):
    global _processes
    log.info("_unregisterProcess(process=%r)", process)
    try:
        _processes.remove(process)
        del process
    except ValueError:
        pass


def _fixupCommand(cmd, env=None):
    """Fixup the command string so it is launchable via CreateProcess.

    One cannot just launch, say "python", via CreateProcess. A full path
    to an executable is required. In general there are two choices:
        1. Launch the command string via the shell. The shell will find
           the fullpath to the appropriate executable. This shell will
           also be able to execute special shell commands, like "dir",
           which don't map to an actual executable.
        2. Find the fullpath to the appropriate executable manually and
           launch that exe.

    Option (1) is preferred because you don't have to worry about not
    exactly duplicating shell behaviour and you get the added bonus of
    being able to launch "dir" and friends.

    However, (1) is not always an option. Doing so when the shell is
    command.com (as on all Win9x boxes) or when using WinNT's cmd.exe,
    problems are created with .kill() because these shells seem to eat
    up Ctrl-C's and Ctrl-Break's sent via
    win32api.GenerateConsoleCtrlEvent().  Strangely this only happens
    when spawn via this Python interface. For example, Ctrl-C get
    through to hang.exe here:
      C:\> ...\w9xpopen.exe "C:\WINDOWS\COMMAND.COM /c hang.exe"
      ^C
    but not here:
      >>> p = ProcessOpen('hang.exe')
      # This results in the same command to CreateProcess as
      # above.
      >>> p.kill()

    Hence, for these platforms we fallback to option (2).  Cons:
      - cannot spawn shell commands like 'dir' directly
      - cannot spawn batch files
    """
    if sys.platform.startswith("win"):
        # Fixup the command string to spawn.  (Lifted from
        # posixmodule.c::_PyPopenCreateProcess() with some modifications)
        comspec = os.environ.get("COMSPEC", None)
        win32Version = win32api.GetVersion()
        if comspec is None:
            raise ProcessError("Cannot locate a COMSPEC environment "\
                               "variable to use as the shell")
        # Explicitly check if we are using COMMAND.COM.  If we
        # are then use the w9xpopen hack.
        elif (win32Version & 0x80000000L == 0) and\
             (win32Version &        0x5L >= 5) and\
             os.path.basename(comspec).lower() != "command.com":
            # 2000/XP and not using command.com.
            if '"' in cmd or "'" in cmd:
                cmd = comspec + ' /c "%s"' % cmd
            else:
                cmd = comspec + ' /c ' + cmd
        elif (win32Version & 0x80000000L == 0) and\
             (win32Version &        0x5L  < 5) and\
             os.path.basename(comspec).lower() != "command.com":
            # NT and not using command.com.
            try:
                cmd = _whichFirstArg(cmd, env)
            except ProcessError:
                raise ProcessError("Could not find a suitable executable "\
                    "to launch for '%s'. On WinNT you must manually prefix "\
                    "shell commands and batch files with 'cmd.exe /c' to "\
                    "have the shell run them." % cmd)
        else:
            # Oh gag, we're on Win9x and/or using COMMAND.COM. Use the
            # workaround listed in KB: Q150956
            w9xpopen = os.path.join(
                os.path.dirname(win32api.GetModuleFileName(0)),
                'w9xpopen.exe')
            if not os.path.exists(w9xpopen):
                # Eeek - file-not-found - possibly an embedding
                # situation - see if we can locate it in sys.exec_prefix
                w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix),
                                        'w9xpopen.exe')
                if not os.path.exists(w9xpopen):
                    raise ProcessError(\
                        "Can not locate 'w9xpopen.exe' which is needed "\
                        "for ProcessOpen to work with your shell or "\
                        "platform.")
            ## This would be option (1):
            #cmd = '%s "%s /c %s"'\
            #      % (w9xpopen, comspec, cmd.replace('"', '\\"'))
            try:
                cmd = _whichFirstArg(cmd, env)
            except ProcessError:
                raise ProcessError("Could not find a suitable executable "\
                    "to launch for '%s'. On Win9x you must manually prefix "\
                    "shell commands and batch files with 'command.com /c' "\
                    "to have the shell run them." % cmd)
            cmd = '%s "%s"' % (w9xpopen, cmd.replace('"', '\\"'))
    return cmd

class _FileWrapper:
    """Wrap a system file object, hiding some nitpicky details.
    
    This class provides a Python file-like interface to either a Python
    file object (pretty easy job), a file descriptor, or an OS-specific
    file handle (e.g.  Win32 handles to file objects on Windows). Any or
    all of these object types may be passed to this wrapper. If more
    than one is specified this wrapper prefers to work with certain one
    in this order:
        - file descriptor (because usually this allows for
          return-immediately-on-read-if-anything-available semantics and
          also provides text mode translation on Windows)
        - OS-specific handle (allows for the above read semantics)
        - file object (buffering can cause difficulty for interacting
          with spawned programs)

    It also provides a place where related such objects can be kept
    alive together to prevent premature ref-counted collection. (E.g. on
    Windows a Python file object may be associated with a Win32 file
    handle. If the file handle is not kept alive the Python file object
    will cease to function.)
    """
    def __init__(self, file=None, descriptor=None, handle=None):
        self._file = file
        self._descriptor = descriptor
        self._handle = handle
        self._closed = 0
        if self._descriptor is not None or self._handle is not None:
            self._lineBuf = "" # to support .readline()

    def __del__(self):
        self.close()

    def __getattr__(self, name):
        """Forward to the underlying file object."""
        if self._file is not None:
            return getattr(self._file, name)
        else:
            raise ProcessError("no file object to pass '%s' attribute to"
                               % name)

    def _win32Read(self, nBytes):
        try:
            log.info("[%s] _FileWrapper.read: waiting for read on pipe",
                     id(self))
            errCode, text = win32file.ReadFile(self._handle, nBytes)
        except pywintypes.error, ex:
            # Ignore errors for now, like "The pipe is being closed.",
            # etc. XXX There *may* be errors we don't want to avoid.
            log.info("[%s] _FileWrapper.read: error reading from pipe: %s",
                     id(self), ex)
            return ""

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -