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

📄 process.py

📁 Wxpython Implemented on Windows CE, Source code
💻 PY
📖 第 1 页 / 共 5 页
字号:
#!/usr/bin/env python
# Copyright (c) 2002-2003 ActiveState
# See LICENSE.txt for license details.
""" Contents of LICENSE.txt:
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
 
r"""
    Python interface for process control.

    This module defines three Process classes for spawning,
    communicating and control processes. They are: Process, ProcessOpen,
    ProcessProxy. All of the classes allow one to specify the command (cmd),
    starting working directory (cwd), and environment to create for the
    new process (env) and to "wait" for termination of the child and
    "kill" the child.

    Process:
        Use this class to simply launch a process (either a GUI app or a
        console app in a new console) with which you do not intend to
        communicate via it std handles.

    ProcessOpen:
        Think of this as a super version of Python's os.popen3() method.
        This spawns the given command and sets up pipes for
        stdin/stdout/stderr which can then be used to communicate with
        the child.

    ProcessProxy:
        This is a heavy-weight class that, similar to ProcessOpen,
        spawns the given commands and sets up pipes to the child's
        stdin/stdout/stderr. However, it also starts three threads to
        proxy communication between each of the child's and parent's std
        handles. At the parent end of this communication are, by
        default, IOBuffer objects. You may specify your own objects here
        (usually sub-classing from IOBuffer, which handles some
        synchronization issues for you). The result is that it is
        possible to have your own IOBuffer instance that gets, say, a
        .write() "event" for every write that the child does on its
        stdout.

        Understanding ProcessProxy is pretty complex. Some examples
        below attempt to help show some uses. Here is a diagram of the
        comminucation:

                            <parent process>
               ,---->->->------'   ^   `------>->->----,
               |                   |                   v
           IOBuffer             IOBuffer            IOBuffer        
           (p.stdout)           (p.stderr)          (p.stdin)
               |                   |                   |
           _OutFileProxy        _OutFileProxy       _InFileProxy
           thread               thread              thread
               |                   ^                   |
               `----<-<-<------,   |   ,------<-<-<----'
                            <child process>

    Usage:
        import process
        p = process.<Process class>(cmd='echo hi', ...)
        #... use the various methods and attributes

    Examples:
      A simple 'hello world':
        >>> import process
        >>> p = process.ProcessOpen(['echo', 'hello'])
        >>> p.stdout.read()
        'hello\r\n'
        >>> p.wait()   # .wait() returns the child's exit status
        0

      Redirecting the stdout handler:
        >>> import sys
        >>> p = process.ProcessProxy(['echo', 'hello'], stdout=sys.stdout)
        hello

      Using stdin (need to use ProcessProxy here because it defaults to
      text-mode translation on Windows, ProcessOpen does not support
      this):
        >>> p = process.ProcessProxy(['sort'])
        >>> p.stdin.write('5\n')
        >>> p.stdin.write('2\n')
        >>> p.stdin.write('7\n')
        >>> p.stdin.close()
        >>> p.stdout.read()
        '2\n5\n7\n'

      Specifying environment variables:
        >>> p = process.ProcessOpen(['perl', '-e', 'print $ENV{FOO}'])
        >>> p.stdout.read()
        ''
        >>> p = process.ProcessOpen(['perl', '-e', 'print $ENV{FOO}'],
        ...                         env={'FOO':'bar'})
        >>> p.stdout.read()
        'bar'

      Killing a long running process (On Linux, to poll you must use
      p.wait(os.WNOHANG)):
        >>> p = ProcessOpen(['perl', '-e', 'while (1) {}'])
        >>> try:
        ...     p.wait(os.WNOHANG)  # poll to see if is process still running
        ... except ProcessError, ex:
        ...     if ex.errno == ProcessProxy.WAIT_TIMEOUT:
        ...             print "process is still running"
        ...
        process is still running
        >>> p.kill(42)
        >>> p.wait()
        42

      Providing objects for stdin/stdout/stderr:
        XXX write this, mention IOBuffer subclassing.
"""
#TODO:
#   - Discuss the decision to NOT have the stdout/stderr _OutFileProxy's
#     wait for process termination before closing stdin. It will just
#     close stdin when stdout is seen to have been closed. That is
#     considered Good Enough (tm). Theoretically it would be nice to
#     only abort the stdin proxying when the process terminates, but
#     watching for process termination in any of the parent's thread
#     adds the undesired condition that the parent cannot exit with the
#     child still running. That sucks.
#     XXX Note that I don't even know if the current stdout proxy even
#         closes the stdin proxy at all.
#   - DavidA: if I specify "unbuffered" for my stdin handler (in the
#     ProcessProxy constructor) then the stdin IOBuffer should do a
#     fparent.read() rather than a fparent.readline(). TrentM: can I do
#     that? What happens?
#

import os
import sys
import threading
import types
import pprint 
if sys.platform.startswith("win"):
    import msvcrt
    import win32api
    import win32file
    import win32pipe
    import pywintypes
    import win32process
    import win32event
    # constants pulled from win32con to save memory
    VER_PLATFORM_WIN32_WINDOWS = 1
    CTRL_BREAK_EVENT = 1
    SW_SHOWDEFAULT = 10
    WM_CLOSE = 0x10
    DUPLICATE_SAME_ACCESS = 2
    
else:
    import signal


#---- exceptions

class ProcessError(Exception):
    def __init__(self, msg, errno=-1):
        Exception.__init__(self, msg)
        self.errno = errno


#---- internal logging facility

class Logger:
    DEBUG, INFO, WARN, ERROR, FATAL = range(5)
    def __init__(self, name, level=None, streamOrFileName=sys.stderr):
        self.name = name
        if level is None:
            self.level = self.WARN
        else:
            self.level = level
        if type(streamOrFileName) == types.StringType:
            self.stream = open(streamOrFileName, 'w')
            self._opennedStream = 1
        else:
            self.stream = streamOrFileName
            self._opennedStream = 0
    def __del__(self):
        if self._opennedStream:
            self.stream.close()
    def _getLevelName(self, level):
        levelNameMap = {
            self.DEBUG: "DEBUG",
            self.INFO: "INFO",
            self.WARN: "WARN",
            self.ERROR: "ERROR",
            self.FATAL: "FATAL",
        }
        return levelNameMap[level]
    def log(self, level, msg, *args):
        if level < self.level:
            return
        message = "%s: %s:" % (self.name, self._getLevelName(level).lower())
        message = message + (msg % args) + "\n"
        self.stream.write(message)
        self.stream.flush()
    def debug(self, msg, *args):
        self.log(self.DEBUG, msg, *args)
    def info(self, msg, *args):
        self.log(self.INFO, msg, *args)
    def warn(self, msg, *args):
        self.log(self.WARN, msg, *args)
    def error(self, msg, *args):
        self.log(self.ERROR, msg, *args)
    def fatal(self, msg, *args):
        self.log(self.FATAL, msg, *args)

# Loggers:
#   - 'log' to log normal process handling
#   - 'logres' to track system resource life
#   - 'logfix' to track wait/kill proxying in _ThreadFixer
if 1:   # normal/production usage
    log = Logger("process", Logger.WARN)
else:   # development/debugging usage
    log = Logger("process", Logger.DEBUG, sys.stdout)
if 1:   # normal/production usage
    logres = Logger("process.res", Logger.WARN)
else:   # development/debugging usage
    logres = Logger("process.res", Logger.DEBUG, sys.stdout)
if 1:   # normal/production usage
    logfix = Logger("process.waitfix", Logger.WARN)
else:   # development/debugging usage
    logfix = Logger("process.waitfix", Logger.DEBUG, sys.stdout)



#---- globals

_version_ = (0, 5, 0)

# List of registered processes (see _(un)registerProcess).
_processes = []



#---- internal support routines

def _escapeArg(arg):
    """Escape the given command line argument for the shell."""
    #XXX There is a probably more that we should escape here.
    return arg.replace('"', r'\"')


def _joinArgv(argv):
    r"""Join an arglist to a string appropriate for running.

        >>> import os
        >>> _joinArgv(['foo', 'bar "baz'])
        'foo "bar \\"baz"'
    """
    cmdstr = ""
    for arg in argv:
        if ' ' in arg or ';' in arg:
            cmdstr += '"%s"' % _escapeArg(arg)
        else:
            cmdstr += _escapeArg(arg)
        cmdstr += ' '
    if cmdstr.endswith(' '): cmdstr = cmdstr[:-1]  # strip trailing space
    return cmdstr


def _getPathFromEnv(env):
    """Return the PATH environment variable or None.

    Do the right thing for case sensitivity per platform.
    XXX Icky. This guarantee of proper case sensitivity of environment
        variables should be done more fundamentally in this module.
    """
    if sys.platform.startswith("win"):
        for key in env.keys():
            if key.upper() == "PATH":
                return env[key]
        else:
            return None
    else:
        if env.has_key("PATH"):
            return env["PATH"]
        else:
            return None


def _whichFirstArg(cmd, env=None):
    """Return the given command ensuring that the first arg (the command to
    launch) is a full path to an existing file.

    Raise a ProcessError if no such executable could be found.
    """
    # Parse out the first arg.
    if cmd.startswith('"'):
        # The .replace() is to ensure it does not mistakenly find the
        # second '"' in, say (escaped quote):

⌨️ 快捷键说明

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