Commit 79cdb661 authored by Brian Curtin's avatar Brian Curtin

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.
parent 2d93e6ee
......@@ -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
......
......@@ -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:
......
......@@ -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()
......
......@@ -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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment