Fix #10554. Added context manager support to Popen objects.

Added a few common Popen uses to the tests like we've done for a few other
instances of adding context managers. Eventually the entire test suite
could be converted to use the context manager format.
This commit is contained in:
Brian Curtin 2010-12-03 02:46:02 +00:00
parent 2d93e6ee63
commit 79cdb661f5
4 changed files with 65 additions and 1 deletions

View file

@ -208,6 +208,16 @@ This module defines one class called :class:`Popen`:
underlying CreateProcess() function. They can specify things such as appearance
of the main window and priority for the new process. (Windows only)
Popen objects are supported as context managers via the :keyword:`with` statement,
closing any open file descriptors on exit.
::
with Popen(["ifconfig"], stdout=PIPE) as proc:
log.write(proc.stdout.read())
.. versionchanged:: 3.2
Added context manager support.
.. data:: PIPE

View file

@ -697,6 +697,16 @@ class Popen(object):
data = data.replace(b"\r\n", b"\n").replace(b"\r", b"\n")
return data.decode(encoding)
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
if self.stdout:
self.stdout.close()
if self.stderr:
self.stderr.close()
if self.stdin:
self.stdin.close()
def __del__(self, _maxsize=sys.maxsize, _active=_active):
if not self._child_created:

View file

@ -1183,6 +1183,47 @@ class CommandsWithSpaces (BaseTestCase):
# call() function with sequence argument with spaces on Windows
self.with_spaces([sys.executable, self.fname, "ab cd"])
class ContextManagerTests(ProcessTestCase):
def test_pipe(self):
with subprocess.Popen([sys.executable, "-c",
"import sys;"
"sys.stdout.write('stdout');"
"sys.stderr.write('stderr');"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE) as proc:
self.assertEqual(proc.stdout.read(), b"stdout")
self.assertStderrEqual(proc.stderr.read(), b"stderr")
self.assertTrue(proc.stdout.closed)
self.assertTrue(proc.stderr.closed)
def test_returncode(self):
with subprocess.Popen([sys.executable, "-c",
"import sys; sys.exit(100)"]) as proc:
proc.wait()
self.assertEqual(proc.returncode, 100)
def test_communicate_stdin(self):
with subprocess.Popen([sys.executable, "-c",
"import sys;"
"sys.exit(sys.stdin.read() == 'context')"],
stdin=subprocess.PIPE) as proc:
proc.communicate(b"context")
self.assertEqual(proc.returncode, 1)
def test_invalid_args(self):
with self.assertRaises(EnvironmentError) as c:
with subprocess.Popen(['nonexisting_i_hope'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE) as proc:
pass
if c.exception.errno != errno.ENOENT: # ignore "no such file"
raise c.exception
def test_main():
unit_tests = (ProcessTestCase,
POSIXProcessTestCase,
@ -1191,7 +1232,8 @@ def test_main():
CommandTests,
ProcessTestCaseNoPoll,
HelperFunctionTests,
CommandsWithSpaces)
CommandsWithSpaces,
ContextManagerTests)
support.run_unittest(*unit_tests)
support.reap_children()

View file

@ -58,6 +58,8 @@ Core and Builtins
Library
-------
- Issue #10554: Add context manager support to subprocess.Popen objects.
- Issue #8989: email.utils.make_msgid now has a domain parameter that can
override the domain name used in the generated msgid.