/usr/lib/python2.7/dist-packages/testfixtures/popen.py is in python-testfixtures 4.14.3-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141  | # Copyright (c) 2015 Simplistix Ltd
# See license.txt for license details.
from mock import Mock
from subprocess import Popen as Popen
from tempfile import TemporaryFile
from testfixtures.compat import basestring
from testfixtures.utils import extend_docstring
class MockPopen(object):
    """
    A specialised mock for testing use of :class:`subprocess.Popen`.
    An instance of this class can be used in place of the
    :class:`subprocess.Popen` and is often inserted where it's needed using
    :func:`mock.patch` or a :class:`Replacer`.
    """
    default_command = None
    def __init__(self):
        self.commands = {}
        self.mock = mock = Mock()
        self.mock.Popen.side_effect = self.Popen
        mock.Popen_instance = Mock(spec=Popen)
        inst = mock.Popen.return_value = mock.Popen_instance
        inst.communicate.side_effect = self.communicate
        inst.wait.side_effect = self.wait
        inst.send_signal.side_effect = self.send_signal
        inst.terminate.side_effect = self.terminate
        inst.kill.side_effect = self.kill
        inst.poll.side_effect = self.poll
    def set_command(self, command, stdout=b'', stderr=b'', returncode=0,
                    pid=1234, poll_count=3):
        """
        Set the behaviour of this mock when it is used to simulate the
        specified command.
        :param command: A string representing the command to be simulated.
        """
        self.commands[command] = (stdout, stderr, returncode, pid, poll_count)
    def set_default(self, stdout=b'', stderr=b'', returncode=0,
                    pid=1234, poll_count=3):
        """
        Set the behaviour of this mock when it is used to simulate commands
        that have no explicit behavior specified using
        :meth:`~MockPopen.set_command`.
        """
        self.default_command = (stdout, stderr, returncode, pid, poll_count)
    def __call__(self, *args, **kw):
        return self.mock.Popen(*args, **kw)
    def Popen(self, args, bufsize=0, executable=None,
              stdin=None, stdout=None, stderr=None,
              preexec_fn=None, close_fds=False, shell=False, cwd=None,
              env=None, universal_newlines=False,
              startupinfo=None, creationflags=0):
        if isinstance(args, basestring):
            cmd = args
        else:
            cmd = ' '.join(args)
        behaviour = self.commands.get(cmd, self.default_command)
        if behaviour is None:
            raise KeyError('Nothing specified for command %r' % cmd)
        self.stdout, self.stderr, self.returncode, pid, poll = behaviour
        self.poll_count = poll
        for name in 'stdout', 'stderr':
            f = TemporaryFile()
            f.write(getattr(self, name))
            f.flush()
            f.seek(0)
            setattr(self.mock.Popen_instance, name, f)
        self.mock.Popen_instance.pid = pid
        self.mock.Popen_instance.returncode = None
        return self.mock.Popen_instance
    def wait(self):
        "Simulate calls to :meth:`subprocess.Popen.wait`"
        self.mock.Popen_instance.returncode = self.returncode
        return self.returncode
    def communicate(self, input=None):
        "Simulate calls to :meth:`subprocess.Popen.communicate`"
        self.wait()
        return self.stdout, self.stderr
    def poll(self):
        "Simulate calls to :meth:`subprocess.Popen.poll`"
        while self.poll_count and self.mock.Popen_instance.returncode is None:
            self.poll_count -= 1
            return None
        # This call to wait() is NOT how poll() behaves in reality.
        # poll() NEVER sets the returncode.
        # The returncode is *only* ever set by process completion.
        # The following is an artifact of the fixture's implementation.
        return self.wait()
    # These are here to check parameter types
    def send_signal(self, signal):
        "Simulate calls to :meth:`subprocess.Popen.send_signal`"
        pass
    def terminate(self):
        "Simulate calls to :meth:`subprocess.Popen.terminate`"
        pass
    def kill(self):
        "Simulate calls to :meth:`subprocess.Popen.kill`"
        pass
set_command_params = """
:param stdout:
    A string representing the simulated content written by the process
    to the stdout pipe.
:param stderr:
    A string representing the simulated content written by the process
    to the stderr pipe.
:param returncode:
    An integer representing the return code of the simulated process.
:param pid:
    An integer representing the process identifier of the simulated
    process. This is useful if you have code the prints out the pids
    of running processes.
:param poll_count:
    Specifies the number of times :meth:`MockPopen.poll` can be
    called before :attr:`MockPopen.returncode` is set and returned
    by :meth:`MockPopen.poll`.
"""
# add the param docs, so we only have one copy of them!
extend_docstring(set_command_params,
                 [MockPopen.set_command, MockPopen.set_default])
 |