-
Notifications
You must be signed in to change notification settings - Fork 1.5k
More descriptive error message for uv run pythonx.xx
#12201
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
base: main
Are you sure you want to change the base?
Conversation
0271bb7
to
c363629
Compare
Hey @JWLee89, thanks for the contribution! This looks like a nice improvement. We can provide some feedback to unblock adding tests. |
if err.kind() == std::io::ErrorKind::NotFound && is_python_executable(&executable) { | ||
// Get version from python command string | ||
// e.g. python3.12 -> "3.12" or "" if python version not specified. | ||
let version_part = executable.strip_prefix("python").unwrap_or(""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should is_python_executable
be python_executable_version -> Some(str)
instead? Then you can avoid the unwrap_or
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Applied: 0cb2d5e
I think the semantics make sense here. I wonder if we can reuse anything from the |
if err.kind() == std::io::ErrorKind::NotFound && is_python_executable(&executable) { | ||
// Get version from python command string | ||
// e.g. python3.12 -> "3.12" or "" if python version not specified. | ||
let version_part = executable.strip_prefix("python").unwrap_or(""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe specified_version
instead of version_part
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Applied: e4a2fa1
"python4", | ||
"python", | ||
"python3.11.3", | ||
"python39", // Still a valid executable, although likely a typo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is likely a typo and we probably don't have to worry about the distant future at the moment, should we detect cases over 37 and treat them as typos? Not necessary for this PR though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be a good idea, especially since python version 37
will not likely be released anytime in the future while we are still alive 😆 .
Still I think we should carefully discuss this and come up with a reasonable spec before making any feature changes.
Would it be okay if I create a separate PR for this once we discuss and decide on specifications here?
/// - ❌ "python3abc", "python3.12b3", "", "python-foo" | ||
fn is_python_executable(executable_command: &str) -> bool { | ||
executable_command | ||
.strip_prefix("python") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth noting this isn't sufficient for Windows, where you'll have a .exe
suffix (though versioned executables are not common there)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the followup!
Windows handling logic
Good point! I don't a windows machine available to me right now, but my guess is that the access pattern for invoking python will be something like the following:
# versioned executable
python3.11.exe
# General
python.exe
Would this be correct?
A simple approach could be also stripping suffix .exe
. I don't think we should introduce complexity by checking whether the host is running windows unless this contextual information is already available without extra compute somewhere else.
Additional Possible Cases for Windows.
From some quick ChatGPT search, I found the following:
Command | Notes |
---|---|
python | After installing via the official installer, adds to PATH. |
py | Python launcher for Windows. Supports version flags like py -3.11. |
python.exe | Explicit executable, useful in scripts or batch files. |
py -X.Y | e.g., py -3.10 to launch a specific version via Python launcher. |
pythonw.exe | Launches Python without a console window (GUI apps). |
Out of these items above, do we need to support the py launcher (E.g. py
)? Just wanted to be sure :)
Edge cases
After thinking I just realized that people might invoke python using the following paths:
# absolute path
/usr/bin/python3
# venv path
/Users/username/repos/uv/venv/bin/python3.10
Should these kinds of absolute path specifications also be covered by this feature update?
CC: @jtfmumm
Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Applied here: e6a801d
Specs include:
- strip
.exe
suffix - Support absolute path python. E.g.
/Users/username/repos/uv/venv/bin/python3.10
Since spec was defined on the fly, might be good to review and discuss this together.
Thank you! 🙇
As I suspected quite some time ago (#6738 (comment)), it's problematic that we don't handle _every_ signal here. This PR adds handling for all of the Unix signals except `SIGCHLD`, `SIGIO`, and `SIGPOLL` which seem incorrect to forward. Also notable, we _cannot_ handle `SIGKILL` so if someone sends that to the PID instead of the PGID, they will leave dangling subprocesses. Instead, we could use `exec` and avoid this handling. However, we'd lose the ability to add nice error message on failure (e.g., as someone is trying to add in #12201) and, more critically, we'd need to figure out how to clean up resources properly (i.e., temporary directories) which currently happens on `Drop`. In the long-term, we'll probably want an option to use `exec` — but we'll need to figure out when to clean up resources or accept that they will dangle. This was last discussed in #3095 — discussion on that approach should continue there. A note on the implementation: I spent time time trying to write the handler using a tokio stream, so we could dynamically iterate over a list of signals instead of copy/pasting the implementation — I couldn't get it to work though and it didn't seem critical. Closes #12830
uv run pythonx.xx
I pushed some snapshot (integration) tests for a handful of cases. I think we might want to update the error messages for |
Thank you so much for adding the snapshot (integration) tests! 🙇
I absolutely agree and thank you for bringing this up! I should have clarified about this point properly in this PR. uv run python3.13.2 Results: `python3.13.2` not available in the virtual environment, which uses python `3.13.2`. Did you mean to search for a Python 3.13.2 environment with `uv run -p 3.13.2 python`? Description of updateWhen users specify up to the patch version: uv run python3.3.3 I updated so that if users specify up to the patch version. E.g. error: Failed to spawn: `python3.3.3`
Caused by: Please omit patch version. Try: `uv run python3.3`. Did you mean to search for a Python 3.3.3 environment with `uv run -p 3.3.3 python`? However, if we omit patch version, we will get the following (same behavior as before): error: Failed to spawn: `python3.3`
Caused by: `3.3` not available in the virtual environment, which uses python `3.13.2`. Did you mean to search for a Python 3.3 environment with `uv run -p 3.3 python`? Note: message is subject to discussion and I think after iterating together, we can come up with the finalized message soon :). |
489d8b2
to
87c1ad7
Compare
Related Issue
#11796
Summary
run python<valid-python-version>
.✅ "python", "python3", "python3.9", "python4", "python3.10", "python3.13.3", "python39" (yes, python39 might still be released in 100 years 😆 )
❌ "python3abc", "python3.12b3", "", "python-foo"
uv project
or not. See: https://github.com/astral-sh/uv/pull/12201/files#diff-423c3a82aab6dba4068dd7675391fc9328a66682131dbf2043e7847ab4ba8661R1092Automated Tests
Need to Discuss
python3.11.9
is invalid. However, uv supportsuv run -p 3.11.9 python
, which is why when we do the following:We will get the following error:
Is this okay? If not, we need to define the specs in the PR here.
post
versionSee:https://github.com/astral-sh/uv/pull/12201/files#diff-423c3a82aab6dba4068dd7675391fc9328a66682131dbf2043e7847ab4ba8661R1572-R1574
Would this be okay?
We can change the specs if needed. Lets discuss.
Manual Test
Case 1: run outside of project
python3.9
)cargo run -- run python3.9.3
cargo run -- run python3.9
cargo run -- run python3.11
cargo run -- run python3.11.9
IMPORTANT: Is this acceptable? Invoking python by its patch version is not supported, so this is the expected behavior, but we need to discuss whether this behavior is acceptable.
Case 2: run inside of project
Create project using
uv init example-app
uv run python3.13
uv run python3