Skip to content

Commit 978cd76

Browse files
gpsheadclaude
andcommitted
Factor out _flush_stdin() and _make_input_view() helpers
Extract common stdin preparation logic into shared helper functions used by both _communicate_streams_posix() and Popen._communicate(): - _flush_stdin(stdin): Flush stdin, ignoring BrokenPipeError and ValueError (for closed files) - _make_input_view(input_data): Convert input data to a byte memoryview, handling non-byte memoryviews by casting to "b" view This ensures consistent behavior and makes the fixes for gh-134453 (memoryview) and gh-74389 (closed stdin) shared in one place. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent df8f082 commit 978cd76

File tree

1 file changed

+32
-33
lines changed

1 file changed

+32
-33
lines changed

Lib/subprocess.py

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,32 @@ def _remaining_time_helper(endtime):
328328
return endtime - _time()
329329

330330

331+
def _flush_stdin(stdin):
332+
"""Flush stdin, ignoring BrokenPipeError and closed file ValueError."""
333+
try:
334+
stdin.flush()
335+
except BrokenPipeError:
336+
pass
337+
except ValueError:
338+
# Ignore ValueError: I/O operation on closed file.
339+
if not stdin.closed:
340+
raise
341+
342+
343+
def _make_input_view(input_data):
344+
"""Convert input data to a byte memoryview for writing.
345+
346+
Handles the case where input_data is already a memoryview with
347+
non-byte elements (e.g., int32 array) by casting to a byte view.
348+
This ensures len(view) returns the byte count, not element count.
349+
"""
350+
if not input_data:
351+
return None
352+
if isinstance(input_data, memoryview):
353+
return input_data.cast("b") # ensure byte view for correct len()
354+
return memoryview(input_data)
355+
356+
331357
def _communicate_io_posix(selector, stdin, input_view, input_offset,
332358
output_buffers, endtime):
333359
"""
@@ -536,29 +562,16 @@ def _communicate_streams_posix(stdin, input_data, read_streams,
536562

537563
# Prepare stdin
538564
if stdin:
539-
try:
540-
stdin.flush()
541-
except BrokenPipeError:
542-
pass
543-
except ValueError:
544-
# ignore ValueError: I/O operation on closed file.
545-
if not stdin.closed:
546-
raise
565+
_flush_stdin(stdin)
547566
if not input_data:
548567
try:
549568
stdin.close()
550569
except BrokenPipeError:
551570
pass
552571
stdin = None # Don't register with selector
553572

554-
# Prepare input data - cast to bytes view for correct length tracking
555-
if input_data:
556-
if not isinstance(input_data, memoryview):
557-
input_view = memoryview(input_data)
558-
else:
559-
input_view = input_data.cast("b") # byte view required
560-
else:
561-
input_view = None
573+
# Prepare input data
574+
input_view = _make_input_view(input_data)
562575

563576
with _PopenSelector() as selector:
564577
if stdin and input_data:
@@ -2671,14 +2684,7 @@ def _communicate(self, input, endtime, orig_timeout):
26712684
if self.stdin and not self._communication_started:
26722685
# Flush stdio buffer. This might block, if the user has
26732686
# been writing to .stdin in an uncontrolled fashion.
2674-
try:
2675-
self.stdin.flush()
2676-
except BrokenPipeError:
2677-
pass # communicate() must ignore BrokenPipeError.
2678-
except ValueError:
2679-
# ignore ValueError: I/O operation on closed file.
2680-
if not self.stdin.closed:
2681-
raise
2687+
_flush_stdin(self.stdin)
26822688
if not input:
26832689
try:
26842690
self.stdin.close()
@@ -2703,15 +2709,8 @@ def _communicate(self, input, endtime, orig_timeout):
27032709

27042710
self._save_input(input)
27052711

2706-
if self._input:
2707-
if not isinstance(self._input, memoryview):
2708-
input_view = memoryview(self._input)
2709-
else:
2710-
input_view = self._input.cast("b") # byte input required
2711-
input_offset = self._input_offset
2712-
else:
2713-
input_view = None
2714-
input_offset = 0
2712+
input_view = _make_input_view(self._input)
2713+
input_offset = self._input_offset if self._input else 0
27152714

27162715
with _PopenSelector() as selector:
27172716
if self.stdin and not self.stdin.closed and self._input:

0 commit comments

Comments
 (0)