feat: Support remote scripts with uv run (#6375)

<!--
Thank you for contributing to uv! To help us out with reviewing, please
consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

First off, congratulations on the 0.3 release! The PEP 723 standalone
scripts support is awesome, and I can already imagine a long tail of
little scripts of my own that would benefit from this functionality.

## Background

I really like the Deno CLI's support for running and installing remote
scripts.

```
deno run <url>
```

```
deno install --name foo <url>
```

I can see parallels with `uv run` and `uvx`. After mentioning this on
Discord, @zanieb suggested I could take a stab at a PR to implement
similar functionality for uv.

## Summary

This PR attempts to add support for executing remote standalone scripts
directly with `uv run`. While this is already possible by downloading
the script (i.e., via curl/wget) and then using uv run, having direct
support would be convenient.

The proposed functionality is:

```sh
uv run <url>
```

Another addition/alternative could be to support running scripts via
stdin:

```sh
curl -sL <url> | uv run -
```

But that is not implemented in this PR.

## Test Plan

I noticed that GitHub and `files.pythonhosted.org` URLs are used in some
of the tests. I've created a personal [GitHub
Gist](https://gist.github.com/manzt/cb24f3066c32983672025b04b9f98d1f)
with the example from PEP 723 for now to test this functionality.

~However, I couldn't figure out how to get the `with_snapshot` config
filter to filter out the tempfile path, so the test is currently
failing. Any assistance with this would be appreciated.~

## Notes

I'm not totally pleased with the implementation of this PR. I think it
would be better to handle the case earlier (and probably reuse the
cache), and avoid mutation, but since run command requires a local path
this was the simplest implementation I could come up with.

I know that performance is paramount with uv so I totally understand if
this requires a different approach or something more explicit to avoid
"inferring" the path. I'm just taking this as an opportunity to learn a
little more Rust and acquaint myself with the code base. cheers!

---------

Co-authored-by: Andrew Gallant <jamslam@gmail.com>
This commit is contained in:
Trevor Manz 2024-10-10 14:10:17 -04:00 committed by GitHub
parent 7d0e56607d
commit 585456a607
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 160 additions and 15 deletions

View file

@ -54,7 +54,7 @@ Run a command or script.
Ensures that the command runs in a Python environment.
When used with a file ending in `.py`, the file will be treated as a script and run with a Python interpreter, i.e., `uv run file.py` is equivalent to `uv run python file.py`. If the script contains inline dependency metadata, it will be installed into an isolated, ephemeral environment. When used with `-`, the input will be read from stdin, and treated as a Python script.
When used with a file ending in `.py` or an HTTP(S) URL, the file will be treated as a script and run with a Python interpreter, i.e., `uv run file.py` is equivalent to `uv run python file.py`. For URLs, the script is temporarily downloaded before execution. If the script contains inline dependency metadata, it will be installed into an isolated, ephemeral environment. When used with `-`, the input will be read from stdin, and treated as a Python script.
When used in a project, the project environment will be created and updated before invoking the command.