Make spawn timeout into a pytest argument to solve false negative in tests#2250
Make spawn timeout into a pytest argument to solve false negative in tests#2250sisp merged 14 commits intocopier-org:masterfrom
Conversation
…ing fixture `spawn_timout`
…pawn_timeout` fixture in fct args
…if spawn_timeout is not None and spawn_timeout > 0 else None` To keep the initial values, `+20` would have worked as well, but `*3` seemed more in-tune with the infered spirit of the scaling.
…MEOUT: <pexpect.popen_spawn.PopenSpawn object at 0x............>` being the cause of test fails to use the newly added argument `--spawn-timeout`
There was a problem hiding this comment.
Thanks for discovering this timeout issue with Gitpod and submitting a PR with a fix! 🙇
Making the timeout configurable via a pytest argument is a great idea! 👌 Just two comments/requests:
- Instead of using the new
spawn_timeoutfixture in every test that callsspawn, I'd modify thespawnfixture to usespawn_timeoutvalue as a default value whenspawn'stimeoutisNone. Only for the few occurrences where the timeout value has been30would I use thespawn_timeoutfixture in the test and callspawnwithtimeout=spawn_timeout * 3. This way, we can avoid the many extraspawn_timeoutfixture uses in tests. - Do we really need to be able to set the timeout to pexpect's default value? Being able to pass
Nonefeels a bit uncommon, and we might not even need it. I think the default timeout of 10s is fine, and it can always be overridden with a different value. TBH, I'd have to check pexpect's documentation to even know what their default value is. 😄
…default value instead of passing fixture to the tests Apply the request from the PR review.\nRemove the fixture argument from almost all the tests except those with initially hard-coded `30` and those with `run.subprocess(..., timeout=...)`. Refs: copier-org#2250#pullrequestreview-3075067200
|
Thank you very much for reviewing my PR ^^ Comment/Request 1: ImplementedPlease let me know if further modifications regarding that request are needed. Comment/Request 2: About pexpect timeout value typesIn
|
timeout value |
Effect |
|---|---|
None |
No timeout, wait indefinitely |
-1 |
Default to the class instance timeout |
x where x is a positive int |
timeout=x |
sisp
left a comment
There was a problem hiding this comment.
Looks great! 👌 Just a few remarks and an idea to use 0 as ∞.
Per review requests. Refs: copier-org#2250#pullrequestreview-3076415358
…lines Per review request. Refs: copier-org#2250#pullrequestreview-3076415358
Per review request. Refs: copier-org#2250#pullrequestreview-3076415358
…_timeout` fixture Per review request. The rest of the code have been adapted to maintain compatibility with pexpect, that is, ultimately remapping `0` to `None` for pexpect function calls. Refs: copier-org#2250#pullrequestreview-3076415358
…test arg in the dedicated note Per review request, and to match the change made in the code. Refs: copier-org#2250#pullrequestreview-3076415358
|
Can I make the pytest argument type validator stricter? type=lambda x: int(x)
if int(x) >= 0
else sys.exit(
f"\033[31mERROR: usage: pytest --spawn-timeout <int>\npytest: error: argument --spawn-timeout: should be positive or `0`: `{x}`\n\33[0m"
), |
Per review request. Equivalent as `spawn_timeout` is an int by fixture. Refs: copier-org#2250#pullrequestreview-3083262401
Makes sense. AFAIK, pytest's options parser is based on argparse, so you can create a custom type and raise, e.g., a
For example: def timeout_type(value: Any) -> int:
value = int(value)
if value >= -1:
return value
raise ValueError("Timeout must be a non-negative integer")
def pytest_addoption(parser: Parser) -> None:
parser.addoption(
"--spawn-timeout",
action="store",
default=10,
help="timeout for spawn of pexpect",
type=timeout_type,
) |
|
It seems that raising def timeout_type(value: str) -> int:
ivalue = int(value)
if ivalue >= -1:
return ivalue
raise ArgumentTypeError("Timeout must be a non-negative integer or -1")
def pytest_addoption(parser: pytest.Parser) -> None:
parser.addoption(
"--spawn-timeout",
action="store",
default=10,
help="timeout for spawn of pexpect",
type=timeout_type,
)$ pytest --spawn-timeout -3
ERROR: usage: pytest [options] [file_or_dir] [file_or_dir] [...]
pytest: error: argument --spawn-timeout: Timeout must be a non-negative integer or -1By the way, I've updated the custom type above a little to satisfy mypy and include -1 in the error message. |
Per review request. Favor raising a proper `ArgumentTypeError` in a function over bypassing and mimicking a pytest argument error using `sys.exit` in a lambda function. Refs: copier-org#2250#issuecomment-3182851308
|
Oh, nice! I've applied modifications, but 2 points require your arbitration:
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2250 +/- ##
==========================================
+ Coverage 97.78% 98.00% +0.21%
==========================================
Files 55 55
Lines 6088 6106 +18
==========================================
+ Hits 5953 5984 +31
+ Misses 135 122 -13
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
sisp
left a comment
There was a problem hiding this comment.
I've applied modifications, but 2 points require your arbitration:
- I've put the type validator function definition inside of the
pytest_addoptionfunction using it. I thought it made more sense scope-wise. But I can put it outside if it is preferable.
Looks good, no need to change it. 👍
- I've excluded
-1from the valid values because of the simplification we made intest_prompt.py: We removed ternaries in favor of a simplertimeout=spawn_timeout * 3. If we accept-1back, then I'll change the type validator and add back the ternaries for the 2 lines intest_prompt.py.
Sorry, I got confused about the -1 value. The current solution without -1 is great, no need to change it.
Only a minor formatting request, other than that it looks great. 👍 Thank you! 🙇
Per review request: ''Prettier doesn't recognize Material for MkDocs' admonition content as regular Markdown content and thus doesn't apply formatting, so we need to format it manually.'' Refs: copier-org#2250#discussion_r2274241832
|
Thank you very much for your guidance and your patience ^^ |



