Skip to content

Commit

Permalink
Rewrite Python interpreter discovery (#3266)
Browse files Browse the repository at this point in the history
Updates our Python interpreter discovery to conform to the rules
described in #2386, please see that issue for a full description of the
behavior. Briefly, we now will search for interpreters that satisfy a
requested version without stopping at the first Python executable.
Additionally, if retrieving information about an interpreter fails we
will continue to search for a working interpreter. We also add the
plumbing necessary to request Python implementations other than CPython,
though we do not add support for other implementations at this time.

A major internal goal of this work is to prepare for user-facing managed
toolchains i.e. fetching a requested version during `uv run`. These APIs
are not introduced, but there is some managed toolchain handling as
required for our test suite.

Some noteworthy implementation changes:

- The `uv_interpreter::find_python` module has been removed in favor of
a `uv_interpreter::discovery` module.
- There are new types to help structure interpreter requests and track
sources
- Executable discovery is implemented as a big lazy iterator and is a
central authority for source precedence
- `uv_interpreter::Error` variants were split into scoped types in each
module
- There's much more unit test coverage, but not for Windows yet

Remaining work:

- [x] Write new test cases
- [x] Determine correct behavior around executables in the current
directory
- _Future_: Combine `PythonVersion` and `VersionRequest`
- _Future_: Consider splitting `ManagedToolchain` into local and remote
variants
- _Future_: Add Windows unit test coverage
- _Future_: Explore behavior around implementation precedence (i.e.
CPython over PyPy)

Refactors split into:

- #3329 
- #3330 
- #3331
- #3332

Closes #2386
  • Loading branch information
zanieb authored May 21, 2024
1 parent c14a7db commit d540d0f
Show file tree
Hide file tree
Showing 32 changed files with 3,105 additions and 1,170 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ jobs:

- name: "Cargo test"
run: |
export UV_BOOTSTRAP_DIR="$(pwd)/bin"
cargo nextest run \
--workspace \
--status-level skip --failure-output immediate-final --no-fail-fast -j 12 --final-status-level slow
Expand Down
13 changes: 12 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 11 additions & 5 deletions crates/uv-dev/src/fetch_python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ pub(crate) struct FetchPythonArgs {
pub(crate) async fn fetch_python(args: FetchPythonArgs) -> Result<()> {
let start = Instant::now();

let bootstrap_dir = TOOLCHAIN_DIRECTORY
.as_ref()
.expect("The toolchain directory must exist for bootstrapping");
let bootstrap_dir = TOOLCHAIN_DIRECTORY.clone().unwrap_or_else(|| {
std::env::current_dir()
.expect("Use `UV_BOOTSTRAP_DIR` if the current directory is not usable.")
.join("bin")
});

fs_err::create_dir_all(bootstrap_dir)?;
fs_err::create_dir_all(&bootstrap_dir)?;

let versions = if args.versions.is_empty() {
info!("Reading versions from file...");
Expand Down Expand Up @@ -59,7 +61,7 @@ pub(crate) async fn fetch_python(args: FetchPythonArgs) -> Result<()> {
let mut tasks = futures::stream::iter(downloads.iter())
.map(|download| {
async {
let result = download.fetch(&client, bootstrap_dir).await;
let result = download.fetch(&client, &bootstrap_dir).await;
(download.python_version(), result)
}
.instrument(info_span!("download", key = %download))
Expand Down Expand Up @@ -130,6 +132,10 @@ pub(crate) async fn fetch_python(args: FetchPythonArgs) -> Result<()> {
};

info!("Installed {} versions", requests.len());
info!(
r#"To enable discovery: export UV_BOOTSTRAP_DIR="{}""#,
bootstrap_dir.display()
);

Ok(())
}
Expand Down
4 changes: 3 additions & 1 deletion crates/uv-interpreter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ winapi = { workspace = true }

[dev-dependencies]
anyhow = { version = "1.0.80" }
assert_fs = { version = "1.1.1" }
indoc = { version = "2.0.4" }
insta = { version = "1.36.1", features = ["filters"] }
itertools = { version = "0.13.0" }
temp-env = { version = "0.3.6" }
tempfile = { version = "3.9.0" }
test-log = { version = "0.2.15", features = ["trace"], default-features = false }
Loading

0 comments on commit d540d0f

Please sign in to comment.