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`: ...@@ -208,6 +208,16 @@ This module defines one class called :class:`Popen`:
underlying CreateProcess() function. They can specify things such as appearance underlying CreateProcess() function. They can specify things such as appearance
of the main window and priority for the new process. (Windows only) 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 .. data:: PIPE
......
...@@ -697,6 +697,16 @@ class Popen(object): ...@@ -697,6 +697,16 @@ class Popen(object):
data = data.replace(b"\r\n", b"\n").replace(b"\r", b"\n") data = data.replace(b"\r\n", b"\n").replace(b"\r", b"\n")
return data.decode(encoding) 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): def __del__(self, _maxsize=sys.maxsize, _active=_active):
if not self._child_created: if not self._child_created:
......
...@@ -1183,6 +1183,47 @@ class CommandsWithSpaces (BaseTestCase): ...@@ -1183,6 +1183,47 @@ class CommandsWithSpaces (BaseTestCase):
# call() function with sequence argument with spaces on Windows # call() function with sequence argument with spaces on Windows
self.with_spaces([sys.executable, self.fname, "ab cd"]) 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(): def test_main():
unit_tests = (ProcessTestCase, unit_tests = (ProcessTestCase,
POSIXProcessTestCase, POSIXProcessTestCase,
...@@ -1191,7 +1232,8 @@ def test_main(): ...@@ -1191,7 +1232,8 @@ def test_main():
CommandTests, CommandTests,
ProcessTestCaseNoPoll, ProcessTestCaseNoPoll,
HelperFunctionTests, HelperFunctionTests,
CommandsWithSpaces) CommandsWithSpaces,
ContextManagerTests)
support.run_unittest(*unit_tests) support.run_unittest(*unit_tests)
support.reap_children() support.reap_children()
......
...@@ -58,6 +58,8 @@ Core and Builtins ...@@ -58,6 +58,8 @@ Core and Builtins
Library Library
------- -------
- Issue #10554: Add context manager support to subprocess.Popen objects.
- Issue #8989: email.utils.make_msgid now has a domain parameter that can - Issue #8989: email.utils.make_msgid now has a domain parameter that can
override the domain name used in the generated msgid. 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