Skip to content
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

Return error when running uvx with a .py script #11623

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

jtfmumm
Copy link
Contributor

@jtfmumm jtfmumm commented Feb 19, 2025

If we see uvx script.py, we exit early, giving a hint to use uv run script.py if the script exists. If it does not exist, we suggest running uv run with a normalized package name.

This PR includes a snapshot test for each of these scenarios.

An alternative approach would be to wait until we encounter an error, and then add the hint. But if there happens to be a malicious package called script-py, this would be run unintentionally (a point raised by @zanieb).

Closes #10784

.extension()
.is_some_and(|ext| ext.eq_ignore_ascii_case("py"))
{
if possible_path.try_exists()? {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we error if we can't read the path? (earnestly not sure here)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good question. We could treat that as the "doesn't exist case" if we'd prefer.

));
}
return Err(anyhow::anyhow!(
"It looks like you are trying to run a script that doesn't exist. \n\n{}{} Did you mean `uvx {}`?",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems nice to include the script name, maybe like

It looks like you're trying to run a script ({}) but it does not exist.

Not in love with that, but don't have a better idea.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the "Did you mean" message, should we clarify what uvx <name> would do? Like "Did you mean to run a tool with uvx {}"?

I'm not sure if I prefer it, but wanted to put it out there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think adding that context is helpful

@@ -104,6 +105,26 @@ pub(crate) async fn run(
return Err(anyhow::anyhow!("Tool command could not be parsed as UTF-8 string. Use `--from` to specify the package name."));
};

let possible_path = Path::new(target);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If --from is provided, e.g, uvx --from <package> foo.py we should probably not perform this check as they've opted-in to loading a specific source.

We probably want to have this logic for uvx --from foo.py <command> though? We can't give a good suggestion though since we don't support like uv run --with-requirements foo.py <command> yet — see #6542

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to reflect your suggestion

.is_some_and(|ext| ext.eq_ignore_ascii_case("py") || ext.eq_ignore_ascii_case("pyw"))
{
return Err(anyhow::anyhow!(
"It looks you have passed a script instead of a package into `--from`"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the same suggestion as below? (but with --from <package>)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't suggest uv run ... but we can suggest uvx --from script-py ... instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

))
} else {
Err(anyhow::anyhow!(
"It looks like you are trying to run a script that doesn't exist. \n\n{}{} Did you mean to run a tool with `uvx {}`?",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I missed this initially, you need to use invocation_source here instead of hard-coding uvx because that's an alias for uv tool run (and we want to match what the user used)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@jtfmumm jtfmumm assigned jtfmumm and unassigned jtfmumm Feb 20, 2025
@zanieb
Copy link
Member

zanieb commented Feb 20, 2025

This looks good to me, thanks for addressing the feedback. I want to do one final pass on the messaging, since this is ostensibly breaking (though I really hope nobody is relying on this behavior). I'll do that on Monday.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Hint use of uv run if uvx is given a script path
2 participants