Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Negative run-time reported by subprocess.run's TimeoutExpired exception when setting timeout=0 #133089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
vadimkantorov opened this issue Apr 28, 2025 · 6 comments · Fixed by #133103
Labels
3.13 bugs and security fixes 3.14 bugs and security fixes stdlib Python modules in the Lib dir topic-subprocess Subprocess issues. type-bug An unexpected behavior, bug, or error

Comments

@vadimkantorov
Copy link

vadimkantorov commented Apr 28, 2025

Bug report

Bug description:

import subprocess
subprocess.run(['echo', 'hi'], timeout = 0)

# subprocess.TimeoutExpired: Command '['echo', 'hi']' timed out after -0.00010189996100962162 seconds
# subprocess.TimeoutExpired: Command '['echo', 'hi']' timed out after -4.819990135729313e-05 seconds

This is quite unexpected that the measured run-time can be negative

In general, it's unclear in the docs what behavior should have timeout=0. I would propose that it should disable timeout control, and should be equivalent to timeout=None.

But in any case, negative run-times are quite strange :)

CPython versions tested on:

3.12

Operating systems tested on:

WSLv1+Ubuntu24.04

Linked PRs

@vadimkantorov vadimkantorov added the type-bug An unexpected behavior, bug, or error label Apr 28, 2025
@picnixz picnixz added stdlib Python modules in the Lib dir topic-subprocess Subprocess issues. labels Apr 28, 2025
Zheaoli added a commit to Zheaoli/cpython that referenced this issue Apr 28, 2025
…ut=None' when the timeout is zero

Signed-off-by: Manjusaka <[email protected]>
@vadimkantorov
Copy link
Author

Btw, even outside of unspecified behavior for timeout=0, setting timeout to a very small value also prints negative time measurement:

import subprocess
subprocess.run(['echo', 'hi'], timeout = 1e-9)

# subprocess.TimeoutExpired: Command '['echo', 'hi']' timed out after -2.162200007660431e-05 seconds

How can time measurement be negative? Is it indicative of some other bug related to execution time measurement?

@ZeroIntensity ZeroIntensity added 3.13 bugs and security fixes 3.14 bugs and security fixes labels May 1, 2025
@gpshead
Copy link
Member

gpshead commented May 3, 2025

if someone specifies an unrealistically small timeout such as 0 or 0.00001 they should expect to get a TimeoutError. timeout=0 should not disable the timeout. Requiring None for that is not a bug.

It'd be reasonable to raise ValueError if the timeout supplied were < 0 but I would not consider that a bugfix.

The tiny negative number in the error message in this case is due to timeout math being floating point, inexact, and fuzzy on posix it is calculated as an time delta of remaining time between steps and thus floating point precision can yield an odd looking result. the value in the error message is not the original timeout passed into the API call as that is not preserved and passed through into the self.wait(timeout=self._remaining_time(endtime)) call within Popen._communicate that raises in this specific case.

@vadimkantorov
Copy link
Author

vadimkantorov commented May 3, 2025

timeout=0 should not disable the timeout. Requiring None for that is not a bug.

I propose that semantics of this edge case is explained clearly in the docs. Because in different systems the semantics of timeout=0 is different, e.g. in bash export TMOUT=0 diables the auto-logout timeout

For the negative number, of course I realize that it's most likely an artifact of some calculation, but it is again very surprising to see it as end user and there might be a suspicion of some bug somewhere. I propose that it's mentioned in the docs somewhere - or clipped up to zero to fix up the semantics


(Allowing timeout=0 to have disabling semantics can simplify types to just being "float" instead of "float | None" in client user code, where the timeout value gets passed around many layers of indirection (including e.g. configs)

@gpshead
Copy link
Member

gpshead commented May 4, 2025

I think the awkward error message is fixable, i left a note on the PR to see if they want to try doing that.

gpshead added a commit that referenced this issue May 5, 2025
…unc `subprocess.run` is called with a timeout (GH-133103)

Signed-off-by: Manjusaka <[email protected]>
Co-authored-by: Gregory P. Smith <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue May 5, 2025
… the func `subprocess.run` is called with a timeout (pythonGH-133103)

(cherry picked from commit 2bbcaed)

Co-authored-by: Nadeshiko Manju <[email protected]>
Signed-off-by: Manjusaka <[email protected]>
Co-authored-by: Gregory P. Smith <[email protected]>
@gpshead
Copy link
Member

gpshead commented May 5, 2025

thanks for the report and contributions!

gpshead added a commit that referenced this issue May 5, 2025
…n the func `subprocess.run` is called with a timeout (GH-133103) (#133418)

gh-133089: Use original timeout value for `TimeoutExpired` when the func `subprocess.run` is called with a timeout (GH-133103)
(cherry picked from commit 2bbcaed)

Signed-off-by: Manjusaka <[email protected]>
Co-authored-by: Nadeshiko Manju <[email protected]>
Co-authored-by: Gregory P. Smith <[email protected]>
@picnixz
Copy link
Member

picnixz commented May 5, 2025

I also thought about the floating-point computation being flaky but AFAIR, the timeout is computed using a monotonic clock so that's surprising. Or maybe the monotonic clock was not used in this specific case?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.13 bugs and security fixes 3.14 bugs and security fixes stdlib Python modules in the Lib dir topic-subprocess Subprocess issues. type-bug An unexpected behavior, bug, or error
Projects
None yet
4 participants