mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
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:
parent
2d93e6ee63
commit
79cdb661f5
4 changed files with 65 additions and 1 deletions
|
@ -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.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue