Commit graph

396 commits

Author SHA1 Message Date
Gregory P. Smith using claude.ai/code
15f8a93bcb
Support universal_newlines and use _translate_newlines in run_pipeline
- Factor out _translate_newlines() as a module-level function, have
  Popen's method delegate to it for code sharing
- Remove rejection of universal_newlines kwarg in run_pipeline(), treat
  it the same as text=True (consistent with Popen behavior)
- Use _translate_newlines() for text mode decoding in run_pipeline()
  to properly handle \r\n and \r newline sequences
- Update documentation to remove mention of universal_newlines rejection
- Update test to verify universal_newlines=True works like text=True

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-29 09:27:29 +00:00
Gregory P. Smith using claude.ai/code
978cd76cd8
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>
2025-11-29 08:56:34 +00:00
Gregory P. Smith using claude.ai/code
df8f082f59
Fix memoryview and closed stdin handling in _communicate_streams_posix
Apply the same fixes from Popen._communicate() to _communicate_streams_posix
for run_pipeline():

1. Handle non-byte memoryview input by casting to byte view (gh-134453):
   Non-byte memoryviews (e.g., int32 arrays) had incorrect length tracking
   because len() returns element count, not byte count. Now cast to "b"
   view for correct progress tracking.

2. Handle ValueError on stdin.flush() when stdin is closed (gh-74389):
   Ignore ValueError from flush() if stdin is already closed, matching
   the BrokenPipeError handling.

Add tests for memoryview input to run_pipeline:
- test_pipeline_memoryview_input: basic byte memoryview
- test_pipeline_memoryview_input_nonbyte: int32 array memoryview

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-11-29 08:46:22 +00:00
Gregory P. Smith using claude.ai/code
d420f29e2b
Fix _communicate_streams_windows to avoid blocking with large input
Move stdin writing to a background thread in _communicate_streams_windows
to avoid blocking indefinitely when writing large input to a pipeline
where the subprocess doesn't consume stdin quickly.

This mirrors the fix made to Popen._communicate() for Windows in
commit 5b1862b (gh-87512).

Add test_pipeline_timeout_large_input to verify that TimeoutExpired
is raised promptly when run_pipeline() is called with large input
and a timeout, even when the first process is slow to consume stdin.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-11-29 08:41:25 +00:00
Gregory P. Smith using claude.ai/code
9f53a8e883
Refactor POSIX communicate I/O into shared _communicate_io_posix()
Extract the core selector-based I/O loop into a new _communicate_io_posix()
function that is shared by both _communicate_streams_posix() (used by
run_pipeline) and Popen._communicate() (used by Popen.communicate).

The new function:
- Takes a pre-configured selector and output buffers
- Supports resume via input_offset parameter (for Popen timeout retry)
- Returns (new_offset, completed) instead of raising TimeoutExpired
- Does not close streams (caller decides based on use case)

This reduces code duplication and ensures both APIs use the same
well-tested I/O multiplexing logic.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-11-29 08:12:12 +00:00
Gregory P. Smith using claude.ai/code
3c28ed6e93
Remove obsolete XXX comment about non-blocking I/O
The comment suggested rewriting Popen._communicate() to use
non-blocking I/O on file objects now that Python 3's io module
is used instead of C stdio.

This is unnecessary - the current approach using select() to
detect ready fds followed by os.read()/os.write() is correct
and efficient. The selector already solves "when is data ready?"
so non-blocking mode would add complexity with no benefit.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-11-29 08:04:35 +00:00
Gregory P. Smith using claude.ai/code
e22d1da9bc
Simplify _communicate_streams() to only accept file objects
Remove support for raw file descriptors in _communicate_streams(),
requiring all streams to be file objects. This simplifies both the
Windows and POSIX implementations by removing isinstance() checks
and fd-wrapping logic.

The run_pipeline() function now wraps the stderr pipe's read end
with os.fdopen() immediately after creation.

This change makes _communicate_streams() more compatible with
Popen.communicate() which already uses file objects, enabling
potential future refactoring to share the multiplexed I/O logic.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-11-29 08:04:34 +00:00
Gregory P. Smith using claude.ai/code
2a11d4bf53
Refactor run_pipeline() to use multiplexed I/O
Add _communicate_streams() helper function that properly multiplexes
read/write operations to prevent pipe buffer deadlocks. The helper
uses selectors on POSIX and threads on Windows, similar to
Popen.communicate().

This fixes potential deadlocks when large amounts of data flow through
the pipeline and significantly improves performance.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-11-29 08:04:34 +00:00
Gregory P. Smith using claude.ai/code
e3a2fbe6da
Add subprocess.run_pipeline() for command pipe chaining
Add a new run_pipeline() function to the subprocess module that enables
running multiple commands connected via pipes, similar to shell pipelines.

New API:
- run_pipeline(*commands, ...) - Run a pipeline of commands
- PipelineResult - Return type with commands, returncodes, stdout, stderr
- PipelineError - Raised when check=True and any command fails

Features:
- Supports arbitrary number of commands (minimum 2)
- capture_output, input, timeout, and check parameters like run()
- stdin= connects to first process, stdout= connects to last process
- Text mode support via text=True, encoding, errors
- All processes share a single stderr pipe for simplicity
- "pipefail" semantics: check=True fails if any command fails

Unlike run(), this function does not accept universal_newlines.
Use text=True instead.

Example:
    result = subprocess.run_pipeline(
        ['cat', 'file.txt'],
        ['grep', 'pattern'],
        ['wc', '-l'],
        capture_output=True, text=True
    )

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-11-29 08:04:33 +00:00
Gregory P. Smith
5b1862bdd8
gh-87512: Fix subprocess using timeout= on Windows blocking with a large input= (GH-142058)
On Windows, Popen._communicate() previously wrote to stdin synchronously, which could block indefinitely if the subprocess didn't consume input= quickly and the pipe buffer filled up. The timeout= parameter was only checked when joining the reader threads, not during the stdin write.

This change moves the Windows stdin writing to a background thread (similar to how stdout/stderr are read in threads), allowing the timeout to be properly enforced. If timeout expires, TimeoutExpired is raised promptly and the writer thread continues in the background. Subsequent calls to communicate() will join the existing writer thread.

Adds test_communicate_timeout_large_input to verify that TimeoutExpired is raised promptly when communicate() is called with large input and a timeout, even when the subprocess doesn't consume stdin quickly.

This test already passed on POSIX (where select() is used) but failed on Windows where the stdin write blocks without checking the timeout.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-11-28 22:07:03 -08:00
Gregory P. Smith
923056b2d4
gh-74389: gh-70560: subprocess.Popen.communicate() now ignores stdin.flush error when closed (GH-142061)
gh-70560: gh-74389: subprocess.Popen.communicate() now ignores stdin.flush error when closed

with a unittest and news entry.
2025-11-29 05:03:06 +00:00
Gregory P. Smith
cc6bc4c97f
GH-134453: Fix subprocess memoryview input handling on POSIX (GH-134949)
Fix inconsistent subprocess.Popen.communicate() behavior between Windows
and POSIX when using memoryview objects with non-byte elements as input.

On POSIX systems, the code was incorrectly comparing bytes written against
element count instead of byte count, causing data truncation for large
inputs with non-byte element types.

Changes:
- Cast memoryview inputs to byte view when input is already a memoryview
- Fix progress tracking to use len(input_view) instead of len(self._input)
- Add comprehensive test coverage for memoryview inputs

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* old-man-yells-at-ReST
* Update 2025-05-30-18-37-44.gh-issue-134453.kxkA-o.rst
* assertIsNone review feedback
* fix memoryview_nonbytes test to fail without our fix on main, and have a nicer error.

Thanks to Peter Bierma @ZeroIntensity for the code review.
2025-11-29 04:25:06 +00:00
Artur Jamro
526d7a8bb4
gh-141473: Fix subprocess.Popen.communicate to send input to stdin upon a subsequent post-timeout call (GH-141477)
* gh-141473: Fix subprocess.Popen.communicate to send input to stdin
* Docs: Clarify that `input` is one time only on `communicate()`
* NEWS entry
* Add a regression test.

---------

Co-authored-by: Gregory P. Smith <greg@krypto.org>
2025-11-28 18:04:52 -08:00
Adam Turner
c89a66feb1
GH-133711: Enable UTF-8 mode by default (PEP 686) (#133712)
Co-authored-by: Victor Stinner <vstinner@python.org>
2025-07-15 10:45:41 +01:00
Nadeshiko Manju
2bbcaedb75
gh-133089: Use original timeout value for TimeoutExpired when the func subprocess.run is called with a timeout (GH-133103)
Signed-off-by: Manjusaka <me@manjusaka.me>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
2025-05-05 01:15:31 +00:00
Vincent Fazio
4c5dcc6d82
gh-129204: Add _PYTHON_SUBPROCESS_USE_POSIX_SPAWN environment knob (GH-132184)
* Add _PYTHON_SUBPROCESS_USE_POSIX_SPAWN environment knob

Add support for disabling the use of `posix_spawn` via a variable in
the process environment.

While it was previously possible to toggle this by modifying the value
of `subprocess._USE_POSIX_SPAWN`, this required either patching CPython
or modifying it within the interpreter instance which is not always
possible, such as when running applications or scripts not under a
user's control.

Signed-off-by: Vincent Fazio <vfazio@gmail.com>

* fixup NEWS entry

---------

Signed-off-by: Vincent Fazio <vfazio@gmail.com>
2025-04-06 20:53:02 -07:00
Gregory P. Smith
ae30646089
gh-118761: Revert "Improve import time of subprocess (GH-129427)" (#130201)
* Revert "gh-118761: Improve import time of `subprocess` (GH-129427)"

This reverts commit 49f24650e4.
Also known as f502c8f6a6 in 3.13 (PR #129447)
Also known as f65aa0d1bf in 3.12 (PR #129448)

This caused bugs in the `__del__` finalizer:
 https://github.com/python/cpython/issues/118761#issuecomment-2661504264

---------

Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
2025-02-16 18:40:08 +00:00
Irit Katriel
56495f81fc
gh-130080: return in finally in subprocess.py (#130081) 2025-02-16 13:52:04 +00:00
Taneli Hukkinen
49f24650e4
gh-118761: Improve import time of subprocess (GH-129427)
* subprocess: lazy import signal and locale to improve module import time
2025-01-29 08:31:13 -08:00
n-l-i
dafe7a4463
gh-128342: Specify timeout unit in subprocess docstrings (GH-128343)
Specify timeout unit (seconds) in subprocess docstrings

Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
2024-12-30 20:52:04 +00:00
Cody Maloney
a9344cdffa
gh-121381 Remove subprocess._USE_VFORK escape hatch (#121383)
This flag was added as an escape hatch in gh-91401 and backported to
Python 3.10. The flag broke at some point between its addition and now.
As there is currently no publicly known environments that require this,
remove it rather than work on fixing it.

This leaves the flag in the subprocess module to not break code which
may have used / checked the flag itself.

discussion: https://discuss.python.org/t/subprocess-use-vfork-escape-hatch-broken-fix-or-remove/56915/2
2024-07-30 18:39:54 -07:00
Victor Stinner
05df063ad8
gh-120417: Fix "imported but unused" linter warnings (#120461)
Add __all__ to the following modules:
importlib.machinery, importlib.util and xml.sax.

Add also "# noqa: F401" in collections.abc,
subprocess and xml.sax.

* Sort __all__; remove collections.abc.__all__; remove private names

* Add tests
2024-06-14 20:39:50 +02:00
Savannah Ostrowski
5b941e57c7
GH-118844: Fix build failures when combining --disable-gil with --enable-experimental-jit (GH-118935) 2024-05-11 16:19:31 -07:00
Henrik Tunedal
133c1a7cdb
gh-118293: Suppress mouse cursor feedback when launching Windows processes with multiprocessing (GH-118315) 2024-04-28 21:10:44 +00:00
Paulo Neves
4abca7e1e7
gh-98966: Handle stdout=subprocess.STDOUT (GH-98967)
Explicitly handle the case where stdout=STDOUT
as otherwise the existing error handling gets
confused and reports hard to understand errors.

Signed-off-by: Paulo Neves <ptsneves@gmail.com>
2024-03-26 13:37:50 +01:00
Victor Stinner
27cf3ed00c
gh-90872: Fix subprocess.Popen.wait() for negative timeout (#116989)
On Windows, subprocess.Popen.wait() no longer calls
WaitForSingleObject() with a negative timeout: pass 0 ms if the
timeout is negative.
2024-03-19 14:42:44 +01:00
Brett Simmers
2731913dd5
gh-116167: Allow disabling the GIL with PYTHON_GIL=0 or -X gil=0 (#116338)
In free-threaded builds, running with `PYTHON_GIL=0` will now disable the
GIL. Follow-up issues track work to re-enable the GIL when loading an
incompatible extension, and to disable the GIL by default.

In order to support re-enabling the GIL at runtime, all GIL-related data
structures are initialized as usual, and disabling the GIL simply sets a flag
that causes `take_gil()` and `drop_gil()` to return early.
2024-03-11 11:02:58 -04:00
Serhiy Storchaka
e2c097ebde
gh-104522: Fix OSError raised when run a subprocess (#114195)
Only set filename to cwd if it was caused by failed chdir(cwd).

_fork_exec() now returns "noexec:chdir" for failed chdir(cwd).

Co-authored-by: Robert O'Shea <PurityLake@users.noreply.github.com>
2024-01-17 16:52:42 -08:00
Jakub Kulík
2b93f52242
gh-113117: Support posix_spawn in subprocess.Popen with close_fds=True (#113118)
Add support for `os.POSIX_SPAWN_CLOSEFROM` and
`posix_spawn_file_actions_addclosefrom_np` and have the `subprocess` module use
them when available.  This means `posix_spawn` can now be used in the default
`close_fds=True` situation on many platforms.

Co-authored-by: Gregory P. Smith [Google LLC] <greg@krypto.org>
2023-12-17 21:34:57 +00:00
Jakub Kulík
48c907a15c
gh-113119 fix environment handling in subprocess.Popen when posix_spawn is used (#113120)
* Allow posix_spawn to inherit environment form parent environ variable.

With this change, posix_spawn call can behave similarly to execv with regards to environments when used in subprocess functions.
2023-12-17 05:19:05 +00:00
Russell Keith-Magee
dc824c5dc1
gh-112736: Refactor del-safe symbol handling in subprocess (#112738)
Refactor delete-safe symbol handling in subprocess.

Only module globals are force-cleared during interpreter finalization, using a class reference instead of individually listing the constants everywhere is simpler.
2023-12-04 20:23:17 -08:00
Felipe A. Hernandez
3dcac78581
gh-106723: forward -Xfrozen_modules option to spawned process interpreters (#106724)
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
2023-07-28 05:04:26 +00:00
cptpcrd
3a4c44bb1e
gh-87474: Fix file descriptor leaks in subprocess.Popen (#96351)
This fixes several ways file descriptors could be leaked from `subprocess.Popen` constructor during error conditions by opening them later and using a context manager "fds to close" registration scheme to ensure they get closed before returning.

---------

Co-authored-by: Gregory P. Smith [Google] <greg@krypto.org>
2023-05-16 20:23:53 +00:00
Steve Dower
20cf32e761
gh-101283: Fix use of unbound variable (GH-101712) 2023-02-08 23:38:56 +00:00
Oleg Iarygin
23751ed826
gh-101283: Improved fallback logic for subprocess with shell=True on Windows (GH-101286) 2023-02-08 22:12:19 +00:00
andrei kulakov
80b3e32d62
Add note on capture_output arg to subprocess.run() docstring (#98012)
add note on capture_output arg to the docstring
2022-10-07 10:08:08 -07:00
andrei kulakov
db64fb9bbe
gh-97825: fix AttributeError when calling subprocess.check_output(input=None) with encoding or errors args (#97826)
* fix AttributeError, add unit test
2022-10-04 17:47:49 -07:00
Christian Heimes
8184f0fce3
gh-95174: Handle missing waitpid and gethostbyname in WASI (GH-95181) 2022-07-24 08:04:06 +02:00
Christian Heimes
db0b455ff4
gh-90473: Fail subprocess early on Emscripten/WASI (GH-92802) 2022-05-14 20:23:19 +02:00
Victor Stinner
ada8b6d1b1
gh-57684: Add -P cmdline option and PYTHONSAFEPATH env var (#31542)
Add the -P command line option and the PYTHONSAFEPATH environment
variable to not prepend a potentially unsafe path to sys.path.

* Add sys.flags.safe_path flag.
* Add PyConfig.safe_path member.
* Programs/_bootstrap_python.c uses config.safe_path=0.
* Update subprocess._optim_args_from_interpreter_flags() to handle
  the -P command line option.
* Modules/getpath.py sets safe_path to 1 if a "._pth" file is
  present.
2022-05-06 01:34:11 +02:00
Gregory P. Smith
f6dd14c653
gh-82616: Add process_group support to subprocess.Popen (#23930)
One more thing that can help prevent people from using `preexec_fn`.

Also adds conditional skips to two tests exposing ASAN flakiness on the Ubuntu 20.04 Address Sanitizer Github CI system. When that build is run on more modern systems the "problem" does not show up. It seems ASAN implementation related.

Co-authored-by: Zackery Spytz <zspytz@gmail.com>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
2022-05-05 16:22:32 -07:00
Inada Naoki
354ace8b07
gh-91954: Emit EncodingWarning from locale and subprocess (GH-91977)
locale.getpreferredencoding() and subprocess.Popen() emit EncodingWarning
2022-04-30 15:53:29 +09:00
Gregory P. Smith
cd5726fe67
gh-91401: Add a failsafe way to disable vfork. (#91490)
Just in case there is ever an issue with _posixsubprocess's use of
vfork() due to the complexity of using it properly and potential
directions that Linux platforms where it defaults to on could take, this
adds a failsafe so that users can disable its use entirely by setting
a global flag.

No known reason to disable it exists. But it'd be a shame to encounter
one and not be able to use CPython without patching and rebuilding it.

See the linked issue for some discussion on reasoning.

Also documents the existing way to disable posix_spawn.
2022-04-25 16:19:39 -07:00
Christian Heimes
082d3495d0
bpo-40280: Emscripten fork_exec now fails early (GH-32224) 2022-04-01 21:20:56 +02:00
Christian Heimes
606e496dd6
bpo-40280: Use presence of msvcrt module to detect Windows (GH-30930) 2022-01-27 01:57:43 -08:00
Christian Heimes
7f4b69b907
bpo-40280: Change subprocess imports for cleaner error on wasm32 (GH-30620) 2022-01-17 07:23:36 +01:00
Rémi Lapeyre
4d2957c1b9
bpo-40497: Fix handling of check in subprocess.check_output() (GH-19897)
Co-authored-by: Tal Einat <taleinat@gmail.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
2021-09-20 17:09:05 +02:00
Jakub Kulík
b1930bf75f
bpo-44935: enable posix_spawn() on Solaris (GH-27795)
Enable posix_spawn() on Solaris
2021-08-17 11:09:48 -07:00
Binbin
17b16e13bb
Fix typos in multiple files (GH-26689)
Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
2021-06-12 22:47:44 -04:00
M. Kocher
db0c5b786d
bpo-43776: Remove list call from args in Popen repr (GH-25338)
Removes the `list` call in the Popen `repr`.

Current implementation:

For cmd = `python --version`,  with `shell=True`.

```bash
<Popen: returncode: None args: ['p', 'y', 't', 'h', 'o', 'n', ' ', '-', '-',...>
```

For `shell=False` and args=`['python', '--version']`, the output is correct:

```bash
<Popen: returncode: None args: ['python', '--version']>
```

With the new changes the `repr`  yields:

For cmd = `python --version`,  with `shell=True`:

```bash
<Popen: returncode: None args: 'python --version'>
```

For `shell=False` and args=`['python', '--version']`, the output:

```bash
<Popen: returncode: None args: ['python', '--version']>
```

Automerge-Triggered-By: GH:gpshead
2021-04-28 01:16:38 -07:00