mirror of
https://github.com/python/cpython.git
synced 2025-12-04 08:34:25 +00:00
Closes #23234: Refactor subprocess
Use new OSError exceptions, factorize stdin.write() code.
This commit is contained in:
parent
f664118817
commit
a5e881d2e8
1 changed files with 24 additions and 34 deletions
|
|
@ -920,6 +920,22 @@ class Popen(object):
|
||||||
self._devnull = os.open(os.devnull, os.O_RDWR)
|
self._devnull = os.open(os.devnull, os.O_RDWR)
|
||||||
return self._devnull
|
return self._devnull
|
||||||
|
|
||||||
|
def _stdin_write(self, input):
|
||||||
|
if input:
|
||||||
|
try:
|
||||||
|
self.stdin.write(input)
|
||||||
|
except BrokenPipeError:
|
||||||
|
# communicate() must ignore broken pipe error
|
||||||
|
pass
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == errno.EINVAL and self.poll() is not None:
|
||||||
|
# Issue #19612: On Windows, stdin.write() fails with EINVAL
|
||||||
|
# if the process already exited before the write
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
self.stdin.close()
|
||||||
|
|
||||||
def communicate(self, input=None, timeout=None):
|
def communicate(self, input=None, timeout=None):
|
||||||
"""Interact with process: Send data to stdin. Read data from
|
"""Interact with process: Send data to stdin. Read data from
|
||||||
stdout and stderr, until end-of-file is reached. Wait for
|
stdout and stderr, until end-of-file is reached. Wait for
|
||||||
|
|
@ -945,13 +961,7 @@ class Popen(object):
|
||||||
stdout = None
|
stdout = None
|
||||||
stderr = None
|
stderr = None
|
||||||
if self.stdin:
|
if self.stdin:
|
||||||
if input:
|
self._stdin_write(input)
|
||||||
try:
|
|
||||||
self.stdin.write(input)
|
|
||||||
except OSError as e:
|
|
||||||
if e.errno != errno.EPIPE and e.errno != errno.EINVAL:
|
|
||||||
raise
|
|
||||||
self.stdin.close()
|
|
||||||
elif self.stdout:
|
elif self.stdout:
|
||||||
stdout = _eintr_retry_call(self.stdout.read)
|
stdout = _eintr_retry_call(self.stdout.read)
|
||||||
self.stdout.close()
|
self.stdout.close()
|
||||||
|
|
@ -1200,21 +1210,7 @@ class Popen(object):
|
||||||
self.stderr_thread.start()
|
self.stderr_thread.start()
|
||||||
|
|
||||||
if self.stdin:
|
if self.stdin:
|
||||||
if input is not None:
|
self._stdin_write(input)
|
||||||
try:
|
|
||||||
self.stdin.write(input)
|
|
||||||
except OSError as e:
|
|
||||||
if e.errno == errno.EPIPE:
|
|
||||||
# communicate() should ignore pipe full error
|
|
||||||
pass
|
|
||||||
elif (e.errno == errno.EINVAL
|
|
||||||
and self.poll() is not None):
|
|
||||||
# Issue #19612: stdin.write() fails with EINVAL
|
|
||||||
# if the process already exited before the write
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
self.stdin.close()
|
|
||||||
|
|
||||||
# Wait for the reader threads, or time out. If we time out, the
|
# Wait for the reader threads, or time out. If we time out, the
|
||||||
# threads remain reading and the fds left open in case the user
|
# threads remain reading and the fds left open in case the user
|
||||||
|
|
@ -1425,9 +1421,8 @@ class Popen(object):
|
||||||
if errpipe_data:
|
if errpipe_data:
|
||||||
try:
|
try:
|
||||||
_eintr_retry_call(os.waitpid, self.pid, 0)
|
_eintr_retry_call(os.waitpid, self.pid, 0)
|
||||||
except OSError as e:
|
except ChildProcessError:
|
||||||
if e.errno != errno.ECHILD:
|
pass
|
||||||
raise
|
|
||||||
try:
|
try:
|
||||||
exception_name, hex_errno, err_msg = (
|
exception_name, hex_errno, err_msg = (
|
||||||
errpipe_data.split(b':', 2))
|
errpipe_data.split(b':', 2))
|
||||||
|
|
@ -1511,9 +1506,7 @@ class Popen(object):
|
||||||
"""All callers to this function MUST hold self._waitpid_lock."""
|
"""All callers to this function MUST hold self._waitpid_lock."""
|
||||||
try:
|
try:
|
||||||
(pid, sts) = _eintr_retry_call(os.waitpid, self.pid, wait_flags)
|
(pid, sts) = _eintr_retry_call(os.waitpid, self.pid, wait_flags)
|
||||||
except OSError as e:
|
except ChildProcessError:
|
||||||
if e.errno != errno.ECHILD:
|
|
||||||
raise
|
|
||||||
# This happens if SIGCLD is set to be ignored or waiting
|
# This happens if SIGCLD is set to be ignored or waiting
|
||||||
# for child processes has otherwise been disabled for our
|
# for child processes has otherwise been disabled for our
|
||||||
# process. This child is dead, we can't get the status.
|
# process. This child is dead, we can't get the status.
|
||||||
|
|
@ -1625,12 +1618,9 @@ class Popen(object):
|
||||||
self._input_offset + _PIPE_BUF]
|
self._input_offset + _PIPE_BUF]
|
||||||
try:
|
try:
|
||||||
self._input_offset += os.write(key.fd, chunk)
|
self._input_offset += os.write(key.fd, chunk)
|
||||||
except OSError as e:
|
except BrokenPipeError:
|
||||||
if e.errno == errno.EPIPE:
|
selector.unregister(key.fileobj)
|
||||||
selector.unregister(key.fileobj)
|
key.fileobj.close()
|
||||||
key.fileobj.close()
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
else:
|
else:
|
||||||
if self._input_offset >= len(self._input):
|
if self._input_offset >= len(self._input):
|
||||||
selector.unregister(key.fileobj)
|
selector.unregister(key.fileobj)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue