diff options
author | Brian Curtin <brian.curtin@gmail.com> | 2010-12-03 02:46:02 (GMT) |
---|---|---|
committer | Brian Curtin <brian.curtin@gmail.com> | 2010-12-03 02:46:02 (GMT) |
commit | 79cdb661f5a6cf8bba07aa50f4451f6c409bb067 (patch) | |
tree | 951cc547f5023ab2965b790fe01617e19952d3cf | |
parent | 2d93e6ee637f3ec62114919835a32ed009b99a0b (diff) | |
download | cpython-79cdb661f5a6cf8bba07aa50f4451f6c409bb067.zip cpython-79cdb661f5a6cf8bba07aa50f4451f6c409bb067.tar.gz cpython-79cdb661f5a6cf8bba07aa50f4451f6c409bb067.tar.bz2 |
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.
-rw-r--r-- | Doc/library/subprocess.rst | 10 | ||||
-rw-r--r-- | Lib/subprocess.py | 10 | ||||
-rw-r--r-- | Lib/test/test_subprocess.py | 44 | ||||
-rw-r--r-- | Misc/NEWS | 2 |
4 files changed, 65 insertions, 1 deletions
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 8f9b9ea..e0bb163 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -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 diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 192185d..bdbcc6b 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -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: diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index d1812e5..ec1e186 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -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. |