Issue
When running the tests for the repo on
gitpod.io, I kept on running into failed tests due to timeout of the spawn frompexpect:The cause is the hardcoded
timeout=10andtimeout=30when calling thespawnfixture, resulting in the same timeouts when the underlyingpexpect.popen_spawnis called. And it seems more time is needed in thegitpod.iodev environment than in the github CI tests.This PR
Description
Thus, to modify all of the timeout values easily at
pytestlaunch, this PR soft-code these timeout values through a fixturespawn_timeoutset by a newly definedpytestargument--spawn-timeout(whosetypeisint| Noneusing a smalllambdafunction checker type). This PR also documents the usage of this argument when facing the previously described issue above when trying to contribute.spawn_timeoutcan beNoneor-1to follow the values oftimeoutinpexpect.popen_spawn.The default values for the timeouts are the same as the hard-coded ones. A choice have been made regarding the timeouts of
30as thespawn_timeoutdefault value is10to fit the majority of the values: the value for30is soft-coded asspawn_timeout*3(instead of an alternativespawn_timeout+20) whenspawn_timeoutis a positiveint(to preserve the-1- andNone-value use-cases).Passing the
--spawn-timeoutpytest argument in the CLI or in the VSCode Workspace settings is described in the docs addition, along with the options it brings of either extending the timeout or removing it (whenNone).Additional
from __future__ import annotationshave been added when needed to accommodate the typeint | Noneof thespawn_timeoutfixture, given that.python-versionis3.9.Usage [As described in the doc]
If you get fails due to
pexpect.exceptions.TIMEOUT: <pexpect.popen_spawn.PopenSpawn object at 0x............>, you can adjust the timeout to a longer one (default:10), or remove the timeout (None).Either add it as an argument in your command:
uv run poe test --spawn-timeout NoneOr modify pytest arguments in VSCode Workspace settings:
.vscode/settings.json{ ... "python.testing.pytestArgs": [ "--spawn-timeout=None" ] }