Simple process IO capture (Was: "shell-commands" and python!) - process.py (0/1)

Neil Schemenauer nas at python.ca
Mon Sep 24 16:42:22 EDT 2001


Here's my humble attempt at a popen replacement.  Note that it doesn't
use the shell (a feature IMHO) and it only works on Unix systems.
Suggestions for the module name are welcome.  I would like to get
something like this in the standard library.

  Neil


###########################################################################
# child_process.py
###########################################################################
import os

# created 2001/09/04, nas

class _ChildProcess:
    """
    Instance attributes:
    
        pid : int
          the process id of the child process
        stdin : file
          open file connected to file descriptor 0 of the child process
        stdout : file
          open file connected to file descriptor 1 of the child process
        stderr : file
          open file connected to file descriptor 2 of the child process
    """

    MAXFD = 256

    def __init__(self, argv, bufsize=-1):
        child_stdin, stdin = os.pipe()
        stdout, child_stdout = os.pipe()
        stderr, child_stderr = os.pipe()
        self.stdin = os.fdopen(stdin, 'w', bufsize)
        self.stdout = os.fdopen(stdout, 'r', bufsize)
        self.stderr = os.fdopen(stderr, 'r', bufsize)
        self.pid = os.fork()
        if self.pid == 0:
            os.dup2(child_stdin, 0)
            os.dup2(child_stdout, 1)
            os.dup2(child_stderr, 2)
            for i in range(3, self.MAXFD):
                try:
                    os.close(i)
                except:
                    pass
            try:
                os.execvp(argv[0], argv)
            finally:
                os._exit(1)
        os.close(child_stdin)
        os.close(child_stdout)
        os.close(child_stderr)

    def read(self, n=-1):
        """Read from child stdout"""
        return self.stdout.read(n)

    def readline(self):
        """Readline from child stdout"""
        return self.stdout.readline()

    def readlines(self):
        """Readlines from child stdout"""
        return self.stdout.readlines()

    def write(self, s):
        """Write data to child stdin"""
        self.stdin.write(s)

    def flush(self):
        """Flush stdin pipe to child"""
        self.stdin.flush()

    def close(self):
        """Close stdin, stdout and stderr pipes to child process.  Wait
        for the exit status of the child and return it."""
        for fd in (self.stdin, self.stdout, self.stderr):
            if not fd.closed:
                fd.close()
        status = self.wait()
        if status == 0:
            return None # matches behavior of popen(...).close()
        else:
            return status

    def wait(self, flags=0):
        pid, status = os.waitpid(self.pid, flags)
        return status


def execute(argv, bufsize=-1):
    r"""execute(argv : (string*), bufsize=-1) -> _ChildProcess
    
    Create a child process with pipes connected to its stdout, stdin and
    stderr file descriptors.  The child is created using fork() and
    execvp() in order to avoid the argument quoting problems presented by
    using system() or popen().  The bufsize argument has the same meaning as
    for the open() builtin and applies to stdin, stdout, and stderr.

    Examples:

        >>> p = execute(("ls", "/"))
        >>> p.readline()
        'bin\n'
        >>> p.readline()
        'boot\n'
        >>> p.close()
        >>>

        >>> p = execute(("cat",))
        >>> p.write("hello world\n")
        >>> p.stdin.close()
        >>> p.read()
        'hello world\n'
        >>> p.close()
        >>>

    """
    return _ChildProcess(argv, bufsize)




More information about the Python-list mailing list