mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
Change "toolchain" to "python" (#4735)
Whew this is a lot. The user-facing changes are: - `uv toolchain` to `uv python` e.g. `uv python find`, `uv python install`, ... - `UV_TOOLCHAIN_DIR` to` UV_PYTHON_INSTALL_DIR` - `<UV_STATE_DIR>/toolchains` to `<UV_STATE_DIR>/python` (with [automatic migration](https://github.com/astral-sh/uv/pull/4735/files#r1663029330)) - User-facing messages no longer refer to toolchains, instead using "Python", "Python versions" or "Python installations" The internal changes are: - `uv-toolchain` crate to `uv-python` - `Toolchain` no longer referenced in type names - Dropped unused `SystemPython` type (previously replaced) - Clarified the type names for "managed Python installations" - (more little things)
This commit is contained in:
parent
60fd98a5e4
commit
dd7da6af5f
105 changed files with 2629 additions and 2603 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -135,7 +135,7 @@ jobs:
|
|||
|
||||
- name: "Install required Python versions"
|
||||
run: |
|
||||
cargo run toolchain install
|
||||
cargo run python install
|
||||
|
||||
- name: "Install cargo nextest"
|
||||
uses: taiki-e/install-action@v2
|
||||
|
@ -172,7 +172,7 @@ jobs:
|
|||
|
||||
- name: "Install required Python versions"
|
||||
run: |
|
||||
cargo run toolchain install
|
||||
cargo run python install
|
||||
|
||||
- name: "Install cargo nextest"
|
||||
uses: taiki-e/install-action@v2
|
||||
|
|
|
@ -42,7 +42,7 @@ Testing uv requires multiple specific Python versions; they can be installed wit
|
|||
cargo run toolchain install
|
||||
```
|
||||
|
||||
The storage directory can be configured with `UV_TOOLCHAIN_DIR`.
|
||||
The storage directory can be configured with `UV_PYTHON_INSTALL_DIR`.
|
||||
|
||||
### Local testing
|
||||
|
||||
|
|
116
Cargo.lock
generated
116
Cargo.lock
generated
|
@ -408,8 +408,8 @@ dependencies = [
|
|||
"uv-dispatch",
|
||||
"uv-distribution",
|
||||
"uv-git",
|
||||
"uv-python",
|
||||
"uv-resolver",
|
||||
"uv-toolchain",
|
||||
"uv-types",
|
||||
]
|
||||
|
||||
|
@ -4483,12 +4483,12 @@ dependencies = [
|
|||
"uv-git",
|
||||
"uv-installer",
|
||||
"uv-normalize",
|
||||
"uv-python",
|
||||
"uv-requirements",
|
||||
"uv-resolver",
|
||||
"uv-scripts",
|
||||
"uv-settings",
|
||||
"uv-tool",
|
||||
"uv-toolchain",
|
||||
"uv-types",
|
||||
"uv-virtualenv",
|
||||
"uv-warnings",
|
||||
|
@ -4543,7 +4543,7 @@ dependencies = [
|
|||
"tracing",
|
||||
"uv-configuration",
|
||||
"uv-fs",
|
||||
"uv-toolchain",
|
||||
"uv-python",
|
||||
"uv-types",
|
||||
"uv-virtualenv",
|
||||
]
|
||||
|
@ -4587,9 +4587,9 @@ dependencies = [
|
|||
"uv-cache",
|
||||
"uv-configuration",
|
||||
"uv-normalize",
|
||||
"uv-python",
|
||||
"uv-resolver",
|
||||
"uv-settings",
|
||||
"uv-toolchain",
|
||||
"uv-version",
|
||||
"uv-warnings",
|
||||
]
|
||||
|
@ -4699,9 +4699,9 @@ dependencies = [
|
|||
"uv-distribution",
|
||||
"uv-git",
|
||||
"uv-installer",
|
||||
"uv-python",
|
||||
"uv-resolver",
|
||||
"uv-settings",
|
||||
"uv-toolchain",
|
||||
"uv-types",
|
||||
"walkdir",
|
||||
]
|
||||
|
@ -4725,8 +4725,8 @@ dependencies = [
|
|||
"uv-distribution",
|
||||
"uv-git",
|
||||
"uv-installer",
|
||||
"uv-python",
|
||||
"uv-resolver",
|
||||
"uv-toolchain",
|
||||
"uv-types",
|
||||
]
|
||||
|
||||
|
@ -4871,7 +4871,7 @@ dependencies = [
|
|||
"uv-fs",
|
||||
"uv-git",
|
||||
"uv-normalize",
|
||||
"uv-toolchain",
|
||||
"uv-python",
|
||||
"uv-types",
|
||||
"uv-warnings",
|
||||
"walkdir",
|
||||
|
@ -4894,6 +4894,52 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uv-python"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_fs",
|
||||
"cache-key",
|
||||
"clap",
|
||||
"configparser",
|
||||
"fs-err",
|
||||
"futures",
|
||||
"indoc",
|
||||
"install-wheel-rs",
|
||||
"itertools 0.13.0",
|
||||
"once_cell",
|
||||
"pep440_rs",
|
||||
"pep508_rs",
|
||||
"platform-tags",
|
||||
"pypi-types",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest-middleware",
|
||||
"rmp-serde",
|
||||
"same-file",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"target-lexicon",
|
||||
"temp-env",
|
||||
"tempfile",
|
||||
"test-log",
|
||||
"thiserror",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"url",
|
||||
"uv-cache",
|
||||
"uv-client",
|
||||
"uv-configuration",
|
||||
"uv-extract",
|
||||
"uv-fs",
|
||||
"uv-state",
|
||||
"uv-warnings",
|
||||
"which",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uv-requirements"
|
||||
version = "0.1.0"
|
||||
|
@ -4974,7 +5020,7 @@ dependencies = [
|
|||
"uv-distribution",
|
||||
"uv-git",
|
||||
"uv-normalize",
|
||||
"uv-toolchain",
|
||||
"uv-python",
|
||||
"uv-types",
|
||||
"uv-warnings",
|
||||
]
|
||||
|
@ -5014,8 +5060,8 @@ dependencies = [
|
|||
"uv-fs",
|
||||
"uv-macros",
|
||||
"uv-normalize",
|
||||
"uv-python",
|
||||
"uv-resolver",
|
||||
"uv-toolchain",
|
||||
"uv-warnings",
|
||||
]
|
||||
|
||||
|
@ -5047,58 +5093,12 @@ dependencies = [
|
|||
"tracing",
|
||||
"uv-cache",
|
||||
"uv-fs",
|
||||
"uv-python",
|
||||
"uv-state",
|
||||
"uv-toolchain",
|
||||
"uv-virtualenv",
|
||||
"uv-warnings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uv-toolchain"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_fs",
|
||||
"cache-key",
|
||||
"clap",
|
||||
"configparser",
|
||||
"fs-err",
|
||||
"futures",
|
||||
"indoc",
|
||||
"install-wheel-rs",
|
||||
"itertools 0.13.0",
|
||||
"once_cell",
|
||||
"pep440_rs",
|
||||
"pep508_rs",
|
||||
"platform-tags",
|
||||
"pypi-types",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest-middleware",
|
||||
"rmp-serde",
|
||||
"same-file",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"target-lexicon",
|
||||
"temp-env",
|
||||
"tempfile",
|
||||
"test-log",
|
||||
"thiserror",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"url",
|
||||
"uv-cache",
|
||||
"uv-client",
|
||||
"uv-configuration",
|
||||
"uv-extract",
|
||||
"uv-fs",
|
||||
"uv-state",
|
||||
"uv-warnings",
|
||||
"which",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uv-types"
|
||||
version = "0.0.1"
|
||||
|
@ -5116,7 +5116,7 @@ dependencies = [
|
|||
"uv-configuration",
|
||||
"uv-git",
|
||||
"uv-normalize",
|
||||
"uv-toolchain",
|
||||
"uv-python",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5135,7 +5135,7 @@ dependencies = [
|
|||
"thiserror",
|
||||
"tracing",
|
||||
"uv-fs",
|
||||
"uv-toolchain",
|
||||
"uv-python",
|
||||
"uv-version",
|
||||
]
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ uv-scripts = { path = "crates/uv-scripts" }
|
|||
uv-settings = { path = "crates/uv-settings" }
|
||||
uv-state = { path = "crates/uv-state" }
|
||||
uv-tool = { path = "crates/uv-tool" }
|
||||
uv-toolchain = { path = "crates/uv-toolchain" }
|
||||
uv-python = { path = "crates/uv-python" }
|
||||
uv-types = { path = "crates/uv-types" }
|
||||
uv-version = { path = "crates/uv-version" }
|
||||
uv-virtualenv = { path = "crates/uv-virtualenv" }
|
||||
|
|
|
@ -89,7 +89,7 @@ Functionality for interacting with Git repositories.
|
|||
|
||||
Functionality for installing Python packages into a virtual environment.
|
||||
|
||||
## [uv-toolchain](./uv-toolchain)
|
||||
## [uv-python](./uv-python)
|
||||
|
||||
Functionality for detecting and leveraging the current Python interpreter.
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ uv-configuration = { workspace = true }
|
|||
uv-dispatch = { workspace = true }
|
||||
uv-distribution = { workspace = true }
|
||||
uv-git = { workspace = true }
|
||||
uv-toolchain = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-resolver = { workspace = true }
|
||||
uv-types = { workspace = true }
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@ use bench::criterion::{criterion_group, criterion_main, measurement::WallTime, C
|
|||
use pypi_types::Requirement;
|
||||
use uv_cache::Cache;
|
||||
use uv_client::RegistryClientBuilder;
|
||||
use uv_python::PythonEnvironment;
|
||||
use uv_resolver::Manifest;
|
||||
use uv_toolchain::PythonEnvironment;
|
||||
|
||||
fn resolve_warm_jupyter(c: &mut Criterion<WallTime>) {
|
||||
let runtime = &tokio::runtime::Builder::new_current_thread()
|
||||
|
@ -87,11 +87,11 @@ mod resolver {
|
|||
use uv_dispatch::BuildDispatch;
|
||||
use uv_distribution::DistributionDatabase;
|
||||
use uv_git::GitResolver;
|
||||
use uv_python::PythonEnvironment;
|
||||
use uv_resolver::{
|
||||
FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, ResolutionGraph,
|
||||
Resolver,
|
||||
};
|
||||
use uv_toolchain::PythonEnvironment;
|
||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
|
||||
|
||||
static MARKERS: Lazy<MarkerEnvironment> = Lazy::new(|| {
|
||||
|
|
|
@ -20,7 +20,7 @@ pep508_rs = { workspace = true }
|
|||
pypi-types = { workspace = true }
|
||||
uv-configuration = { workspace = true }
|
||||
uv-fs = { workspace = true }
|
||||
uv-toolchain = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-types = { workspace = true }
|
||||
uv-virtualenv = { workspace = true }
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ use pep508_rs::PackageName;
|
|||
use pypi_types::{Requirement, VerbatimParsedUrl};
|
||||
use uv_configuration::{BuildKind, ConfigSettings, SetupPyStrategy};
|
||||
use uv_fs::{rename_with_retry, PythonExt, Simplified};
|
||||
use uv_toolchain::{Interpreter, PythonEnvironment};
|
||||
use uv_python::{Interpreter, PythonEnvironment};
|
||||
use uv_types::{BuildContext, BuildIsolation, SourceBuildTrait};
|
||||
|
||||
/// e.g. `pygraphviz/graphviz_wrap.c:3020:10: fatal error: graphviz/cgraph.h: No such file or directory`
|
||||
|
|
|
@ -21,7 +21,7 @@ uv-configuration = { workspace = true, features = ["clap"] }
|
|||
uv-normalize = { workspace = true }
|
||||
uv-resolver = { workspace = true, features = ["clap"] }
|
||||
uv-settings = { workspace = true, features = ["schemars"] }
|
||||
uv-toolchain = { workspace = true, features = ["clap", "schemars"]}
|
||||
uv-python = { workspace = true, features = ["clap", "schemars"]}
|
||||
uv-version = { workspace = true }
|
||||
uv-warnings = { workspace = true }
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ use uv_configuration::{
|
|||
ConfigSettingEntry, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple,
|
||||
};
|
||||
use uv_normalize::{ExtraName, PackageName};
|
||||
use uv_python::{PythonFetch, PythonPreference, PythonVersion};
|
||||
use uv_resolver::{AnnotationStyle, ExcludeNewer, PreReleaseMode, ResolutionMode};
|
||||
use uv_toolchain::{PythonVersion, ToolchainFetch, ToolchainPreference};
|
||||
|
||||
pub mod compat;
|
||||
pub mod options;
|
||||
|
@ -118,13 +118,13 @@ pub struct GlobalArgs {
|
|||
#[arg(global = true, long, overrides_with("offline"), hide = true)]
|
||||
pub no_offline: bool,
|
||||
|
||||
/// Whether to prefer Python toolchains from uv or on the system.
|
||||
/// Whether to prefer using Python from uv or on the system.
|
||||
#[arg(global = true, long)]
|
||||
pub toolchain_preference: Option<ToolchainPreference>,
|
||||
pub python_preference: Option<PythonPreference>,
|
||||
|
||||
/// Whether to automatically download Python toolchains when required.
|
||||
/// Whether to automatically download Python when required.
|
||||
#[arg(global = true, long)]
|
||||
pub toolchain_fetch: Option<ToolchainFetch>,
|
||||
pub python_fetch: Option<PythonFetch>,
|
||||
|
||||
/// Whether to enable experimental, preview features.
|
||||
#[arg(global = true, long, hide = true, env = "UV_PREVIEW", value_parser = clap::builder::BoolishValueParser::new(), overrides_with("no_preview"))]
|
||||
|
@ -173,7 +173,7 @@ pub enum Commands {
|
|||
/// Run and manage executable Python packages.
|
||||
Tool(ToolNamespace),
|
||||
/// Manage Python installations.
|
||||
Toolchain(ToolchainNamespace),
|
||||
Python(PythonNamespace),
|
||||
/// Manage Python projects.
|
||||
#[command(flatten)]
|
||||
Project(ProjectCommand),
|
||||
|
@ -2020,72 +2020,71 @@ pub struct ToolUninstallArgs {
|
|||
|
||||
#[derive(Args)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct ToolchainNamespace {
|
||||
pub struct PythonNamespace {
|
||||
#[command(subcommand)]
|
||||
pub command: ToolchainCommand,
|
||||
pub command: PythonCommand,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum ToolchainCommand {
|
||||
/// List the available toolchains.
|
||||
List(ToolchainListArgs),
|
||||
pub enum PythonCommand {
|
||||
/// List the available Python installations.
|
||||
List(PythonListArgs),
|
||||
|
||||
/// Download and install toolchains.
|
||||
Install(ToolchainInstallArgs),
|
||||
/// Download and install Python versions.
|
||||
Install(PythonInstallArgs),
|
||||
|
||||
/// Search for a toolchain.
|
||||
#[command(disable_version_flag = true)]
|
||||
Find(ToolchainFindArgs),
|
||||
/// Search for a Python installation.
|
||||
Find(PythonFindArgs),
|
||||
|
||||
/// Show the toolchains directory.
|
||||
/// Show the uv Python installation directory.
|
||||
Dir,
|
||||
|
||||
/// Uninstall toolchains.
|
||||
Uninstall(ToolchainUninstallArgs),
|
||||
/// Uninstall Python versions.
|
||||
Uninstall(PythonUninstallArgs),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct ToolchainListArgs {
|
||||
/// List all toolchain versions, including outdated patch versions.
|
||||
pub struct PythonListArgs {
|
||||
/// List all Python versions, including outdated patch versions.
|
||||
#[arg(long)]
|
||||
pub all_versions: bool,
|
||||
|
||||
/// List toolchains for all platforms.
|
||||
/// List Python installations for all platforms.
|
||||
#[arg(long)]
|
||||
pub all_platforms: bool,
|
||||
|
||||
/// Only show installed toolchains, exclude available downloads.
|
||||
/// Only show installed Python versions, exclude available downloads.
|
||||
#[arg(long)]
|
||||
pub only_installed: bool,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct ToolchainInstallArgs {
|
||||
/// The toolchains to install.
|
||||
pub struct PythonInstallArgs {
|
||||
/// The Python versions to install.
|
||||
///
|
||||
/// If not provided, the requested toolchain(s) will be read from the `.python-versions`
|
||||
/// If not provided, the requested Python version(s) will be read from the `.python-versions`
|
||||
/// or `.python-version` files. If neither file is present, uv will check if it has
|
||||
/// installed any toolchains. If not, it will install the latest stable version of Python.
|
||||
/// installed any Python versions. If not, it will install the latest stable version of Python.
|
||||
pub targets: Vec<String>,
|
||||
|
||||
/// Force the installation of the toolchain, even if it is already installed.
|
||||
/// Force the installation of the requested Python, even if it is already installed.
|
||||
#[arg(long, short)]
|
||||
pub force: bool,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct ToolchainUninstallArgs {
|
||||
/// The toolchains to uninstall.
|
||||
pub struct PythonUninstallArgs {
|
||||
/// The Python versions to uninstall.
|
||||
pub targets: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct ToolchainFindArgs {
|
||||
/// The toolchain request.
|
||||
pub struct PythonFindArgs {
|
||||
/// The Python request.
|
||||
pub request: Option<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ uv-git = { workspace = true }
|
|||
uv-installer = { workspace = true }
|
||||
uv-resolver = { workspace = true }
|
||||
uv-settings = { workspace = true, features = ["schemars"] }
|
||||
uv-toolchain = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-types = { workspace = true }
|
||||
|
||||
# Any dependencies that are exclusively used in `uv-dev` should be listed as non-workspace
|
||||
|
|
|
@ -16,8 +16,8 @@ use uv_configuration::{
|
|||
};
|
||||
use uv_dispatch::BuildDispatch;
|
||||
use uv_git::GitResolver;
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
use uv_resolver::{FlatIndex, InMemoryIndex};
|
||||
use uv_toolchain::{EnvironmentPreference, PythonEnvironment, ToolchainRequest};
|
||||
use uv_types::{BuildContext, BuildIsolation, InFlight};
|
||||
|
||||
#[derive(Parser)]
|
||||
|
@ -68,8 +68,8 @@ pub(crate) async fn build(args: BuildArgs) -> Result<PathBuf> {
|
|||
let index_urls = IndexLocations::default();
|
||||
let index_strategy = IndexStrategy::default();
|
||||
let setup_py = SetupPyStrategy::default();
|
||||
let toolchain = PythonEnvironment::find(
|
||||
&ToolchainRequest::default(),
|
||||
let python = PythonEnvironment::find(
|
||||
&PythonRequest::default(),
|
||||
EnvironmentPreference::OnlyVirtual,
|
||||
&cache,
|
||||
)?;
|
||||
|
@ -78,7 +78,7 @@ pub(crate) async fn build(args: BuildArgs) -> Result<PathBuf> {
|
|||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
&cache,
|
||||
toolchain.interpreter(),
|
||||
python.interpreter(),
|
||||
&index_urls,
|
||||
&flat_index,
|
||||
&index,
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
|||
use clap::Parser;
|
||||
use tracing::info;
|
||||
use uv_cache::{Cache, CacheArgs};
|
||||
use uv_toolchain::{EnvironmentPreference, PythonEnvironment, ToolchainRequest};
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
|
||||
#[derive(Parser)]
|
||||
pub(crate) struct CompileArgs {
|
||||
|
@ -21,7 +21,7 @@ pub(crate) async fn compile(args: CompileArgs) -> anyhow::Result<()> {
|
|||
python
|
||||
} else {
|
||||
let interpreter = PythonEnvironment::find(
|
||||
&ToolchainRequest::default(),
|
||||
&PythonRequest::default(),
|
||||
EnvironmentPreference::OnlyVirtual,
|
||||
&cache,
|
||||
)?
|
||||
|
|
|
@ -24,7 +24,7 @@ uv-configuration = { workspace = true }
|
|||
uv-distribution = { workspace = true }
|
||||
uv-git = { workspace = true }
|
||||
uv-installer = { workspace = true }
|
||||
uv-toolchain = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-resolver = { workspace = true }
|
||||
uv-types = { workspace = true }
|
||||
|
||||
|
|
|
@ -23,10 +23,10 @@ use uv_configuration::{Concurrency, PreviewMode};
|
|||
use uv_distribution::DistributionDatabase;
|
||||
use uv_git::GitResolver;
|
||||
use uv_installer::{Installer, Plan, Planner, Preparer, SitePackages};
|
||||
use uv_python::{Interpreter, PythonEnvironment};
|
||||
use uv_resolver::{
|
||||
ExcludeNewer, FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, Resolver,
|
||||
};
|
||||
use uv_toolchain::{Interpreter, PythonEnvironment};
|
||||
use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
|
||||
|
||||
/// The main implementation of [`BuildContext`], used by the CLI, see [`BuildContext`]
|
||||
|
|
|
@ -27,7 +27,7 @@ uv-distribution = { workspace = true }
|
|||
uv-extract = { workspace = true }
|
||||
uv-fs = { workspace = true }
|
||||
uv-git = { workspace = true }
|
||||
uv-toolchain = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-normalize = { workspace = true }
|
||||
uv-types = { workspace = true }
|
||||
uv-warnings = { workspace = true }
|
||||
|
|
|
@ -3,7 +3,7 @@ use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
|||
use tracing::instrument;
|
||||
|
||||
use distribution_types::CachedDist;
|
||||
use uv_toolchain::PythonEnvironment;
|
||||
use uv_python::PythonEnvironment;
|
||||
|
||||
pub struct Installer<'a> {
|
||||
venv: &'a PythonEnvironment,
|
||||
|
|
|
@ -21,7 +21,7 @@ use uv_distribution::{
|
|||
};
|
||||
use uv_fs::Simplified;
|
||||
use uv_git::GitUrl;
|
||||
use uv_toolchain::PythonEnvironment;
|
||||
use uv_python::PythonEnvironment;
|
||||
use uv_types::HashStrategy;
|
||||
|
||||
use crate::satisfies::RequirementSatisfaction;
|
||||
|
|
|
@ -13,7 +13,7 @@ use distribution_types::{
|
|||
use pep440_rs::{Version, VersionSpecifiers};
|
||||
use pypi_types::{Requirement, VerbatimParsedUrl};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_toolchain::PythonEnvironment;
|
||||
use uv_python::PythonEnvironment;
|
||||
use uv_types::InstalledPackagesProvider;
|
||||
|
||||
use crate::satisfies::RequirementSatisfaction;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "uv-toolchain"
|
||||
name = "uv-python"
|
||||
version = "0.0.1"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -3,10 +3,10 @@
|
|||
// Generated with `{{generated_with}}`
|
||||
// From template at `{{generated_from}}`
|
||||
|
||||
pub(crate) const PYTHON_DOWNLOADS: &[PythonDownload] = &[
|
||||
pub(crate) const PYTHON_DOWNLOADS: &[ManagedPythonDownload] = &[
|
||||
{{#versions}}
|
||||
PythonDownload {
|
||||
key: ToolchainKey {
|
||||
ManagedPythonDownload {
|
||||
key: PythonInstallationKey {
|
||||
major: {{value.major}},
|
||||
minor: {{value.minor}},
|
||||
patch: {{value.patch}},
|
|
@ -6,9 +6,9 @@ use std::str::FromStr;
|
|||
use crate::implementation::{
|
||||
Error as ImplementationError, ImplementationName, LenientImplementationName,
|
||||
};
|
||||
use crate::installation::PythonInstallationKey;
|
||||
use crate::platform::{self, Arch, Libc, Os};
|
||||
use crate::toolchain::ToolchainKey;
|
||||
use crate::{Interpreter, PythonVersion, ToolchainRequest, VersionRequest};
|
||||
use crate::{Interpreter, PythonRequest, PythonVersion, VersionRequest};
|
||||
use thiserror::Error;
|
||||
use uv_client::WrappedReqwestError;
|
||||
|
||||
|
@ -45,26 +45,26 @@ pub enum Error {
|
|||
#[source]
|
||||
err: io::Error,
|
||||
},
|
||||
#[error("Failed to read toolchain directory: {0}", dir.user_display())]
|
||||
#[error("Failed to read managed Python installation directory: {0}", dir.user_display())]
|
||||
ReadError {
|
||||
dir: PathBuf,
|
||||
#[source]
|
||||
err: io::Error,
|
||||
},
|
||||
#[error("Failed to parse toolchain directory name: {0}")]
|
||||
#[error("Failed to parse managed Python directory name: {0}")]
|
||||
NameError(String),
|
||||
#[error("Failed to parse request part")]
|
||||
InvalidRequestPlatform(#[from] platform::Error),
|
||||
#[error("Cannot download toolchain for request: {0}")]
|
||||
InvalidRequestKind(ToolchainRequest),
|
||||
#[error("Cannot download managed Python for request: {0}")]
|
||||
InvalidRequestKind(PythonRequest),
|
||||
// TODO(zanieb): Implement display for `PythonDownloadRequest`
|
||||
#[error("No download found for request: {0:?}")]
|
||||
NoDownloadFound(PythonDownloadRequest),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct PythonDownload {
|
||||
key: ToolchainKey,
|
||||
pub struct ManagedPythonDownload {
|
||||
key: PythonInstallationKey,
|
||||
url: &'static str,
|
||||
sha256: Option<&'static str>,
|
||||
}
|
||||
|
@ -125,30 +125,30 @@ impl PythonDownloadRequest {
|
|||
self
|
||||
}
|
||||
|
||||
/// Construct a new [`PythonDownloadRequest`] from a [`ToolchainRequest`] if possible.
|
||||
/// Construct a new [`PythonDownloadRequest`] from a [`PythonRequest`] if possible.
|
||||
///
|
||||
/// Returns [`None`] if the request kind is not compatible with a download, e.g., it is
|
||||
/// a request for a specific directory or executable name.
|
||||
pub fn try_from_request(request: &ToolchainRequest) -> Option<Self> {
|
||||
pub fn try_from_request(request: &PythonRequest) -> Option<Self> {
|
||||
Self::from_request(request).ok()
|
||||
}
|
||||
|
||||
/// Construct a new [`PythonDownloadRequest`] from a [`ToolchainRequest`].
|
||||
pub fn from_request(request: &ToolchainRequest) -> Result<Self, Error> {
|
||||
/// Construct a new [`PythonDownloadRequest`] from a [`PythonRequest`].
|
||||
pub fn from_request(request: &PythonRequest) -> Result<Self, Error> {
|
||||
match request {
|
||||
ToolchainRequest::Version(version) => Ok(Self::default().with_version(version.clone())),
|
||||
ToolchainRequest::Implementation(implementation) => {
|
||||
PythonRequest::Version(version) => Ok(Self::default().with_version(version.clone())),
|
||||
PythonRequest::Implementation(implementation) => {
|
||||
Ok(Self::default().with_implementation(*implementation))
|
||||
}
|
||||
ToolchainRequest::ImplementationVersion(implementation, version) => Ok(Self::default()
|
||||
PythonRequest::ImplementationVersion(implementation, version) => Ok(Self::default()
|
||||
.with_implementation(*implementation)
|
||||
.with_version(version.clone())),
|
||||
ToolchainRequest::Key(request) => Ok(request.clone()),
|
||||
ToolchainRequest::Any => Ok(Self::default()),
|
||||
// We can't download a toolchain for these request kinds
|
||||
ToolchainRequest::Directory(_)
|
||||
| ToolchainRequest::ExecutableName(_)
|
||||
| ToolchainRequest::File(_) => Err(Error::InvalidRequestKind(request.clone())),
|
||||
PythonRequest::Key(request) => Ok(request.clone()),
|
||||
PythonRequest::Any => Ok(Self::default()),
|
||||
// We can't download a managed installation for these request kinds
|
||||
PythonRequest::Directory(_)
|
||||
| PythonRequest::ExecutableName(_)
|
||||
| PythonRequest::File(_) => Err(Error::InvalidRequestKind(request.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,11 +204,12 @@ impl PythonDownloadRequest {
|
|||
}
|
||||
|
||||
/// Iterate over all [`PythonDownload`]'s that match this request.
|
||||
pub fn iter_downloads(&self) -> impl Iterator<Item = &'static PythonDownload> + '_ {
|
||||
PythonDownload::iter_all().filter(move |download| self.satisfied_by_download(download))
|
||||
pub fn iter_downloads(&self) -> impl Iterator<Item = &'static ManagedPythonDownload> + '_ {
|
||||
ManagedPythonDownload::iter_all()
|
||||
.filter(move |download| self.satisfied_by_download(download))
|
||||
}
|
||||
|
||||
pub fn satisfied_by_key(&self, key: &ToolchainKey) -> bool {
|
||||
pub fn satisfied_by_key(&self, key: &PythonInstallationKey) -> bool {
|
||||
if let Some(arch) = &self.arch {
|
||||
if key.arch != *arch {
|
||||
return false;
|
||||
|
@ -232,7 +233,7 @@ impl PythonDownloadRequest {
|
|||
true
|
||||
}
|
||||
|
||||
pub fn satisfied_by_download(&self, download: &PythonDownload) -> bool {
|
||||
pub fn satisfied_by_download(&self, download: &ManagedPythonDownload) -> bool {
|
||||
self.satisfied_by_key(download.key())
|
||||
}
|
||||
|
||||
|
@ -356,9 +357,11 @@ pub enum DownloadResult {
|
|||
Fetched(PathBuf),
|
||||
}
|
||||
|
||||
impl PythonDownload {
|
||||
impl ManagedPythonDownload {
|
||||
/// Return the first [`PythonDownload`] matching a request, if any.
|
||||
pub fn from_request(request: &PythonDownloadRequest) -> Result<&'static PythonDownload, Error> {
|
||||
pub fn from_request(
|
||||
request: &PythonDownloadRequest,
|
||||
) -> Result<&'static ManagedPythonDownload, Error> {
|
||||
request
|
||||
.iter_downloads()
|
||||
.next()
|
||||
|
@ -366,7 +369,7 @@ impl PythonDownload {
|
|||
}
|
||||
|
||||
/// Iterate over all [`PythonDownload`]'s.
|
||||
pub fn iter_all() -> impl Iterator<Item = &'static PythonDownload> {
|
||||
pub fn iter_all() -> impl Iterator<Item = &'static ManagedPythonDownload> {
|
||||
PYTHON_DOWNLOADS.iter()
|
||||
}
|
||||
|
||||
|
@ -374,7 +377,7 @@ impl PythonDownload {
|
|||
self.url
|
||||
}
|
||||
|
||||
pub fn key(&self) -> &ToolchainKey {
|
||||
pub fn key(&self) -> &PythonInstallationKey {
|
||||
&self.key
|
||||
}
|
||||
|
||||
|
@ -465,7 +468,7 @@ impl From<reqwest_middleware::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for PythonDownload {
|
||||
impl Display for ManagedPythonDownload {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.key)
|
||||
}
|
|
@ -7,12 +7,12 @@ use std::sync::Arc;
|
|||
use uv_cache::Cache;
|
||||
use uv_fs::{LockedFile, Simplified};
|
||||
|
||||
use crate::discovery::find_toolchain;
|
||||
use crate::toolchain::Toolchain;
|
||||
use crate::discovery::find_python_installation;
|
||||
use crate::installation::PythonInstallation;
|
||||
use crate::virtualenv::{virtualenv_python_executable, PyVenvConfiguration};
|
||||
use crate::{
|
||||
EnvironmentPreference, Error, Interpreter, Prefix, Target, ToolchainNotFound,
|
||||
ToolchainPreference, ToolchainRequest,
|
||||
EnvironmentPreference, Error, Interpreter, Prefix, PythonNotFound, PythonPreference,
|
||||
PythonRequest, Target,
|
||||
};
|
||||
|
||||
/// A Python environment, consisting of a Python [`Interpreter`] and its associated paths.
|
||||
|
@ -27,15 +27,15 @@ struct PythonEnvironmentShared {
|
|||
|
||||
/// The result of failed environment discovery.
|
||||
///
|
||||
/// Generally this is cast from [`ToolchainNotFound`] by [`PythonEnvironment::find`].
|
||||
/// Generally this is cast from [`PythonNotFound`] by [`PythonEnvironment::find`].
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub struct EnvironmentNotFound {
|
||||
request: ToolchainRequest,
|
||||
request: PythonRequest,
|
||||
preference: EnvironmentPreference,
|
||||
}
|
||||
|
||||
impl From<ToolchainNotFound> for EnvironmentNotFound {
|
||||
fn from(value: ToolchainNotFound) -> Self {
|
||||
impl From<PythonNotFound> for EnvironmentNotFound {
|
||||
fn from(value: PythonNotFound) -> Self {
|
||||
Self {
|
||||
request: value.request,
|
||||
preference: value.environment_preference,
|
||||
|
@ -59,7 +59,7 @@ impl fmt::Display for EnvironmentNotFound {
|
|||
EnvironmentPreference::OnlyVirtual => "virtual environment",
|
||||
};
|
||||
match self.request {
|
||||
ToolchainRequest::Any => {
|
||||
PythonRequest::Any => {
|
||||
write!(f, "No {environment} found")
|
||||
}
|
||||
_ => {
|
||||
|
@ -72,24 +72,24 @@ impl fmt::Display for EnvironmentNotFound {
|
|||
impl PythonEnvironment {
|
||||
/// Find a [`PythonEnvironment`] matching the given request and preference.
|
||||
///
|
||||
/// If looking for a Python toolchain to create a new environment, use [`Toolchain::find`]
|
||||
/// If looking for a Python interpreter to create a new environment, use [`PythonInstallation::find`]
|
||||
/// instead.
|
||||
pub fn find(
|
||||
request: &ToolchainRequest,
|
||||
request: &PythonRequest,
|
||||
preference: EnvironmentPreference,
|
||||
cache: &Cache,
|
||||
) -> Result<Self, Error> {
|
||||
let toolchain = match find_toolchain(
|
||||
let installation = match find_python_installation(
|
||||
request,
|
||||
preference,
|
||||
// Ignore managed toolchains when looking for environments
|
||||
ToolchainPreference::OnlySystem,
|
||||
// Ignore managed installations when looking for environments
|
||||
PythonPreference::OnlySystem,
|
||||
cache,
|
||||
)? {
|
||||
Ok(toolchain) => toolchain,
|
||||
Ok(installation) => installation,
|
||||
Err(err) => return Err(EnvironmentNotFound::from(err).into()),
|
||||
};
|
||||
Ok(Self::from_toolchain(toolchain))
|
||||
Ok(Self::from_installation(installation))
|
||||
}
|
||||
|
||||
/// Create a [`PythonEnvironment`] from the virtual environment at the given root.
|
||||
|
@ -99,7 +99,7 @@ impl PythonEnvironment {
|
|||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||
return Err(Error::MissingEnvironment(EnvironmentNotFound {
|
||||
preference: EnvironmentPreference::Any,
|
||||
request: ToolchainRequest::Directory(root.as_ref().to_owned()),
|
||||
request: PythonRequest::Directory(root.as_ref().to_owned()),
|
||||
}));
|
||||
}
|
||||
Err(err) => return Err(Error::Discovery(err.into())),
|
||||
|
@ -113,9 +113,9 @@ impl PythonEnvironment {
|
|||
})))
|
||||
}
|
||||
|
||||
/// Create a [`PythonEnvironment`] from an existing [`Toolchain`].
|
||||
pub fn from_toolchain(toolchain: Toolchain) -> Self {
|
||||
Self::from_interpreter(toolchain.into_interpreter())
|
||||
/// Create a [`PythonEnvironment`] from an existing [`PythonInstallation`].
|
||||
pub fn from_installation(installation: PythonInstallation) -> Self {
|
||||
Self::from_interpreter(installation.into_interpreter())
|
||||
}
|
||||
|
||||
/// Create a [`PythonEnvironment`] from an existing [`Interpreter`].
|
|
@ -8,27 +8,25 @@ use uv_client::BaseClientBuilder;
|
|||
use uv_cache::Cache;
|
||||
|
||||
use crate::discovery::{
|
||||
find_best_toolchain, find_toolchain, EnvironmentPreference, ToolchainRequest,
|
||||
find_best_python_installation, find_python_installation, EnvironmentPreference, PythonRequest,
|
||||
};
|
||||
use crate::downloads::{DownloadResult, PythonDownload, PythonDownloadRequest};
|
||||
use crate::downloads::{DownloadResult, ManagedPythonDownload, PythonDownloadRequest};
|
||||
use crate::implementation::LenientImplementationName;
|
||||
use crate::managed::{InstalledToolchain, InstalledToolchains};
|
||||
use crate::managed::{ManagedPythonInstallation, ManagedPythonInstallations};
|
||||
use crate::platform::{Arch, Libc, Os};
|
||||
use crate::{
|
||||
Error, Interpreter, PythonVersion, ToolchainFetch, ToolchainPreference, ToolchainSource,
|
||||
};
|
||||
use crate::{Error, Interpreter, PythonFetch, PythonPreference, PythonSource, PythonVersion};
|
||||
|
||||
/// A Python interpreter and accompanying tools.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Toolchain {
|
||||
pub struct PythonInstallation {
|
||||
// Public in the crate for test assertions
|
||||
pub(crate) source: ToolchainSource,
|
||||
pub(crate) source: PythonSource,
|
||||
pub(crate) interpreter: Interpreter,
|
||||
}
|
||||
|
||||
impl Toolchain {
|
||||
/// Create a new [`Toolchain`] from a source, interpreter tuple.
|
||||
pub(crate) fn from_tuple(tuple: (ToolchainSource, Interpreter)) -> Self {
|
||||
impl PythonInstallation {
|
||||
/// Create a new [`PythonInstallation`] from a source, interpreter tuple.
|
||||
pub(crate) fn from_tuple(tuple: (PythonSource, Interpreter)) -> Self {
|
||||
let (source, interpreter) = tuple;
|
||||
Self {
|
||||
source,
|
||||
|
@ -36,9 +34,9 @@ impl Toolchain {
|
|||
}
|
||||
}
|
||||
|
||||
/// Find an installed [`Toolchain`].
|
||||
/// Find an installed [`PythonInstallation`].
|
||||
///
|
||||
/// This is the standard interface for discovering a Python toolchain for creating
|
||||
/// This is the standard interface for discovering a Python installation for creating
|
||||
/// an environment. If interested in finding an existing environment, see
|
||||
/// [`PythonEnvironment::find`] instead.
|
||||
///
|
||||
|
@ -47,26 +45,26 @@ impl Toolchain {
|
|||
/// but if you want to allow an interpreter from a virtual environment if it satisfies the request,
|
||||
/// then use [`EnvironmentPreference::Any`].
|
||||
///
|
||||
/// See [`find_toolchain`] for implementation details.
|
||||
/// See [`find_installation`] for implementation details.
|
||||
pub fn find(
|
||||
request: &ToolchainRequest,
|
||||
request: &PythonRequest,
|
||||
environments: EnvironmentPreference,
|
||||
preference: ToolchainPreference,
|
||||
preference: PythonPreference,
|
||||
cache: &Cache,
|
||||
) -> Result<Self, Error> {
|
||||
let toolchain = find_toolchain(request, environments, preference, cache)??;
|
||||
Ok(toolchain)
|
||||
let installation = find_python_installation(request, environments, preference, cache)??;
|
||||
Ok(installation)
|
||||
}
|
||||
|
||||
/// Find an installed [`Toolchain`] that satisfies a requested version, if the request cannot
|
||||
/// be satisfied, fallback to the best available toolchain.
|
||||
/// Find an installed [`PythonInstallation`] that satisfies a requested version, if the request cannot
|
||||
/// be satisfied, fallback to the best available Python installation.
|
||||
pub fn find_best(
|
||||
request: &ToolchainRequest,
|
||||
request: &PythonRequest,
|
||||
environments: EnvironmentPreference,
|
||||
preference: ToolchainPreference,
|
||||
preference: PythonPreference,
|
||||
cache: &Cache,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(find_best_toolchain(
|
||||
Ok(find_best_python_installation(
|
||||
request,
|
||||
environments,
|
||||
preference,
|
||||
|
@ -74,33 +72,33 @@ impl Toolchain {
|
|||
)??)
|
||||
}
|
||||
|
||||
/// Find or fetch a [`Toolchain`].
|
||||
/// Find or fetch a [`PythonInstallation`].
|
||||
///
|
||||
/// Unlike [`Toolchain::find`], if the toolchain is not installed it will be installed automatically.
|
||||
/// Unlike [`PythonInstallation::find`], if the required Python is not installed it will be installed automatically.
|
||||
pub async fn find_or_fetch<'a>(
|
||||
request: Option<ToolchainRequest>,
|
||||
request: Option<PythonRequest>,
|
||||
environments: EnvironmentPreference,
|
||||
preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
client_builder: &BaseClientBuilder<'a>,
|
||||
cache: &Cache,
|
||||
) -> Result<Self, Error> {
|
||||
let request = request.unwrap_or_default();
|
||||
|
||||
// Perform a fetch aggressively if managed toolchains are preferred
|
||||
if matches!(preference, ToolchainPreference::Managed) && toolchain_fetch.is_automatic() {
|
||||
// Perform a fetch aggressively if managed Python is preferred
|
||||
if matches!(preference, PythonPreference::Managed) && python_fetch.is_automatic() {
|
||||
if let Some(request) = PythonDownloadRequest::try_from_request(&request) {
|
||||
return Self::fetch(request, client_builder, cache).await;
|
||||
}
|
||||
}
|
||||
|
||||
// Search for the toolchain
|
||||
// Search for the installation
|
||||
match Self::find(&request, environments, preference, cache) {
|
||||
Ok(venv) => Ok(venv),
|
||||
// If missing and allowed, perform a fetch
|
||||
err @ Err(Error::MissingToolchain(_))
|
||||
err @ Err(Error::MissingPython(_))
|
||||
if preference.allows_managed()
|
||||
&& toolchain_fetch.is_automatic()
|
||||
&& python_fetch.is_automatic()
|
||||
&& client_builder.connectivity.is_online() =>
|
||||
{
|
||||
if let Some(request) = PythonDownloadRequest::try_from_request(&request) {
|
||||
|
@ -114,51 +112,51 @@ impl Toolchain {
|
|||
}
|
||||
}
|
||||
|
||||
/// Download and install the requested toolchain.
|
||||
/// Download and install the requested installation.
|
||||
pub async fn fetch<'a>(
|
||||
request: PythonDownloadRequest,
|
||||
client_builder: &BaseClientBuilder<'a>,
|
||||
cache: &Cache,
|
||||
) -> Result<Self, Error> {
|
||||
let toolchains = InstalledToolchains::from_settings()?.init()?;
|
||||
let toolchain_dir = toolchains.root();
|
||||
let _lock = toolchains.acquire_lock()?;
|
||||
let installations = ManagedPythonInstallations::from_settings()?.init()?;
|
||||
let installations_dir = installations.root();
|
||||
let _lock = installations.acquire_lock()?;
|
||||
|
||||
let download = PythonDownload::from_request(&request)?;
|
||||
let download = ManagedPythonDownload::from_request(&request)?;
|
||||
let client = client_builder.build();
|
||||
|
||||
info!("Fetching requested toolchain...");
|
||||
let result = download.fetch(&client, toolchain_dir).await?;
|
||||
info!("Fetching requested Python...");
|
||||
let result = download.fetch(&client, installations_dir).await?;
|
||||
|
||||
let path = match result {
|
||||
DownloadResult::AlreadyAvailable(path) => path,
|
||||
DownloadResult::Fetched(path) => path,
|
||||
};
|
||||
|
||||
let installed = InstalledToolchain::new(path)?;
|
||||
let installed = ManagedPythonInstallation::new(path)?;
|
||||
installed.ensure_externally_managed()?;
|
||||
|
||||
Ok(Self {
|
||||
source: ToolchainSource::Managed,
|
||||
source: PythonSource::Managed,
|
||||
interpreter: Interpreter::query(installed.executable(), cache)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a [`Toolchain`] from an existing [`Interpreter`].
|
||||
/// Create a [`PythonInstallation`] from an existing [`Interpreter`].
|
||||
pub fn from_interpreter(interpreter: Interpreter) -> Self {
|
||||
Self {
|
||||
source: ToolchainSource::ProvidedPath,
|
||||
source: PythonSource::ProvidedPath,
|
||||
interpreter,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the [`ToolchainSource`] of the toolchain, indicating where it was found.
|
||||
pub fn source(&self) -> &ToolchainSource {
|
||||
/// Return the [`PythonSource`] of the Python installation, indicating where it was found.
|
||||
pub fn source(&self) -> &PythonSource {
|
||||
&self.source
|
||||
}
|
||||
|
||||
pub fn key(&self) -> ToolchainKey {
|
||||
ToolchainKey::new(
|
||||
pub fn key(&self) -> PythonInstallationKey {
|
||||
PythonInstallationKey::new(
|
||||
LenientImplementationName::from(self.interpreter.implementation_name()),
|
||||
self.interpreter.python_major(),
|
||||
self.interpreter.python_minor(),
|
||||
|
@ -169,32 +167,32 @@ impl Toolchain {
|
|||
)
|
||||
}
|
||||
|
||||
/// Return the Python [`Version`] of the toolchain as reported by its interpreter.
|
||||
/// Return the Python [`Version`] of the Python installation as reported by its interpreter.
|
||||
pub fn python_version(&self) -> &Version {
|
||||
self.interpreter.python_version()
|
||||
}
|
||||
|
||||
/// Return the [`LenientImplementationName`] of the toolchain as reported by its interpreter.
|
||||
/// Return the [`LenientImplementationName`] of the Python installation as reported by its interpreter.
|
||||
pub fn implementation(&self) -> LenientImplementationName {
|
||||
LenientImplementationName::from(self.interpreter.implementation_name())
|
||||
}
|
||||
|
||||
/// Return the [`Arch`] of the toolchain as reported by its interpreter.
|
||||
/// Return the [`Arch`] of the Python installation as reported by its interpreter.
|
||||
pub fn arch(&self) -> Arch {
|
||||
Arch::from(&self.interpreter.platform().arch())
|
||||
}
|
||||
|
||||
/// Return the [`Libc`] of the toolchain as reported by its interpreter.
|
||||
/// Return the [`Libc`] of the Python installation as reported by its interpreter.
|
||||
pub fn libc(&self) -> Libc {
|
||||
Libc::from(self.interpreter.platform().os())
|
||||
}
|
||||
|
||||
/// Return the [`Os`] of the toolchain as reported by its interpreter.
|
||||
/// Return the [`Os`] of the Python installation as reported by its interpreter.
|
||||
pub fn os(&self) -> Os {
|
||||
Os::from(self.interpreter.platform().os())
|
||||
}
|
||||
|
||||
/// Return the [`Interpreter`] for the toolchain.
|
||||
/// Return the [`Interpreter`] for the Python installation.
|
||||
pub fn interpreter(&self) -> &Interpreter {
|
||||
&self.interpreter
|
||||
}
|
||||
|
@ -205,13 +203,13 @@ impl Toolchain {
|
|||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ToolchainKeyError {
|
||||
#[error("Failed to parse toolchain key `{0}`: {1}")]
|
||||
pub enum PythonInstallationKeyError {
|
||||
#[error("Failed to parse Python installation key `{0}`: {1}")]
|
||||
ParseError(String, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ToolchainKey {
|
||||
pub struct PythonInstallationKey {
|
||||
pub(crate) implementation: LenientImplementationName,
|
||||
pub(crate) major: u8,
|
||||
pub(crate) minor: u8,
|
||||
|
@ -221,7 +219,7 @@ pub struct ToolchainKey {
|
|||
pub(crate) libc: Libc,
|
||||
}
|
||||
|
||||
impl ToolchainKey {
|
||||
impl PythonInstallationKey {
|
||||
pub fn new(
|
||||
implementation: LenientImplementationName,
|
||||
major: u8,
|
||||
|
@ -248,7 +246,7 @@ impl ToolchainKey {
|
|||
|
||||
pub fn version(&self) -> PythonVersion {
|
||||
PythonVersion::from_str(&format!("{}.{}.{}", self.major, self.minor, self.patch))
|
||||
.expect("Toolchain keys must have valid Python versions")
|
||||
.expect("Python installation keys must have valid Python versions")
|
||||
}
|
||||
|
||||
pub fn arch(&self) -> &Arch {
|
||||
|
@ -264,7 +262,7 @@ impl ToolchainKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ToolchainKey {
|
||||
impl fmt::Display for PythonInstallationKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
|
@ -274,13 +272,13 @@ impl fmt::Display for ToolchainKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromStr for ToolchainKey {
|
||||
type Err = ToolchainKeyError;
|
||||
impl FromStr for PythonInstallationKey {
|
||||
type Err = PythonInstallationKeyError;
|
||||
|
||||
fn from_str(key: &str) -> Result<Self, Self::Err> {
|
||||
let parts = key.split('-').collect::<Vec<_>>();
|
||||
let [implementation, version, os, arch, libc] = parts.as_slice() else {
|
||||
return Err(ToolchainKeyError::ParseError(
|
||||
return Err(PythonInstallationKeyError::ParseError(
|
||||
key.to_string(),
|
||||
"not enough `-`-separated values".to_string(),
|
||||
));
|
||||
|
@ -289,15 +287,18 @@ impl FromStr for ToolchainKey {
|
|||
let implementation = LenientImplementationName::from(*implementation);
|
||||
|
||||
let os = Os::from_str(os).map_err(|err| {
|
||||
ToolchainKeyError::ParseError(key.to_string(), format!("invalid OS: {err}"))
|
||||
PythonInstallationKeyError::ParseError(key.to_string(), format!("invalid OS: {err}"))
|
||||
})?;
|
||||
|
||||
let arch = Arch::from_str(arch).map_err(|err| {
|
||||
ToolchainKeyError::ParseError(key.to_string(), format!("invalid architecture: {err}"))
|
||||
PythonInstallationKeyError::ParseError(
|
||||
key.to_string(),
|
||||
format!("invalid architecture: {err}"),
|
||||
)
|
||||
})?;
|
||||
|
||||
let libc = Libc::from_str(libc).map_err(|err| {
|
||||
ToolchainKeyError::ParseError(key.to_string(), format!("invalid libc: {err}"))
|
||||
PythonInstallationKeyError::ParseError(key.to_string(), format!("invalid libc: {err}"))
|
||||
})?;
|
||||
|
||||
let [major, minor, patch] = version
|
||||
|
@ -305,13 +306,13 @@ impl FromStr for ToolchainKey {
|
|||
.map(str::parse::<u8>)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|err| {
|
||||
ToolchainKeyError::ParseError(
|
||||
PythonInstallationKeyError::ParseError(
|
||||
key.to_string(),
|
||||
format!("invalid Python version: {err}"),
|
||||
)
|
||||
})?[..]
|
||||
else {
|
||||
return Err(ToolchainKeyError::ParseError(
|
||||
return Err(PythonInstallationKeyError::ParseError(
|
||||
key.to_string(),
|
||||
"invalid Python version: expected `<major>.<minor>.<patch>`".to_string(),
|
||||
));
|
||||
|
@ -329,12 +330,12 @@ impl FromStr for ToolchainKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ToolchainKey {
|
||||
impl PartialOrd for PythonInstallationKey {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
impl Ord for ToolchainKey {
|
||||
impl Ord for PythonInstallationKey {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.to_string().cmp(&other.to_string())
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -14,11 +14,11 @@ use crate::downloads::Error as DownloadError;
|
|||
use crate::implementation::{
|
||||
Error as ImplementationError, ImplementationName, LenientImplementationName,
|
||||
};
|
||||
use crate::installation::{self, PythonInstallationKey};
|
||||
use crate::platform::Error as PlatformError;
|
||||
use crate::platform::{Arch, Libc, Os};
|
||||
use crate::python_version::PythonVersion;
|
||||
use crate::toolchain::{self, ToolchainKey};
|
||||
use crate::ToolchainRequest;
|
||||
use crate::PythonRequest;
|
||||
use uv_fs::{LockedFile, Simplified};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
@ -41,26 +41,26 @@ pub enum Error {
|
|||
#[source]
|
||||
err: io::Error,
|
||||
},
|
||||
#[error("Failed to read toolchain directory: {0}", dir.user_display())]
|
||||
#[error("Failed to read Python installation directory: {0}", dir.user_display())]
|
||||
ReadError {
|
||||
dir: PathBuf,
|
||||
#[source]
|
||||
err: io::Error,
|
||||
},
|
||||
#[error("Failed to read toolchain directory name: {0}")]
|
||||
#[error("Failed to read managed Python directory name: {0}")]
|
||||
NameError(String),
|
||||
#[error(transparent)]
|
||||
NameParseError(#[from] toolchain::ToolchainKeyError),
|
||||
NameParseError(#[from] installation::PythonInstallationKeyError),
|
||||
}
|
||||
/// A collection of uv-managed Python toolchains installed on the current system.
|
||||
/// A collection of uv-managed Python installations installed on the current system.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InstalledToolchains {
|
||||
/// The path to the top-level directory of the installed toolchains.
|
||||
pub struct ManagedPythonInstallations {
|
||||
/// The path to the top-level directory of the installed Python versions.
|
||||
root: PathBuf,
|
||||
}
|
||||
|
||||
impl InstalledToolchains {
|
||||
/// A directory for installed toolchains at `root`.
|
||||
impl ManagedPythonInstallations {
|
||||
/// A directory for Python installations at `root`.
|
||||
fn from_path(root: impl Into<PathBuf>) -> Self {
|
||||
Self { root: root.into() }
|
||||
}
|
||||
|
@ -74,33 +74,48 @@ impl InstalledToolchains {
|
|||
}
|
||||
|
||||
/// Prefer, in order:
|
||||
/// 1. The specific toolchain directory specified by the user, i.e., `UV_TOOLCHAIN_DIR`
|
||||
/// 2. A directory in the system-appropriate user-level data directory, e.g., `~/.local/uv/toolchains`
|
||||
/// 3. A directory in the local data directory, e.g., `./.uv/toolchains`
|
||||
/// 1. The specific Python directory specified by the user, i.e., `UV_PYTHON_INSTALL_DIR`
|
||||
/// 2. A directory in the system-appropriate user-level data directory, e.g., `~/.local/uv/python`
|
||||
/// 3. A directory in the local data directory, e.g., `./.uv/python`
|
||||
pub fn from_settings() -> Result<Self, Error> {
|
||||
if let Some(toolchain_dir) = std::env::var_os("UV_TOOLCHAIN_DIR") {
|
||||
Ok(Self::from_path(toolchain_dir))
|
||||
if let Some(install_dir) = std::env::var_os("UV_PYTHON_INSTALL_DIR") {
|
||||
Ok(Self::from_path(install_dir))
|
||||
} else {
|
||||
Ok(Self::from_path(
|
||||
StateStore::from_settings(None)?.bucket(StateBucket::Toolchains),
|
||||
StateStore::from_settings(None)?.bucket(StateBucket::ManagedPython),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a temporary installed toolchain directory.
|
||||
/// Create a temporary Python installation directory.
|
||||
pub fn temp() -> Result<Self, Error> {
|
||||
Ok(Self::from_path(
|
||||
StateStore::temp()?.bucket(StateBucket::Toolchains),
|
||||
StateStore::temp()?.bucket(StateBucket::ManagedPython),
|
||||
))
|
||||
}
|
||||
|
||||
/// Initialize the installed toolchain directory.
|
||||
/// Initialize the Python installation directory.
|
||||
///
|
||||
/// Ensures the directory is created.
|
||||
pub fn init(self) -> Result<Self, Error> {
|
||||
let root = &self.root;
|
||||
|
||||
// Create the toolchain directory, if it doesn't exist.
|
||||
// Support `toolchains` -> `python` migration transparently.
|
||||
if !root.exists()
|
||||
&& root
|
||||
.parent()
|
||||
.is_some_and(|parent| parent.join("toolchains").exists())
|
||||
{
|
||||
let deprecated = root.parent().unwrap().join("toolchains");
|
||||
// Move the deprecated directory to the new location.
|
||||
fs::rename(&deprecated, root)?;
|
||||
// Create a link or junction to at the old location
|
||||
uv_fs::replace_symlink(root, &deprecated)?;
|
||||
} else {
|
||||
fs::create_dir_all(root)?;
|
||||
}
|
||||
|
||||
// Create the directory, if it doesn't exist.
|
||||
fs::create_dir_all(root)?;
|
||||
|
||||
// Add a .gitignore.
|
||||
|
@ -117,17 +132,19 @@ impl InstalledToolchains {
|
|||
Ok(self)
|
||||
}
|
||||
|
||||
/// Iterate over each installed toolchain in this directory.
|
||||
/// Iterate over each Python installation in this directory.
|
||||
///
|
||||
/// Toolchains are sorted descending by name, such that we get deterministic
|
||||
/// Pythons are sorted descending by name, such that we get deterministic
|
||||
/// ordering across platforms. This also results in newer Python versions coming first,
|
||||
/// but should not be relied on — instead the toolchains should be sorted later by
|
||||
/// but should not be relied on — instead the installations should be sorted later by
|
||||
/// the parsed Python version.
|
||||
pub fn find_all(&self) -> Result<impl DoubleEndedIterator<Item = InstalledToolchain>, Error> {
|
||||
pub fn find_all(
|
||||
&self,
|
||||
) -> Result<impl DoubleEndedIterator<Item = ManagedPythonInstallation>, Error> {
|
||||
let dirs = match fs_err::read_dir(&self.root) {
|
||||
Ok(toolchain_dirs) => {
|
||||
Ok(installation_dirs) => {
|
||||
// Collect sorted directory paths; `read_dir` is not stable across platforms
|
||||
let directories: BTreeSet<_> = toolchain_dirs
|
||||
let directories: BTreeSet<_> = installation_dirs
|
||||
.filter_map(|read_dir| match read_dir {
|
||||
Ok(entry) => match entry.file_type() {
|
||||
Ok(file_type) => file_type.is_dir().then_some(Ok(entry.path())),
|
||||
|
@ -153,25 +170,25 @@ impl InstalledToolchains {
|
|||
Ok(dirs
|
||||
.into_iter()
|
||||
.filter_map(|path| {
|
||||
InstalledToolchain::new(path)
|
||||
ManagedPythonInstallation::new(path)
|
||||
.inspect_err(|err| {
|
||||
warn!("Ignoring malformed toolchain entry:\n {err}");
|
||||
warn!("Ignoring malformed managed Python entry:\n {err}");
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.rev())
|
||||
}
|
||||
|
||||
/// Iterate over toolchains that support the current platform.
|
||||
/// Iterate over Python installations that support the current platform.
|
||||
pub fn find_matching_current_platform(
|
||||
&self,
|
||||
) -> Result<impl DoubleEndedIterator<Item = InstalledToolchain>, Error> {
|
||||
) -> Result<impl DoubleEndedIterator<Item = ManagedPythonInstallation>, Error> {
|
||||
let platform_key = platform_key_from_env();
|
||||
|
||||
let iter = InstalledToolchains::from_settings()?
|
||||
let iter = ManagedPythonInstallations::from_settings()?
|
||||
.find_all()?
|
||||
.filter(move |toolchain| {
|
||||
toolchain
|
||||
.filter(move |installation| {
|
||||
installation
|
||||
.path
|
||||
.file_name()
|
||||
.map(OsStr::to_string_lossy)
|
||||
|
@ -181,20 +198,20 @@ impl InstalledToolchains {
|
|||
Ok(iter)
|
||||
}
|
||||
|
||||
/// Iterate over toolchains that satisfy the given Python version on this platform.
|
||||
/// Iterate over managed Python installations that satisfy the requested version on this platform.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// - The platform metadata cannot be read
|
||||
/// - A directory in the toolchain directory cannot be read
|
||||
/// - A directory for the installation cannot be read
|
||||
pub fn find_version<'a>(
|
||||
&self,
|
||||
version: &'a PythonVersion,
|
||||
) -> Result<impl DoubleEndedIterator<Item = InstalledToolchain> + 'a, Error> {
|
||||
) -> Result<impl DoubleEndedIterator<Item = ManagedPythonInstallation> + 'a, Error> {
|
||||
Ok(self
|
||||
.find_matching_current_platform()?
|
||||
.filter(move |toolchain| {
|
||||
toolchain
|
||||
.filter(move |installation| {
|
||||
installation
|
||||
.path
|
||||
.file_name()
|
||||
.map(OsStr::to_string_lossy)
|
||||
|
@ -208,21 +225,21 @@ impl InstalledToolchains {
|
|||
}
|
||||
|
||||
static EXTERNALLY_MANAGED: &str = "[externally-managed]
|
||||
Error=This toolchain is managed by uv and should not be modified.
|
||||
Error=This Python installation is managed by uv and should not be modified.
|
||||
";
|
||||
|
||||
/// A uv-managed Python toolchain installed on the current system..
|
||||
/// A uv-managed Python installation on the current system..
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub struct InstalledToolchain {
|
||||
/// The path to the top-level directory of the installed toolchain.
|
||||
pub struct ManagedPythonInstallation {
|
||||
/// The path to the top-level directory of the installed Python.
|
||||
path: PathBuf,
|
||||
/// An install key for the toolchain.
|
||||
key: ToolchainKey,
|
||||
/// An install key for the Python version.
|
||||
key: PythonInstallationKey,
|
||||
}
|
||||
|
||||
impl InstalledToolchain {
|
||||
impl ManagedPythonInstallation {
|
||||
pub fn new(path: PathBuf) -> Result<Self, Error> {
|
||||
let key = ToolchainKey::from_str(
|
||||
let key = PythonInstallationKey::from_str(
|
||||
path.file_name()
|
||||
.ok_or(Error::NameError("name is empty".to_string()))?
|
||||
.to_str()
|
||||
|
@ -252,7 +269,7 @@ impl InstalledToolchain {
|
|||
match self.key.implementation() {
|
||||
LenientImplementationName::Known(implementation) => implementation,
|
||||
LenientImplementationName::Unknown(_) => {
|
||||
panic!("Managed toolchains should have a known implementation")
|
||||
panic!("Managed Python installations should have a known implementation")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -261,31 +278,31 @@ impl InstalledToolchain {
|
|||
&self.path
|
||||
}
|
||||
|
||||
pub fn key(&self) -> &ToolchainKey {
|
||||
pub fn key(&self) -> &PythonInstallationKey {
|
||||
&self.key
|
||||
}
|
||||
|
||||
pub fn satisfies(&self, request: &ToolchainRequest) -> bool {
|
||||
pub fn satisfies(&self, request: &PythonRequest) -> bool {
|
||||
match request {
|
||||
ToolchainRequest::File(path) => self.executable() == *path,
|
||||
ToolchainRequest::Any => true,
|
||||
ToolchainRequest::Directory(path) => self.path() == *path,
|
||||
ToolchainRequest::ExecutableName(name) => self
|
||||
PythonRequest::File(path) => self.executable() == *path,
|
||||
PythonRequest::Any => true,
|
||||
PythonRequest::Directory(path) => self.path() == *path,
|
||||
PythonRequest::ExecutableName(name) => self
|
||||
.executable()
|
||||
.file_name()
|
||||
.is_some_and(|filename| filename.to_string_lossy() == *name),
|
||||
ToolchainRequest::Implementation(implementation) => {
|
||||
PythonRequest::Implementation(implementation) => {
|
||||
implementation == self.implementation()
|
||||
}
|
||||
ToolchainRequest::ImplementationVersion(implementation, version) => {
|
||||
PythonRequest::ImplementationVersion(implementation, version) => {
|
||||
implementation == self.implementation() && version.matches_version(&self.version())
|
||||
}
|
||||
ToolchainRequest::Version(version) => version.matches_version(&self.version()),
|
||||
ToolchainRequest::Key(request) => request.satisfied_by_key(self.key()),
|
||||
PythonRequest::Version(version) => version.matches_version(&self.version()),
|
||||
PythonRequest::Key(request) => request.satisfied_by_key(self.key()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure the toolchain is marked as externally managed with the
|
||||
/// Ensure the environment is marked as externally managed with the
|
||||
/// standard `EXTERNALLY-MANAGED` file.
|
||||
pub fn ensure_externally_managed(&self) -> Result<(), Error> {
|
||||
// Construct the path to the `stdlib` directory.
|
||||
|
@ -311,7 +328,7 @@ fn platform_key_from_env() -> String {
|
|||
format!("{os}-{arch}-{libc}").to_lowercase()
|
||||
}
|
||||
|
||||
impl fmt::Display for InstalledToolchain {
|
||||
impl fmt::Display for ManagedPythonInstallation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
|
@ -2,40 +2,40 @@ use fs_err as fs;
|
|||
use std::{io, path::PathBuf};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::ToolchainRequest;
|
||||
use crate::PythonRequest;
|
||||
|
||||
/// Read [`ToolchainRequest`]s from a version file, if present.
|
||||
/// Read [`PythonRequest`]s from a version file, if present.
|
||||
///
|
||||
/// Prefers `.python-versions` then `.python-version`.
|
||||
/// If only one Python version is desired, use [`request_from_version_files`] which prefers the `.python-version` file.
|
||||
pub async fn requests_from_version_file() -> Result<Option<Vec<ToolchainRequest>>, io::Error> {
|
||||
pub async fn requests_from_version_file() -> Result<Option<Vec<PythonRequest>>, io::Error> {
|
||||
if let Some(versions) = read_versions_file().await? {
|
||||
Ok(Some(
|
||||
versions
|
||||
.into_iter()
|
||||
.map(|version| ToolchainRequest::parse(&version))
|
||||
.map(|version| PythonRequest::parse(&version))
|
||||
.collect(),
|
||||
))
|
||||
} else if let Some(version) = read_version_file().await? {
|
||||
Ok(Some(vec![ToolchainRequest::parse(&version)]))
|
||||
Ok(Some(vec![PythonRequest::parse(&version)]))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a [`ToolchainRequest`] from a version file, if present.
|
||||
/// Read a [`PythonRequest`] from a version file, if present.
|
||||
///
|
||||
/// Prefers `.python-version` then the first entry of `.python-versions`.
|
||||
/// If multiple Python versions are desired, use [`requests_from_version_files`] instead.
|
||||
pub async fn request_from_version_file() -> Result<Option<ToolchainRequest>, io::Error> {
|
||||
pub async fn request_from_version_file() -> Result<Option<PythonRequest>, io::Error> {
|
||||
if let Some(version) = read_version_file().await? {
|
||||
Ok(Some(ToolchainRequest::parse(&version)))
|
||||
Ok(Some(PythonRequest::parse(&version)))
|
||||
} else if let Some(versions) = read_versions_file().await? {
|
||||
Ok(versions
|
||||
.into_iter()
|
||||
.next()
|
||||
.inspect(|_| debug!("Using the first version from `.python-versions`"))
|
||||
.map(|version| ToolchainRequest::parse(&version)))
|
||||
.map(|version| PythonRequest::parse(&version)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
|
@ -6,7 +6,7 @@ Generates the `downloads.inc` file from the `downloads.inc.mustache` template.
|
|||
|
||||
Usage:
|
||||
|
||||
uv run --isolated --with chevron-blue -- crates/uv-toolchain/template-download-metadata.py
|
||||
uv run --isolated --with chevron-blue -- crates/uv-python/template-download-metadata.py
|
||||
"""
|
||||
|
||||
import sys
|
|
@ -27,7 +27,7 @@ uv-client = { workspace = true }
|
|||
uv-configuration = { workspace = true }
|
||||
uv-distribution = { workspace = true }
|
||||
uv-git = { workspace = true }
|
||||
uv-toolchain = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-normalize = { workspace = true }
|
||||
uv-types = { workspace = true }
|
||||
uv-warnings = { workspace = true }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use pep440_rs::VersionSpecifiers;
|
||||
use pep508_rs::{MarkerTree, StringVersion};
|
||||
use uv_toolchain::{Interpreter, PythonVersion};
|
||||
use uv_python::{Interpreter, PythonVersion};
|
||||
|
||||
use crate::{RequiresPython, RequiresPythonBound};
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ uv-fs = { workspace = true }
|
|||
uv-macros = { workspace = true }
|
||||
uv-normalize = { workspace = true, features = ["schemars"] }
|
||||
uv-resolver = { workspace = true, features = ["schemars"] }
|
||||
uv-toolchain = { workspace = true, features = ["schemars"] }
|
||||
uv-python = { workspace = true, features = ["schemars"] }
|
||||
uv-warnings = { workspace = true }
|
||||
|
||||
dirs-sys = { workspace = true }
|
||||
|
|
|
@ -4,8 +4,8 @@ use std::path::PathBuf;
|
|||
use distribution_types::IndexUrl;
|
||||
use install_wheel_rs::linker::LinkMode;
|
||||
use uv_configuration::{ConfigSettings, IndexStrategy, KeyringProviderType, TargetTriple};
|
||||
use uv_python::{PythonFetch, PythonPreference, PythonVersion};
|
||||
use uv_resolver::{AnnotationStyle, ExcludeNewer, PreReleaseMode, ResolutionMode};
|
||||
use uv_toolchain::{PythonVersion, ToolchainFetch, ToolchainPreference};
|
||||
|
||||
use crate::{FilesystemOptions, PipOptions};
|
||||
|
||||
|
@ -69,8 +69,8 @@ impl_combine_or!(PythonVersion);
|
|||
impl_combine_or!(ResolutionMode);
|
||||
impl_combine_or!(String);
|
||||
impl_combine_or!(TargetTriple);
|
||||
impl_combine_or!(ToolchainPreference);
|
||||
impl_combine_or!(ToolchainFetch);
|
||||
impl_combine_or!(PythonPreference);
|
||||
impl_combine_or!(PythonFetch);
|
||||
impl_combine_or!(bool);
|
||||
|
||||
impl<T> Combine for Option<Vec<T>> {
|
||||
|
|
|
@ -10,8 +10,8 @@ use uv_configuration::{
|
|||
};
|
||||
use uv_macros::CombineOptions;
|
||||
use uv_normalize::{ExtraName, PackageName};
|
||||
use uv_python::{PythonFetch, PythonPreference, PythonVersion};
|
||||
use uv_resolver::{AnnotationStyle, ExcludeNewer, PreReleaseMode, ResolutionMode};
|
||||
use uv_toolchain::{PythonVersion, ToolchainFetch, ToolchainPreference};
|
||||
|
||||
/// A `pyproject.toml` with an (optional) `[tool.uv]` section.
|
||||
#[allow(dead_code)]
|
||||
|
@ -59,8 +59,8 @@ pub struct GlobalOptions {
|
|||
pub no_cache: Option<bool>,
|
||||
pub cache_dir: Option<PathBuf>,
|
||||
pub preview: Option<bool>,
|
||||
pub toolchain_preference: Option<ToolchainPreference>,
|
||||
pub toolchain_fetch: Option<ToolchainFetch>,
|
||||
pub python_preference: Option<PythonPreference>,
|
||||
pub python_fetch: Option<PythonFetch>,
|
||||
}
|
||||
|
||||
/// Settings relevant to all installer operations.
|
||||
|
|
|
@ -95,8 +95,8 @@ impl StateStore {
|
|||
/// are subdirectories of the state store root.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum StateBucket {
|
||||
// Managed toolchains
|
||||
Toolchains,
|
||||
// Managed Python installations
|
||||
ManagedPython,
|
||||
// Installed tools
|
||||
Tools,
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ pub enum StateBucket {
|
|||
impl StateBucket {
|
||||
fn to_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Toolchains => "toolchains",
|
||||
Self::ManagedPython => "python",
|
||||
Self::Tools => "tools",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ pypi-types = { workspace = true }
|
|||
uv-cache = { workspace = true }
|
||||
uv-fs = { workspace = true }
|
||||
uv-state = { workspace = true }
|
||||
uv-toolchain = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-virtualenv = { workspace = true }
|
||||
uv-warnings = { workspace = true }
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ pub use receipt::ToolReceipt;
|
|||
pub use tool::{Tool, ToolEntrypoint};
|
||||
use uv_cache::Cache;
|
||||
use uv_fs::{LockedFile, Simplified};
|
||||
use uv_python::{Interpreter, PythonEnvironment};
|
||||
use uv_state::{StateBucket, StateStore};
|
||||
use uv_toolchain::{Interpreter, PythonEnvironment};
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
mod receipt;
|
||||
|
@ -38,7 +38,7 @@ pub enum Error {
|
|||
#[error("Failed to find a directory for executables")]
|
||||
NoExecutableDirectory,
|
||||
#[error(transparent)]
|
||||
EnvironmentError(#[from] uv_toolchain::Error),
|
||||
EnvironmentError(#[from] uv_python::Error),
|
||||
#[error("Failed to find a receipt for tool `{0}` at {1}")]
|
||||
MissingToolReceipt(String, PathBuf),
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ pypi-types = { workspace = true }
|
|||
uv-cache = { workspace = true }
|
||||
uv-configuration = { workspace = true }
|
||||
uv-git = { workspace = true }
|
||||
uv-toolchain = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-normalize = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use uv_toolchain::PythonEnvironment;
|
||||
use uv_python::PythonEnvironment;
|
||||
|
||||
/// Whether to enforce build isolation when building source distributions.
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
|
|
|
@ -9,7 +9,7 @@ use pypi_types::Requirement;
|
|||
use uv_cache::Cache;
|
||||
use uv_configuration::{BuildKind, BuildOptions};
|
||||
use uv_git::GitResolver;
|
||||
use uv_toolchain::{Interpreter, PythonEnvironment};
|
||||
use uv_python::{Interpreter, PythonEnvironment};
|
||||
|
||||
/// Avoids cyclic crate dependencies between resolver, installer and builder.
|
||||
///
|
||||
|
|
|
@ -20,7 +20,7 @@ workspace = true
|
|||
platform-tags = { workspace = true }
|
||||
pypi-types = { workspace = true }
|
||||
uv-fs = { workspace = true }
|
||||
uv-toolchain = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-version = { workspace = true }
|
||||
|
||||
fs-err = { workspace = true }
|
||||
|
|
|
@ -13,7 +13,7 @@ use tracing::info;
|
|||
|
||||
use pypi_types::Scheme;
|
||||
use uv_fs::{cachedir, Simplified};
|
||||
use uv_toolchain::{Interpreter, VirtualEnvironment};
|
||||
use uv_python::{Interpreter, VirtualEnvironment};
|
||||
use uv_version::version;
|
||||
|
||||
use crate::{Error, Prompt};
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::path::Path;
|
|||
use thiserror::Error;
|
||||
|
||||
use platform_tags::PlatformError;
|
||||
use uv_toolchain::{Interpreter, PythonEnvironment};
|
||||
use uv_python::{Interpreter, PythonEnvironment};
|
||||
|
||||
pub use crate::bare::create_bare_venv;
|
||||
|
||||
|
@ -15,9 +15,9 @@ pub enum Error {
|
|||
#[error(transparent)]
|
||||
IO(#[from] io::Error),
|
||||
#[error("Failed to determine Python interpreter to use")]
|
||||
Discovery(#[from] uv_toolchain::DiscoveryError),
|
||||
Discovery(#[from] uv_python::DiscoveryError),
|
||||
#[error("Failed to determine Python interpreter to use")]
|
||||
InterpreterNotFound(#[from] uv_toolchain::ToolchainNotFound),
|
||||
InterpreterNotFound(#[from] uv_python::PythonNotFound),
|
||||
#[error(transparent)]
|
||||
Platform(#[from] PlatformError),
|
||||
#[error("Could not find a suitable Python executable for the virtual environment based on the interpreter: {0}")]
|
||||
|
|
|
@ -36,7 +36,7 @@ uv-resolver = { workspace = true }
|
|||
uv-scripts = { workspace = true }
|
||||
uv-settings = { workspace = true, features = ["schemars"] }
|
||||
uv-tool = { workspace = true }
|
||||
uv-toolchain = { workspace = true, features = ["schemars"]}
|
||||
uv-python = { workspace = true, features = ["schemars"]}
|
||||
uv-types = { workspace = true }
|
||||
uv-virtualenv = { workspace = true }
|
||||
uv-warnings = { workspace = true }
|
||||
|
|
|
@ -22,6 +22,11 @@ pub(crate) use project::lock::lock;
|
|||
pub(crate) use project::remove::remove;
|
||||
pub(crate) use project::run::run;
|
||||
pub(crate) use project::sync::sync;
|
||||
pub(crate) use python::dir::dir as python_dir;
|
||||
pub(crate) use python::find::find as python_find;
|
||||
pub(crate) use python::install::install as python_install;
|
||||
pub(crate) use python::list::list as python_list;
|
||||
pub(crate) use python::uninstall::uninstall as python_uninstall;
|
||||
#[cfg(feature = "self-update")]
|
||||
pub(crate) use self_update::self_update;
|
||||
pub(crate) use tool::dir::dir as tool_dir;
|
||||
|
@ -29,16 +34,11 @@ pub(crate) use tool::install::install as tool_install;
|
|||
pub(crate) use tool::list::list as tool_list;
|
||||
pub(crate) use tool::run::run as tool_run;
|
||||
pub(crate) use tool::uninstall::uninstall as tool_uninstall;
|
||||
pub(crate) use toolchain::dir::dir as toolchain_dir;
|
||||
pub(crate) use toolchain::find::find as toolchain_find;
|
||||
pub(crate) use toolchain::install::install as toolchain_install;
|
||||
pub(crate) use toolchain::list::list as toolchain_list;
|
||||
pub(crate) use toolchain::uninstall::uninstall as toolchain_uninstall;
|
||||
use uv_cache::Cache;
|
||||
use uv_fs::Simplified;
|
||||
use uv_installer::compile_tree;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_toolchain::PythonEnvironment;
|
||||
use uv_python::PythonEnvironment;
|
||||
pub(crate) use venv::venv;
|
||||
pub(crate) use version::version;
|
||||
|
||||
|
@ -49,9 +49,9 @@ mod cache_dir;
|
|||
mod cache_prune;
|
||||
pub(crate) mod pip;
|
||||
mod project;
|
||||
mod python;
|
||||
pub(crate) mod reporters;
|
||||
mod tool;
|
||||
mod toolchain;
|
||||
|
||||
#[cfg(feature = "self-update")]
|
||||
mod self_update;
|
||||
|
|
|
@ -10,7 +10,7 @@ use uv_cache::Cache;
|
|||
use uv_configuration::PreviewMode;
|
||||
use uv_fs::Simplified;
|
||||
use uv_installer::{SitePackages, SitePackagesDiagnostic};
|
||||
use uv_toolchain::{EnvironmentPreference, PythonEnvironment, ToolchainRequest};
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
|
||||
use crate::commands::{elapsed, ExitStatus};
|
||||
use crate::printer::Printer;
|
||||
|
@ -27,7 +27,7 @@ pub(crate) fn pip_check(
|
|||
|
||||
// Detect the current Python interpreter.
|
||||
let environment = PythonEnvironment::find(
|
||||
&python.map(ToolchainRequest::parse).unwrap_or_default(),
|
||||
&python.map(PythonRequest::parse).unwrap_or_default(),
|
||||
EnvironmentPreference::from_system_flag(system, false),
|
||||
cache,
|
||||
)?;
|
||||
|
|
|
@ -23,6 +23,10 @@ use uv_dispatch::BuildDispatch;
|
|||
use uv_fs::Simplified;
|
||||
use uv_git::GitResolver;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_python::{
|
||||
EnvironmentPreference, PythonEnvironment, PythonInstallation, PythonPreference, PythonRequest,
|
||||
PythonVersion, VersionRequest,
|
||||
};
|
||||
use uv_requirements::{
|
||||
upgrade::read_requirements_txt, RequirementsSource, RequirementsSpecification,
|
||||
};
|
||||
|
@ -31,10 +35,6 @@ use uv_resolver::{
|
|||
InMemoryIndex, OptionsBuilder, PreReleaseMode, PythonRequirement, RequiresPython,
|
||||
ResolutionMode,
|
||||
};
|
||||
use uv_toolchain::{
|
||||
EnvironmentPreference, PythonEnvironment, PythonVersion, Toolchain, ToolchainPreference,
|
||||
ToolchainRequest, VersionRequest,
|
||||
};
|
||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
|
||||
use uv_warnings::warn_user;
|
||||
|
||||
|
@ -83,7 +83,7 @@ pub(crate) async fn pip_compile(
|
|||
link_mode: LinkMode,
|
||||
python: Option<String>,
|
||||
system: bool,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
python_preference: PythonPreference,
|
||||
concurrency: Concurrency,
|
||||
native_tls: bool,
|
||||
quiet: bool,
|
||||
|
@ -159,18 +159,18 @@ pub(crate) async fn pip_compile(
|
|||
// Find an interpreter to use for building distributions
|
||||
let environments = EnvironmentPreference::from_system_flag(system, false);
|
||||
let interpreter = if let Some(python) = python.as_ref() {
|
||||
let request = ToolchainRequest::parse(python);
|
||||
Toolchain::find(&request, environments, toolchain_preference, &cache)
|
||||
let request = PythonRequest::parse(python);
|
||||
PythonInstallation::find(&request, environments, python_preference, &cache)
|
||||
} else {
|
||||
// TODO(zanieb): The split here hints at a problem with the abstraction; we should be able to use
|
||||
// `Toolchain::find(...)` here.
|
||||
// `PythonInstallation::find(...)` here.
|
||||
let request = if let Some(version) = python_version.as_ref() {
|
||||
// TODO(zanieb): We should consolidate `VersionRequest` and `PythonVersion`
|
||||
ToolchainRequest::Version(VersionRequest::from(version))
|
||||
PythonRequest::Version(VersionRequest::from(version))
|
||||
} else {
|
||||
ToolchainRequest::default()
|
||||
PythonRequest::default()
|
||||
};
|
||||
Toolchain::find_best(&request, environments, toolchain_preference, &cache)
|
||||
PythonInstallation::find_best(&request, environments, python_preference, &cache)
|
||||
}?
|
||||
.into_interpreter();
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use uv_cache::Cache;
|
|||
use uv_configuration::PreviewMode;
|
||||
use uv_fs::Simplified;
|
||||
use uv_installer::SitePackages;
|
||||
use uv_toolchain::{EnvironmentPreference, PythonEnvironment, ToolchainRequest};
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
|
@ -27,7 +27,7 @@ pub(crate) fn pip_freeze(
|
|||
) -> Result<ExitStatus> {
|
||||
// Detect the current Python interpreter.
|
||||
let environment = PythonEnvironment::find(
|
||||
&python.map(ToolchainRequest::parse).unwrap_or_default(),
|
||||
&python.map(PythonRequest::parse).unwrap_or_default(),
|
||||
EnvironmentPreference::from_system_flag(system, false),
|
||||
cache,
|
||||
)?;
|
||||
|
|
|
@ -20,14 +20,14 @@ use uv_dispatch::BuildDispatch;
|
|||
use uv_fs::Simplified;
|
||||
use uv_git::GitResolver;
|
||||
use uv_installer::{SatisfiesResult, SitePackages};
|
||||
use uv_python::{
|
||||
EnvironmentPreference, Prefix, PythonEnvironment, PythonRequest, PythonVersion, Target,
|
||||
};
|
||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||
use uv_resolver::{
|
||||
DependencyMode, ExcludeNewer, FlatIndex, InMemoryIndex, OptionsBuilder, PreReleaseMode,
|
||||
PythonRequirement, ResolutionMode,
|
||||
};
|
||||
use uv_toolchain::{
|
||||
EnvironmentPreference, Prefix, PythonEnvironment, PythonVersion, Target, ToolchainRequest,
|
||||
};
|
||||
use uv_types::{BuildIsolation, HashStrategy, InFlight};
|
||||
|
||||
use crate::commands::pip::operations::Modifications;
|
||||
|
@ -119,7 +119,7 @@ pub(crate) async fn pip_install(
|
|||
let environment = PythonEnvironment::find(
|
||||
&python
|
||||
.as_deref()
|
||||
.map(ToolchainRequest::parse)
|
||||
.map(PythonRequest::parse)
|
||||
.unwrap_or_default(),
|
||||
EnvironmentPreference::from_system_flag(system, true),
|
||||
&cache,
|
||||
|
|
|
@ -15,8 +15,8 @@ use uv_configuration::PreviewMode;
|
|||
use uv_fs::Simplified;
|
||||
use uv_installer::SitePackages;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_toolchain::ToolchainRequest;
|
||||
use uv_toolchain::{EnvironmentPreference, PythonEnvironment};
|
||||
use uv_python::PythonRequest;
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment};
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
|
@ -37,7 +37,7 @@ pub(crate) fn pip_list(
|
|||
) -> Result<ExitStatus> {
|
||||
// Detect the current Python interpreter.
|
||||
let environment = PythonEnvironment::find(
|
||||
&python.map(ToolchainRequest::parse).unwrap_or_default(),
|
||||
&python.map(PythonRequest::parse).unwrap_or_default(),
|
||||
EnvironmentPreference::from_system_flag(system, false),
|
||||
cache,
|
||||
)?;
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::borrow::Cow;
|
|||
use pep508_rs::MarkerEnvironment;
|
||||
use platform_tags::{Tags, TagsError};
|
||||
use uv_configuration::TargetTriple;
|
||||
use uv_toolchain::{Interpreter, PythonVersion};
|
||||
use uv_python::{Interpreter, PythonVersion};
|
||||
|
||||
pub(crate) mod check;
|
||||
pub(crate) mod compile;
|
||||
|
|
|
@ -29,6 +29,7 @@ use uv_distribution::DistributionDatabase;
|
|||
use uv_fs::Simplified;
|
||||
use uv_installer::{Plan, Planner, Preparer, SitePackages};
|
||||
use uv_normalize::{GroupName, PackageName};
|
||||
use uv_python::PythonEnvironment;
|
||||
use uv_requirements::{
|
||||
LookaheadResolver, NamedRequirementsResolver, RequirementsSource, RequirementsSpecification,
|
||||
SourceTreeResolver,
|
||||
|
@ -37,7 +38,6 @@ use uv_resolver::{
|
|||
DependencyMode, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options, Preference,
|
||||
Preferences, PythonRequirement, ResolutionGraph, Resolver,
|
||||
};
|
||||
use uv_toolchain::PythonEnvironment;
|
||||
use uv_types::{HashStrategy, InFlight, InstalledPackagesProvider};
|
||||
use uv_warnings::warn_user;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ use uv_configuration::PreviewMode;
|
|||
use uv_fs::Simplified;
|
||||
use uv_installer::SitePackages;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_toolchain::{EnvironmentPreference, PythonEnvironment, ToolchainRequest};
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
|
@ -42,7 +42,7 @@ pub(crate) fn pip_show(
|
|||
|
||||
// Detect the current Python interpreter.
|
||||
let environment = PythonEnvironment::find(
|
||||
&python.map(ToolchainRequest::parse).unwrap_or_default(),
|
||||
&python.map(PythonRequest::parse).unwrap_or_default(),
|
||||
EnvironmentPreference::from_system_flag(system, false),
|
||||
cache,
|
||||
)?;
|
||||
|
|
|
@ -19,14 +19,14 @@ use uv_dispatch::BuildDispatch;
|
|||
use uv_fs::Simplified;
|
||||
use uv_git::GitResolver;
|
||||
use uv_installer::SitePackages;
|
||||
use uv_python::{
|
||||
EnvironmentPreference, Prefix, PythonEnvironment, PythonRequest, PythonVersion, Target,
|
||||
};
|
||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||
use uv_resolver::{
|
||||
DependencyMode, ExcludeNewer, FlatIndex, InMemoryIndex, OptionsBuilder, PreReleaseMode,
|
||||
PythonRequirement, ResolutionMode,
|
||||
};
|
||||
use uv_toolchain::{
|
||||
EnvironmentPreference, Prefix, PythonEnvironment, PythonVersion, Target, ToolchainRequest,
|
||||
};
|
||||
use uv_types::{BuildIsolation, HashStrategy, InFlight};
|
||||
|
||||
use crate::commands::pip::operations::Modifications;
|
||||
|
@ -117,7 +117,7 @@ pub(crate) async fn pip_sync(
|
|||
let environment = PythonEnvironment::find(
|
||||
&python
|
||||
.as_deref()
|
||||
.map(ToolchainRequest::parse)
|
||||
.map(PythonRequest::parse)
|
||||
.unwrap_or_default(),
|
||||
EnvironmentPreference::from_system_flag(system, true),
|
||||
&cache,
|
||||
|
|
|
@ -13,9 +13,9 @@ use uv_cache::Cache;
|
|||
use uv_fs::Simplified;
|
||||
use uv_installer::SitePackages;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_toolchain::EnvironmentPreference;
|
||||
use uv_toolchain::PythonEnvironment;
|
||||
use uv_toolchain::ToolchainRequest;
|
||||
use uv_python::EnvironmentPreference;
|
||||
use uv_python::PythonEnvironment;
|
||||
use uv_python::PythonRequest;
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
|
@ -36,7 +36,7 @@ pub(crate) fn pip_tree(
|
|||
) -> Result<ExitStatus> {
|
||||
// Detect the current Python interpreter.
|
||||
let environment = PythonEnvironment::find(
|
||||
&python.map(ToolchainRequest::parse).unwrap_or_default(),
|
||||
&python.map(PythonRequest::parse).unwrap_or_default(),
|
||||
EnvironmentPreference::from_system_flag(system, false),
|
||||
cache,
|
||||
)?;
|
||||
|
|
|
@ -13,10 +13,10 @@ use uv_cache::Cache;
|
|||
use uv_client::{BaseClientBuilder, Connectivity};
|
||||
use uv_configuration::{KeyringProviderType, PreviewMode};
|
||||
use uv_fs::Simplified;
|
||||
use uv_python::EnvironmentPreference;
|
||||
use uv_python::PythonRequest;
|
||||
use uv_python::{Prefix, PythonEnvironment, Target};
|
||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||
use uv_toolchain::EnvironmentPreference;
|
||||
use uv_toolchain::ToolchainRequest;
|
||||
use uv_toolchain::{Prefix, PythonEnvironment, Target};
|
||||
|
||||
use crate::commands::{elapsed, ExitStatus};
|
||||
use crate::printer::Printer;
|
||||
|
@ -49,7 +49,7 @@ pub(crate) async fn pip_uninstall(
|
|||
let environment = PythonEnvironment::find(
|
||||
&python
|
||||
.as_deref()
|
||||
.map(ToolchainRequest::parse)
|
||||
.map(PythonRequest::parse)
|
||||
.unwrap_or_default(),
|
||||
EnvironmentPreference::from_system_flag(system, true),
|
||||
&cache,
|
||||
|
|
|
@ -10,9 +10,9 @@ use uv_distribution::pyproject_mut::PyProjectTomlMut;
|
|||
use uv_distribution::{DistributionDatabase, ProjectWorkspace, VirtualProject, Workspace};
|
||||
use uv_git::GitResolver;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_python::{PythonFetch, PythonPreference, PythonRequest};
|
||||
use uv_requirements::{NamedRequirementsResolver, RequirementsSource, RequirementsSpecification};
|
||||
use uv_resolver::{FlatIndex, InMemoryIndex};
|
||||
use uv_toolchain::{ToolchainFetch, ToolchainPreference, ToolchainRequest};
|
||||
use uv_types::{BuildIsolation, HashStrategy, InFlight};
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
|
@ -38,8 +38,8 @@ pub(crate) async fn add(
|
|||
package: Option<PackageName>,
|
||||
python: Option<String>,
|
||||
settings: ResolverInstallerSettings,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
preview: PreviewMode,
|
||||
connectivity: Connectivity,
|
||||
concurrency: Concurrency,
|
||||
|
@ -64,9 +64,9 @@ pub(crate) async fn add(
|
|||
// Discover or create the virtual environment.
|
||||
let venv = project::get_or_init_environment(
|
||||
project.workspace(),
|
||||
python.as_deref().map(ToolchainRequest::parse),
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
python_preference,
|
||||
python_fetch,
|
||||
connectivity,
|
||||
native_tls,
|
||||
cache,
|
||||
|
|
|
@ -7,9 +7,9 @@ use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode, Reinstall,
|
|||
use uv_dispatch::BuildDispatch;
|
||||
use uv_distribution::{Workspace, DEV_DEPENDENCIES};
|
||||
use uv_git::ResolvedRepositoryReference;
|
||||
use uv_python::{Interpreter, PythonFetch, PythonPreference, PythonRequest};
|
||||
use uv_requirements::upgrade::{read_lockfile, LockedRequirements};
|
||||
use uv_resolver::{FlatIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython};
|
||||
use uv_toolchain::{Interpreter, ToolchainFetch, ToolchainPreference, ToolchainRequest};
|
||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
|
||||
|
@ -23,8 +23,8 @@ pub(crate) async fn lock(
|
|||
python: Option<String>,
|
||||
settings: ResolverSettings,
|
||||
preview: PreviewMode,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
connectivity: Connectivity,
|
||||
concurrency: Concurrency,
|
||||
native_tls: bool,
|
||||
|
@ -41,9 +41,9 @@ pub(crate) async fn lock(
|
|||
// Find an interpreter for the project
|
||||
let interpreter = FoundInterpreter::discover(
|
||||
&workspace,
|
||||
python.as_deref().map(ToolchainRequest::parse),
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
python_preference,
|
||||
python_fetch,
|
||||
connectivity,
|
||||
native_tls,
|
||||
cache,
|
||||
|
|
|
@ -15,12 +15,12 @@ use uv_distribution::{DistributionDatabase, Workspace};
|
|||
use uv_fs::Simplified;
|
||||
use uv_git::GitResolver;
|
||||
use uv_installer::{SatisfiesResult, SitePackages};
|
||||
use uv_python::{
|
||||
request_from_version_file, EnvironmentPreference, Interpreter, PythonEnvironment, PythonFetch,
|
||||
PythonInstallation, PythonPreference, PythonRequest, VersionRequest,
|
||||
};
|
||||
use uv_requirements::{NamedRequirementsResolver, RequirementsSpecification};
|
||||
use uv_resolver::{FlatIndex, InMemoryIndex, OptionsBuilder, PythonRequirement, RequiresPython};
|
||||
use uv_toolchain::{
|
||||
request_from_version_file, EnvironmentPreference, Interpreter, PythonEnvironment, Toolchain,
|
||||
ToolchainFetch, ToolchainPreference, ToolchainRequest, VersionRequest,
|
||||
};
|
||||
use uv_types::{BuildIsolation, HashStrategy, InFlight};
|
||||
|
||||
use crate::commands::pip;
|
||||
|
@ -44,7 +44,7 @@ pub(crate) enum ProjectError {
|
|||
RequestedPythonIncompatibility(Version, RequiresPython),
|
||||
|
||||
#[error(transparent)]
|
||||
Toolchain(#[from] uv_toolchain::Error),
|
||||
Python(#[from] uv_python::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
Virtualenv(#[from] uv_virtualenv::Error),
|
||||
|
@ -94,14 +94,14 @@ pub(crate) fn find_requires_python(
|
|||
fn find_environment(
|
||||
workspace: &Workspace,
|
||||
cache: &Cache,
|
||||
) -> Result<PythonEnvironment, uv_toolchain::Error> {
|
||||
) -> Result<PythonEnvironment, uv_python::Error> {
|
||||
PythonEnvironment::from_root(workspace.venv(), cache)
|
||||
}
|
||||
|
||||
/// Check if the given interpreter satisfies the project's requirements.
|
||||
fn interpreter_meets_requirements(
|
||||
interpreter: &Interpreter,
|
||||
requested_python: Option<&ToolchainRequest>,
|
||||
requested_python: Option<&PythonRequest>,
|
||||
cache: &Cache,
|
||||
) -> bool {
|
||||
let Some(request) = requested_python else {
|
||||
|
@ -126,9 +126,9 @@ impl FoundInterpreter {
|
|||
/// Discover the interpreter to use in the current [`Workspace`].
|
||||
pub(crate) async fn discover(
|
||||
workspace: &Workspace,
|
||||
python_request: Option<ToolchainRequest>,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_request: Option<PythonRequest>,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
connectivity: Connectivity,
|
||||
native_tls: bool,
|
||||
cache: &Cache,
|
||||
|
@ -147,9 +147,7 @@ impl FoundInterpreter {
|
|||
requires_python
|
||||
.as_ref()
|
||||
.map(RequiresPython::specifiers)
|
||||
.map(|specifiers| {
|
||||
ToolchainRequest::Version(VersionRequest::Range(specifiers.clone()))
|
||||
})
|
||||
.map(|specifiers| PythonRequest::Version(VersionRequest::Range(specifiers.clone())))
|
||||
};
|
||||
|
||||
// Read from the virtual environment first.
|
||||
|
@ -172,7 +170,7 @@ impl FoundInterpreter {
|
|||
}
|
||||
}
|
||||
}
|
||||
Err(uv_toolchain::Error::MissingEnvironment(_)) => {}
|
||||
Err(uv_python::Error::MissingEnvironment(_)) => {}
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
|
||||
|
@ -181,11 +179,11 @@ impl FoundInterpreter {
|
|||
.native_tls(native_tls);
|
||||
|
||||
// Locate the Python interpreter to use in the environment
|
||||
let interpreter = Toolchain::find_or_fetch(
|
||||
let interpreter = PythonInstallation::find_or_fetch(
|
||||
python_request,
|
||||
EnvironmentPreference::OnlySystem,
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
&client_builder,
|
||||
cache,
|
||||
)
|
||||
|
@ -223,9 +221,9 @@ impl FoundInterpreter {
|
|||
/// Initialize a virtual environment for the current project.
|
||||
pub(crate) async fn get_or_init_environment(
|
||||
workspace: &Workspace,
|
||||
python: Option<ToolchainRequest>,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python: Option<PythonRequest>,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
connectivity: Connectivity,
|
||||
native_tls: bool,
|
||||
cache: &Cache,
|
||||
|
@ -234,8 +232,8 @@ pub(crate) async fn get_or_init_environment(
|
|||
match FoundInterpreter::discover(
|
||||
workspace,
|
||||
python,
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
connectivity,
|
||||
native_tls,
|
||||
cache,
|
||||
|
|
|
@ -7,7 +7,7 @@ use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode};
|
|||
use uv_distribution::pyproject::DependencyType;
|
||||
use uv_distribution::pyproject_mut::PyProjectTomlMut;
|
||||
use uv_distribution::{ProjectWorkspace, VirtualProject, Workspace};
|
||||
use uv_toolchain::{ToolchainFetch, ToolchainPreference, ToolchainRequest};
|
||||
use uv_python::{PythonFetch, PythonPreference, PythonRequest};
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
|
||||
use crate::commands::pip::operations::Modifications;
|
||||
|
@ -22,8 +22,8 @@ pub(crate) async fn remove(
|
|||
dependency_type: DependencyType,
|
||||
package: Option<PackageName>,
|
||||
python: Option<String>,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
preview: PreviewMode,
|
||||
connectivity: Connectivity,
|
||||
concurrency: Concurrency,
|
||||
|
@ -85,9 +85,9 @@ pub(crate) async fn remove(
|
|||
// Discover or create the virtual environment.
|
||||
let venv = project::get_or_init_environment(
|
||||
project.workspace(),
|
||||
python.as_deref().map(ToolchainRequest::parse),
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
python_preference,
|
||||
python_fetch,
|
||||
connectivity,
|
||||
native_tls,
|
||||
cache,
|
||||
|
|
|
@ -13,11 +13,11 @@ use uv_client::{BaseClientBuilder, Connectivity};
|
|||
use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode};
|
||||
use uv_distribution::{VirtualProject, Workspace, WorkspaceError};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||
use uv_toolchain::{
|
||||
request_from_version_file, EnvironmentPreference, Interpreter, PythonEnvironment, Toolchain,
|
||||
ToolchainFetch, ToolchainPreference, ToolchainRequest, VersionRequest,
|
||||
use uv_python::{
|
||||
request_from_version_file, EnvironmentPreference, Interpreter, PythonEnvironment, PythonFetch,
|
||||
PythonInstallation, PythonPreference, PythonRequest, VersionRequest,
|
||||
};
|
||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::pip::operations::Modifications;
|
||||
|
@ -37,8 +37,8 @@ pub(crate) async fn run(
|
|||
settings: ResolverInstallerSettings,
|
||||
isolated: bool,
|
||||
preview: PreviewMode,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
connectivity: Connectivity,
|
||||
concurrency: Concurrency,
|
||||
native_tls: bool,
|
||||
|
@ -71,14 +71,14 @@ pub(crate) async fn run(
|
|||
|
||||
// (1) Explicit request from user
|
||||
let python_request = if let Some(request) = python.as_deref() {
|
||||
Some(ToolchainRequest::parse(request))
|
||||
Some(PythonRequest::parse(request))
|
||||
// (2) Request from `.python-version`
|
||||
} else if let Some(request) = request_from_version_file().await? {
|
||||
Some(request)
|
||||
// (3) `Requires-Python` in `pyproject.toml`
|
||||
} else {
|
||||
metadata.requires_python.map(|requires_python| {
|
||||
ToolchainRequest::Version(VersionRequest::Range(requires_python))
|
||||
PythonRequest::Version(VersionRequest::Range(requires_python))
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -86,11 +86,11 @@ pub(crate) async fn run(
|
|||
.connectivity(connectivity)
|
||||
.native_tls(native_tls);
|
||||
|
||||
let interpreter = Toolchain::find_or_fetch(
|
||||
let interpreter = PythonInstallation::find_or_fetch(
|
||||
python_request,
|
||||
EnvironmentPreference::Any,
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
&client_builder,
|
||||
cache,
|
||||
)
|
||||
|
@ -171,9 +171,9 @@ pub(crate) async fn run(
|
|||
|
||||
let venv = project::get_or_init_environment(
|
||||
project.workspace(),
|
||||
python.as_deref().map(ToolchainRequest::parse),
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
python_preference,
|
||||
python_fetch,
|
||||
connectivity,
|
||||
native_tls,
|
||||
cache,
|
||||
|
@ -221,18 +221,18 @@ pub(crate) async fn run(
|
|||
.connectivity(connectivity)
|
||||
.native_tls(native_tls);
|
||||
|
||||
let toolchain = Toolchain::find_or_fetch(
|
||||
python.as_deref().map(ToolchainRequest::parse),
|
||||
let python = PythonInstallation::find_or_fetch(
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
// No opt-in is required for system environments, since we are not mutating it.
|
||||
EnvironmentPreference::Any,
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
&client_builder,
|
||||
cache,
|
||||
)
|
||||
.await?;
|
||||
|
||||
toolchain.into_interpreter()
|
||||
python.into_interpreter()
|
||||
};
|
||||
|
||||
Some(interpreter)
|
||||
|
@ -262,11 +262,11 @@ pub(crate) async fn run(
|
|||
.native_tls(native_tls);
|
||||
|
||||
// Note we force preview on during `uv run` for now since the entire interface is in preview
|
||||
Toolchain::find_or_fetch(
|
||||
python.as_deref().map(ToolchainRequest::parse),
|
||||
PythonInstallation::find_or_fetch(
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
EnvironmentPreference::Any,
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
&client_builder,
|
||||
cache,
|
||||
)
|
||||
|
|
|
@ -6,8 +6,8 @@ use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode, SetupPyStr
|
|||
use uv_dispatch::BuildDispatch;
|
||||
use uv_distribution::{VirtualProject, DEV_DEPENDENCIES};
|
||||
use uv_installer::SitePackages;
|
||||
use uv_python::{PythonEnvironment, PythonFetch, PythonPreference, PythonRequest};
|
||||
use uv_resolver::{FlatIndex, Lock};
|
||||
use uv_toolchain::{PythonEnvironment, ToolchainFetch, ToolchainPreference, ToolchainRequest};
|
||||
use uv_types::{BuildIsolation, HashStrategy, InFlight};
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
|
@ -23,8 +23,8 @@ pub(crate) async fn sync(
|
|||
dev: bool,
|
||||
modifications: Modifications,
|
||||
python: Option<String>,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
settings: InstallerSettings,
|
||||
preview: PreviewMode,
|
||||
connectivity: Connectivity,
|
||||
|
@ -43,9 +43,9 @@ pub(crate) async fn sync(
|
|||
// Discover or create the virtual environment.
|
||||
let venv = project::get_or_init_environment(
|
||||
project.workspace(),
|
||||
python.as_deref().map(ToolchainRequest::parse),
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
python_preference,
|
||||
python_fetch,
|
||||
connectivity,
|
||||
native_tls,
|
||||
cache,
|
||||
|
|
|
@ -2,16 +2,16 @@ use anyhow::Context;
|
|||
use owo_colors::OwoColorize;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_fs::Simplified;
|
||||
use uv_toolchain::managed::InstalledToolchains;
|
||||
use uv_python::managed::ManagedPythonInstallations;
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
/// Show the toolchain directory.
|
||||
pub(crate) fn dir(preview: PreviewMode) -> anyhow::Result<()> {
|
||||
if preview.is_disabled() {
|
||||
warn_user_once!("`uv toolchain dir` is experimental and may change without warning.");
|
||||
warn_user_once!("`uv python dir` is experimental and may change without warning.");
|
||||
}
|
||||
let installed_toolchains =
|
||||
InstalledToolchains::from_settings().context("Failed to initialize toolchain settings")?;
|
||||
let installed_toolchains = ManagedPythonInstallations::from_settings()
|
||||
.context("Failed to initialize toolchain settings")?;
|
||||
anstream::println!(
|
||||
"{}",
|
||||
installed_toolchains.root().simplified_display().cyan()
|
|
@ -4,39 +4,39 @@ use std::fmt::Write;
|
|||
use uv_cache::Cache;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_fs::Simplified;
|
||||
use uv_toolchain::{EnvironmentPreference, Toolchain, ToolchainPreference, ToolchainRequest};
|
||||
use uv_python::{EnvironmentPreference, PythonInstallation, PythonPreference, PythonRequest};
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
|
||||
/// Find a toolchain.
|
||||
/// Find a Python interpreter.
|
||||
pub(crate) async fn find(
|
||||
request: Option<String>,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
python_preference: PythonPreference,
|
||||
preview: PreviewMode,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
) -> Result<ExitStatus> {
|
||||
if preview.is_disabled() {
|
||||
warn_user_once!("`uv toolchain find` is experimental and may change without warning.");
|
||||
warn_user_once!("`uv python find` is experimental and may change without warning.");
|
||||
}
|
||||
|
||||
let request = match request {
|
||||
Some(request) => ToolchainRequest::parse(&request),
|
||||
None => ToolchainRequest::Any,
|
||||
Some(request) => PythonRequest::parse(&request),
|
||||
None => PythonRequest::Any,
|
||||
};
|
||||
let toolchain = Toolchain::find(
|
||||
let python = PythonInstallation::find(
|
||||
&request,
|
||||
EnvironmentPreference::OnlySystem,
|
||||
toolchain_preference,
|
||||
python_preference,
|
||||
cache,
|
||||
)?;
|
||||
|
||||
writeln!(
|
||||
printer.stdout(),
|
||||
"{}",
|
||||
toolchain.interpreter().sys_executable().user_display()
|
||||
python.interpreter().sys_executable().user_display()
|
||||
)?;
|
||||
|
||||
Ok(ExitStatus::Success)
|
|
@ -5,15 +5,15 @@ use uv_cache::Cache;
|
|||
use uv_client::Connectivity;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_fs::Simplified;
|
||||
use uv_toolchain::downloads::{self, DownloadResult, PythonDownload, PythonDownloadRequest};
|
||||
use uv_toolchain::managed::{InstalledToolchain, InstalledToolchains};
|
||||
use uv_toolchain::{requests_from_version_file, ToolchainRequest};
|
||||
use uv_python::downloads::{self, DownloadResult, ManagedPythonDownload, PythonDownloadRequest};
|
||||
use uv_python::managed::{ManagedPythonInstallation, ManagedPythonInstallations};
|
||||
use uv_python::{requests_from_version_file, PythonRequest};
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
|
||||
/// Download and install a Python toolchain.
|
||||
/// Download and install Python versions.
|
||||
pub(crate) async fn install(
|
||||
targets: Vec<String>,
|
||||
force: bool,
|
||||
|
@ -24,25 +24,25 @@ pub(crate) async fn install(
|
|||
printer: Printer,
|
||||
) -> Result<ExitStatus> {
|
||||
if preview.is_disabled() {
|
||||
warn_user_once!("`uv toolchain install` is experimental and may change without warning.");
|
||||
warn_user_once!("`uv python install` is experimental and may change without warning.");
|
||||
}
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
let toolchains = InstalledToolchains::from_settings()?.init()?;
|
||||
let toolchain_dir = toolchains.root();
|
||||
let _lock = toolchains.acquire_lock()?;
|
||||
let installations = ManagedPythonInstallations::from_settings()?.init()?;
|
||||
let installations_dir = installations.root();
|
||||
let _lock = installations.acquire_lock()?;
|
||||
|
||||
let requests: Vec<_> = if targets.is_empty() {
|
||||
if let Some(requests) = requests_from_version_file().await? {
|
||||
requests
|
||||
} else {
|
||||
vec![ToolchainRequest::Any]
|
||||
vec![PythonRequest::Any]
|
||||
}
|
||||
} else {
|
||||
targets
|
||||
.iter()
|
||||
.map(|target| ToolchainRequest::parse(target.as_str()))
|
||||
.map(|target| PythonRequest::parse(target.as_str()))
|
||||
.collect()
|
||||
};
|
||||
|
||||
|
@ -51,21 +51,21 @@ pub(crate) async fn install(
|
|||
.map(PythonDownloadRequest::from_request)
|
||||
.collect::<Result<Vec<_>, downloads::Error>>()?;
|
||||
|
||||
let installed_toolchains: Vec<_> = toolchains.find_all()?.collect();
|
||||
let installed_installations: Vec<_> = installations.find_all()?.collect();
|
||||
let mut unfilled_requests = Vec::new();
|
||||
for (request, download_request) in requests.iter().zip(download_requests) {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Looking for toolchain {request} ({download_request})"
|
||||
"Looking for installation {request} ({download_request})"
|
||||
)?;
|
||||
if let Some(toolchain) = installed_toolchains
|
||||
if let Some(installation) = installed_installations
|
||||
.iter()
|
||||
.find(|toolchain| download_request.satisfied_by_key(toolchain.key()))
|
||||
.find(|installation| download_request.satisfied_by_key(installation.key()))
|
||||
{
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Found installed toolchain `{}` that satisfies {request}",
|
||||
toolchain.key()
|
||||
"Found installed installation `{}` that satisfies {request}",
|
||||
installation.key()
|
||||
)?;
|
||||
if force {
|
||||
unfilled_requests.push(download_request);
|
||||
|
@ -76,18 +76,21 @@ pub(crate) async fn install(
|
|||
}
|
||||
|
||||
if unfilled_requests.is_empty() {
|
||||
if matches!(requests.as_slice(), [ToolchainRequest::Any]) {
|
||||
if matches!(requests.as_slice(), [PythonRequest::Any]) {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"A toolchain is already installed. Use `uv toolchain install <request>` to install a specific toolchain.",
|
||||
"A installation is already installed. Use `uv installation install <request>` to install a specific installation.",
|
||||
)?;
|
||||
} else if requests.len() > 1 {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"All requested toolchains already installed."
|
||||
"All requested installations already installed."
|
||||
)?;
|
||||
} else {
|
||||
writeln!(printer.stderr(), "Requested toolchain already installed.")?;
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Requested installation already installed."
|
||||
)?;
|
||||
}
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
|
@ -95,7 +98,7 @@ pub(crate) async fn install(
|
|||
if unfilled_requests.len() > 1 {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Found {}/{} toolchains requiring installation",
|
||||
"Found {}/{} installations requiring installation",
|
||||
unfilled_requests.len(),
|
||||
requests.len()
|
||||
)?;
|
||||
|
@ -105,8 +108,8 @@ pub(crate) async fn install(
|
|||
.into_iter()
|
||||
// Populate the download requests with defaults
|
||||
.map(PythonDownloadRequest::fill)
|
||||
.map(|request| PythonDownload::from_request(&request))
|
||||
.collect::<Result<Vec<_>, uv_toolchain::downloads::Error>>()?;
|
||||
.map(|request| ManagedPythonDownload::from_request(&request))
|
||||
.collect::<Result<Vec<_>, uv_python::downloads::Error>>()?;
|
||||
|
||||
// Construct a client
|
||||
let client = uv_client::BaseClientBuilder::new()
|
||||
|
@ -117,7 +120,7 @@ pub(crate) async fn install(
|
|||
let mut tasks = futures::stream::iter(downloads.iter())
|
||||
.map(|download| async {
|
||||
let _ = writeln!(printer.stderr(), "Downloading {}", download.key());
|
||||
let result = download.fetch(&client, toolchain_dir).await;
|
||||
let result = download.fetch(&client, installations_dir).await;
|
||||
(download.python_version(), result)
|
||||
})
|
||||
.buffered(4);
|
||||
|
@ -138,7 +141,7 @@ pub(crate) async fn install(
|
|||
}
|
||||
};
|
||||
// Ensure the installations have externally managed markers
|
||||
let installed = InstalledToolchain::new(path.clone())?;
|
||||
let installed = ManagedPythonInstallation::new(path.clone())?;
|
||||
installed.ensure_externally_managed()?;
|
||||
results.push((version, path));
|
||||
}
|
||||
|
@ -146,7 +149,7 @@ pub(crate) async fn install(
|
|||
let s = if downloads.len() == 1 { "" } else { "s" };
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Installed {} toolchain{s} in {}s",
|
||||
"Installed {} installation{s} in {}s",
|
||||
downloads.len(),
|
||||
start.elapsed().as_secs()
|
||||
)?;
|
|
@ -6,16 +6,16 @@ use anyhow::Result;
|
|||
use uv_cache::Cache;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_fs::Simplified;
|
||||
use uv_toolchain::downloads::PythonDownloadRequest;
|
||||
use uv_toolchain::{
|
||||
find_toolchains, DiscoveryError, EnvironmentPreference, Toolchain, ToolchainFetch,
|
||||
ToolchainNotFound, ToolchainPreference, ToolchainRequest, ToolchainSource,
|
||||
use uv_python::downloads::PythonDownloadRequest;
|
||||
use uv_python::{
|
||||
find_python_installations, DiscoveryError, EnvironmentPreference, PythonFetch,
|
||||
PythonInstallation, PythonNotFound, PythonPreference, PythonRequest, PythonSource,
|
||||
};
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
use crate::settings::ToolchainListKinds;
|
||||
use crate::settings::PythonListKinds;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
enum Kind {
|
||||
|
@ -24,26 +24,26 @@ enum Kind {
|
|||
System,
|
||||
}
|
||||
|
||||
/// List available toolchains.
|
||||
/// List available Python installations.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) async fn list(
|
||||
kinds: ToolchainListKinds,
|
||||
kinds: PythonListKinds,
|
||||
all_versions: bool,
|
||||
all_platforms: bool,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
preview: PreviewMode,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
) -> Result<ExitStatus> {
|
||||
if preview.is_disabled() {
|
||||
warn_user_once!("`uv toolchain list` is experimental and may change without warning.");
|
||||
warn_user_once!("`uv python list` is experimental and may change without warning.");
|
||||
}
|
||||
|
||||
let download_request = match kinds {
|
||||
ToolchainListKinds::Installed => None,
|
||||
ToolchainListKinds::Default => {
|
||||
if toolchain_fetch.is_automatic() {
|
||||
PythonListKinds::Installed => None,
|
||||
PythonListKinds::Default => {
|
||||
if python_fetch.is_automatic() {
|
||||
Some(if all_platforms {
|
||||
PythonDownloadRequest::default()
|
||||
} else {
|
||||
|
@ -58,14 +58,14 @@ pub(crate) async fn list(
|
|||
|
||||
let downloads = download_request
|
||||
.as_ref()
|
||||
.map(uv_toolchain::downloads::PythonDownloadRequest::iter_downloads)
|
||||
.map(uv_python::downloads::PythonDownloadRequest::iter_downloads)
|
||||
.into_iter()
|
||||
.flatten();
|
||||
|
||||
let installed = find_toolchains(
|
||||
&ToolchainRequest::Any,
|
||||
let installed = find_python_installations(
|
||||
&PythonRequest::Any,
|
||||
EnvironmentPreference::OnlySystem,
|
||||
toolchain_preference,
|
||||
python_preference,
|
||||
cache,
|
||||
)
|
||||
// Raise discovery errors if critical
|
||||
|
@ -75,24 +75,24 @@ pub(crate) async fn list(
|
|||
.err()
|
||||
.map_or(true, DiscoveryError::is_critical)
|
||||
})
|
||||
.collect::<Result<Vec<Result<Toolchain, ToolchainNotFound>>, DiscoveryError>>()?
|
||||
.collect::<Result<Vec<Result<PythonInstallation, PythonNotFound>>, DiscoveryError>>()?
|
||||
.into_iter()
|
||||
// Drop any "missing" toolchains
|
||||
// Drop any "missing" installations
|
||||
.filter_map(std::result::Result::ok);
|
||||
|
||||
let mut output = BTreeSet::new();
|
||||
for toolchain in installed {
|
||||
let kind = if matches!(toolchain.source(), ToolchainSource::Managed) {
|
||||
for installation in installed {
|
||||
let kind = if matches!(installation.source(), PythonSource::Managed) {
|
||||
Kind::Managed
|
||||
} else {
|
||||
Kind::System
|
||||
};
|
||||
output.insert((
|
||||
toolchain.python_version().clone(),
|
||||
toolchain.os().to_string(),
|
||||
toolchain.key().clone(),
|
||||
installation.python_version().clone(),
|
||||
installation.os().to_string(),
|
||||
installation.key().clone(),
|
||||
kind,
|
||||
Some(toolchain.interpreter().sys_executable().to_path_buf()),
|
||||
Some(installation.interpreter().sys_executable().to_path_buf()),
|
||||
));
|
||||
}
|
||||
for download in downloads {
|
124
crates/uv/src/commands/python/uninstall.rs
Normal file
124
crates/uv/src/commands/python/uninstall.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
use anyhow::Result;
|
||||
use futures::StreamExt;
|
||||
use itertools::Itertools;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::Write;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_python::downloads::{self, PythonDownloadRequest};
|
||||
use uv_python::managed::ManagedPythonInstallations;
|
||||
use uv_python::PythonRequest;
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
|
||||
/// Uninstall managed Python versions.
|
||||
pub(crate) async fn uninstall(
|
||||
targets: Vec<String>,
|
||||
preview: PreviewMode,
|
||||
printer: Printer,
|
||||
) -> Result<ExitStatus> {
|
||||
if preview.is_disabled() {
|
||||
warn_user_once!("`uv python uninstall` is experimental and may change without warning.");
|
||||
}
|
||||
|
||||
let installations = ManagedPythonInstallations::from_settings()?.init()?;
|
||||
let _lock = installations.acquire_lock()?;
|
||||
|
||||
let requests = targets
|
||||
.iter()
|
||||
.map(|target| PythonRequest::parse(target.as_str()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let download_requests = requests
|
||||
.iter()
|
||||
.map(PythonDownloadRequest::from_request)
|
||||
.collect::<Result<Vec<_>, downloads::Error>>()?;
|
||||
|
||||
let installed_installations: Vec<_> = installations.find_all()?.collect();
|
||||
let mut matching_installations = BTreeSet::default();
|
||||
for (request, download_request) in requests.iter().zip(download_requests) {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Looking for Python installations matching {request} ({download_request})"
|
||||
)?;
|
||||
let mut found = false;
|
||||
for installation in installed_installations
|
||||
.iter()
|
||||
.filter(|installation| download_request.satisfied_by_key(installation.key()))
|
||||
{
|
||||
found = true;
|
||||
if matching_installations.insert(installation.clone()) {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Found installation `{}` that matches {request}",
|
||||
installation.key()
|
||||
)?;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"No installations found matching {request}"
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
if matching_installations.is_empty() {
|
||||
if matches!(requests.as_slice(), [PythonRequest::Any]) {
|
||||
writeln!(printer.stderr(), "No installed installations found")?;
|
||||
} else if requests.len() > 1 {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"No installations found matching the requests"
|
||||
)?;
|
||||
} else {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"No installations found matching the request"
|
||||
)?;
|
||||
}
|
||||
return Ok(ExitStatus::Failure);
|
||||
}
|
||||
|
||||
let tasks = futures::stream::iter(matching_installations.iter())
|
||||
.map(|installation| async {
|
||||
(
|
||||
installation.key(),
|
||||
fs_err::tokio::remove_dir_all(installation.path()).await,
|
||||
)
|
||||
})
|
||||
.buffered(4);
|
||||
|
||||
let results = tasks.collect::<Vec<_>>().await;
|
||||
let mut failed = false;
|
||||
for (key, result) in results.iter().sorted_by_key(|(key, _)| key) {
|
||||
if let Err(err) = result {
|
||||
failed = true;
|
||||
writeln!(printer.stderr(), "Failed to uninstall `{key}`: {err}")?;
|
||||
} else {
|
||||
writeln!(printer.stderr(), "Uninstalled `{key}`")?;
|
||||
}
|
||||
}
|
||||
|
||||
if failed {
|
||||
if matching_installations.len() > 1 {
|
||||
writeln!(printer.stderr(), "Some Python uninstalls failed")?;
|
||||
}
|
||||
return Ok(ExitStatus::Failure);
|
||||
}
|
||||
|
||||
let s = if matching_installations.len() == 1 {
|
||||
""
|
||||
} else {
|
||||
"s"
|
||||
};
|
||||
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Removed {} Python installation{s}",
|
||||
matching_installations.len()
|
||||
)?;
|
||||
|
||||
Ok(ExitStatus::Success)
|
||||
}
|
|
@ -17,12 +17,12 @@ use uv_fs::replace_symlink;
|
|||
use uv_fs::Simplified;
|
||||
use uv_installer::SitePackages;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_python::{
|
||||
EnvironmentPreference, Interpreter, PythonFetch, PythonInstallation, PythonPreference,
|
||||
PythonRequest,
|
||||
};
|
||||
use uv_requirements::RequirementsSpecification;
|
||||
use uv_tool::{entrypoint_paths, find_executable_directory, InstalledTools, Tool, ToolEntrypoint};
|
||||
use uv_toolchain::{
|
||||
EnvironmentPreference, Interpreter, Toolchain, ToolchainFetch, ToolchainPreference,
|
||||
ToolchainRequest,
|
||||
};
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::pip::operations::Modifications;
|
||||
|
@ -40,8 +40,8 @@ pub(crate) async fn install(
|
|||
force: bool,
|
||||
settings: ResolverInstallerSettings,
|
||||
preview: PreviewMode,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
connectivity: Connectivity,
|
||||
concurrency: Concurrency,
|
||||
native_tls: bool,
|
||||
|
@ -56,15 +56,15 @@ pub(crate) async fn install(
|
|||
.connectivity(connectivity)
|
||||
.native_tls(native_tls);
|
||||
|
||||
let python_request = python.as_deref().map(ToolchainRequest::parse);
|
||||
let python_request = python.as_deref().map(PythonRequest::parse);
|
||||
|
||||
// Pre-emptively identify a Python interpreter. We need an interpreter to resolve any unnamed
|
||||
// requirements, even if we end up using a different interpreter for the tool install itself.
|
||||
let interpreter = Toolchain::find_or_fetch(
|
||||
let interpreter = PythonInstallation::find_or_fetch(
|
||||
python_request.clone(),
|
||||
EnvironmentPreference::OnlySystem,
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
&client_builder,
|
||||
cache,
|
||||
)
|
||||
|
|
|
@ -14,11 +14,11 @@ use uv_cli::ExternalCommand;
|
|||
use uv_client::{BaseClientBuilder, Connectivity};
|
||||
use uv_configuration::{Concurrency, PreviewMode};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||
use uv_toolchain::{
|
||||
EnvironmentPreference, PythonEnvironment, Toolchain, ToolchainFetch, ToolchainPreference,
|
||||
ToolchainRequest,
|
||||
use uv_python::{
|
||||
EnvironmentPreference, PythonEnvironment, PythonFetch, PythonInstallation, PythonPreference,
|
||||
PythonRequest,
|
||||
};
|
||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::pip::operations::Modifications;
|
||||
|
@ -36,8 +36,8 @@ pub(crate) async fn run(
|
|||
settings: ResolverInstallerSettings,
|
||||
_isolated: bool,
|
||||
preview: PreviewMode,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
connectivity: Connectivity,
|
||||
concurrency: Concurrency,
|
||||
native_tls: bool,
|
||||
|
@ -78,11 +78,11 @@ pub(crate) async fn run(
|
|||
debug!("Syncing ephemeral environment.");
|
||||
|
||||
// Discover an interpreter.
|
||||
let interpreter = Toolchain::find_or_fetch(
|
||||
python.as_deref().map(ToolchainRequest::parse),
|
||||
let interpreter = PythonInstallation::find_or_fetch(
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
EnvironmentPreference::OnlySystem,
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
&client_builder,
|
||||
cache,
|
||||
)
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
use anyhow::Result;
|
||||
use futures::StreamExt;
|
||||
use itertools::Itertools;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::Write;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_toolchain::downloads::{self, PythonDownloadRequest};
|
||||
use uv_toolchain::managed::InstalledToolchains;
|
||||
use uv_toolchain::ToolchainRequest;
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
|
||||
/// Uninstall Python toolchains.
|
||||
pub(crate) async fn uninstall(
|
||||
targets: Vec<String>,
|
||||
preview: PreviewMode,
|
||||
printer: Printer,
|
||||
) -> Result<ExitStatus> {
|
||||
if preview.is_disabled() {
|
||||
warn_user_once!("`uv toolchain uninstall` is experimental and may change without warning.");
|
||||
}
|
||||
|
||||
let toolchains = InstalledToolchains::from_settings()?.init()?;
|
||||
let _lock = toolchains.acquire_lock()?;
|
||||
|
||||
let requests = targets
|
||||
.iter()
|
||||
.map(|target| ToolchainRequest::parse(target.as_str()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let download_requests = requests
|
||||
.iter()
|
||||
.map(PythonDownloadRequest::from_request)
|
||||
.collect::<Result<Vec<_>, downloads::Error>>()?;
|
||||
|
||||
let installed_toolchains: Vec<_> = toolchains.find_all()?.collect();
|
||||
let mut matching_toolchains = BTreeSet::default();
|
||||
for (request, download_request) in requests.iter().zip(download_requests) {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Looking for installed toolchains matching {request} ({download_request})"
|
||||
)?;
|
||||
let mut found = false;
|
||||
for toolchain in installed_toolchains
|
||||
.iter()
|
||||
.filter(|toolchain| download_request.satisfied_by_key(toolchain.key()))
|
||||
{
|
||||
found = true;
|
||||
if matching_toolchains.insert(toolchain.clone()) {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Found toolchain `{}` that matches {request}",
|
||||
toolchain.key()
|
||||
)?;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
writeln!(printer.stderr(), "No toolchains found matching {request}")?;
|
||||
}
|
||||
}
|
||||
|
||||
if matching_toolchains.is_empty() {
|
||||
if matches!(requests.as_slice(), [ToolchainRequest::Any]) {
|
||||
writeln!(printer.stderr(), "No installed toolchains found")?;
|
||||
} else if requests.len() > 1 {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"No toolchains found matching the requests"
|
||||
)?;
|
||||
} else {
|
||||
writeln!(printer.stderr(), "No toolchains found matching the request")?;
|
||||
}
|
||||
return Ok(ExitStatus::Failure);
|
||||
}
|
||||
|
||||
let tasks = futures::stream::iter(matching_toolchains.iter())
|
||||
.map(|toolchain| async {
|
||||
(
|
||||
toolchain.key(),
|
||||
fs_err::tokio::remove_dir_all(toolchain.path()).await,
|
||||
)
|
||||
})
|
||||
.buffered(4);
|
||||
|
||||
let results = tasks.collect::<Vec<_>>().await;
|
||||
let mut failed = false;
|
||||
for (key, result) in results.iter().sorted_by_key(|(key, _)| key) {
|
||||
if let Err(err) = result {
|
||||
failed = true;
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Failed to uninstall toolchain `{key}`: {err}"
|
||||
)?;
|
||||
} else {
|
||||
writeln!(printer.stderr(), "Uninstalled toolchain `{key}`")?;
|
||||
}
|
||||
}
|
||||
|
||||
if failed {
|
||||
if matching_toolchains.len() > 1 {
|
||||
writeln!(printer.stderr(), "Uninstall of some toolchains failed")?;
|
||||
}
|
||||
return Ok(ExitStatus::Failure);
|
||||
}
|
||||
|
||||
let s = if matching_toolchains.len() == 1 {
|
||||
""
|
||||
} else {
|
||||
"s"
|
||||
};
|
||||
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Uninstalled {} toolchain{s}",
|
||||
matching_toolchains.len()
|
||||
)?;
|
||||
|
||||
Ok(ExitStatus::Success)
|
||||
}
|
|
@ -22,11 +22,11 @@ use uv_configuration::{
|
|||
use uv_dispatch::BuildDispatch;
|
||||
use uv_fs::Simplified;
|
||||
use uv_git::GitResolver;
|
||||
use uv_resolver::{ExcludeNewer, FlatIndex, InMemoryIndex};
|
||||
use uv_toolchain::{
|
||||
request_from_version_file, EnvironmentPreference, Toolchain, ToolchainFetch,
|
||||
ToolchainPreference, ToolchainRequest,
|
||||
use uv_python::{
|
||||
request_from_version_file, EnvironmentPreference, PythonFetch, PythonInstallation,
|
||||
PythonPreference, PythonRequest,
|
||||
};
|
||||
use uv_resolver::{ExcludeNewer, FlatIndex, InMemoryIndex};
|
||||
use uv_types::{BuildContext, BuildIsolation, HashStrategy, InFlight};
|
||||
|
||||
use crate::commands::{pip, ExitStatus};
|
||||
|
@ -42,8 +42,8 @@ use crate::shell::Shell;
|
|||
pub(crate) async fn venv(
|
||||
path: &Path,
|
||||
python_request: Option<&str>,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
link_mode: LinkMode,
|
||||
index_locations: &IndexLocations,
|
||||
index_strategy: IndexStrategy,
|
||||
|
@ -71,8 +71,8 @@ pub(crate) async fn venv(
|
|||
connectivity,
|
||||
seed,
|
||||
preview,
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
allow_existing,
|
||||
exclude_newer,
|
||||
native_tls,
|
||||
|
@ -122,8 +122,8 @@ async fn venv_impl(
|
|||
connectivity: Connectivity,
|
||||
seed: bool,
|
||||
preview: PreviewMode,
|
||||
toolchain_preference: ToolchainPreference,
|
||||
toolchain_fetch: ToolchainFetch,
|
||||
python_preference: PythonPreference,
|
||||
python_fetch: PythonFetch,
|
||||
allow_existing: bool,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
native_tls: bool,
|
||||
|
@ -134,17 +134,17 @@ async fn venv_impl(
|
|||
.connectivity(connectivity)
|
||||
.native_tls(native_tls);
|
||||
|
||||
let mut interpreter_request = python_request.map(ToolchainRequest::parse);
|
||||
let mut interpreter_request = python_request.map(PythonRequest::parse);
|
||||
if preview.is_enabled() && interpreter_request.is_none() {
|
||||
interpreter_request = request_from_version_file().await.into_diagnostic()?;
|
||||
}
|
||||
|
||||
// Locate the Python interpreter to use in the environment
|
||||
let interpreter = Toolchain::find_or_fetch(
|
||||
let interpreter = PythonInstallation::find_or_fetch(
|
||||
interpreter_request,
|
||||
EnvironmentPreference::OnlySystem,
|
||||
toolchain_preference,
|
||||
toolchain_fetch,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
&client_builder,
|
||||
cache,
|
||||
)
|
||||
|
|
|
@ -17,9 +17,9 @@ use uv_cli::{
|
|||
compat::CompatArgs, CacheCommand, CacheNamespace, Cli, Commands, PipCommand, PipNamespace,
|
||||
ProjectCommand,
|
||||
};
|
||||
use uv_cli::{PythonCommand, PythonNamespace, ToolCommand, ToolNamespace};
|
||||
#[cfg(feature = "self-update")]
|
||||
use uv_cli::{SelfCommand, SelfNamespace};
|
||||
use uv_cli::{ToolCommand, ToolNamespace, ToolchainCommand, ToolchainNamespace};
|
||||
use uv_configuration::Concurrency;
|
||||
use uv_distribution::Workspace;
|
||||
use uv_requirements::RequirementsSource;
|
||||
|
@ -288,7 +288,7 @@ async fn run() -> Result<ExitStatus> {
|
|||
args.settings.link_mode,
|
||||
args.settings.python,
|
||||
args.settings.system,
|
||||
globals.toolchain_preference,
|
||||
globals.python_preference,
|
||||
args.settings.concurrency,
|
||||
globals.native_tls,
|
||||
globals.quiet,
|
||||
|
@ -617,8 +617,8 @@ async fn run() -> Result<ExitStatus> {
|
|||
commands::venv(
|
||||
&args.name,
|
||||
args.settings.python.as_deref(),
|
||||
globals.toolchain_preference,
|
||||
globals.toolchain_fetch,
|
||||
globals.python_preference,
|
||||
globals.python_fetch,
|
||||
args.settings.link_mode,
|
||||
&args.settings.index_locations,
|
||||
args.settings.index_strategy,
|
||||
|
@ -660,8 +660,8 @@ async fn run() -> Result<ExitStatus> {
|
|||
args.settings,
|
||||
globals.isolated,
|
||||
globals.preview,
|
||||
globals.toolchain_preference,
|
||||
globals.toolchain_fetch,
|
||||
globals.python_preference,
|
||||
globals.python_fetch,
|
||||
globals.connectivity,
|
||||
Concurrency::default(),
|
||||
globals.native_tls,
|
||||
|
@ -683,8 +683,8 @@ async fn run() -> Result<ExitStatus> {
|
|||
args.dev,
|
||||
args.modifications,
|
||||
args.python,
|
||||
globals.toolchain_preference,
|
||||
globals.toolchain_fetch,
|
||||
globals.python_preference,
|
||||
globals.python_fetch,
|
||||
args.settings,
|
||||
globals.preview,
|
||||
globals.connectivity,
|
||||
|
@ -707,8 +707,8 @@ async fn run() -> Result<ExitStatus> {
|
|||
args.python,
|
||||
args.settings,
|
||||
globals.preview,
|
||||
globals.toolchain_preference,
|
||||
globals.toolchain_fetch,
|
||||
globals.python_preference,
|
||||
globals.python_fetch,
|
||||
globals.connectivity,
|
||||
Concurrency::default(),
|
||||
globals.native_tls,
|
||||
|
@ -737,8 +737,8 @@ async fn run() -> Result<ExitStatus> {
|
|||
args.package,
|
||||
args.python,
|
||||
args.settings,
|
||||
globals.toolchain_preference,
|
||||
globals.toolchain_fetch,
|
||||
globals.python_preference,
|
||||
globals.python_fetch,
|
||||
globals.preview,
|
||||
globals.connectivity,
|
||||
Concurrency::default(),
|
||||
|
@ -761,8 +761,8 @@ async fn run() -> Result<ExitStatus> {
|
|||
args.dependency_type,
|
||||
args.package,
|
||||
args.python,
|
||||
globals.toolchain_preference,
|
||||
globals.toolchain_fetch,
|
||||
globals.python_preference,
|
||||
globals.python_fetch,
|
||||
globals.preview,
|
||||
globals.connectivity,
|
||||
Concurrency::default(),
|
||||
|
@ -802,8 +802,8 @@ async fn run() -> Result<ExitStatus> {
|
|||
args.settings,
|
||||
globals.isolated,
|
||||
globals.preview,
|
||||
globals.toolchain_preference,
|
||||
globals.toolchain_fetch,
|
||||
globals.python_preference,
|
||||
globals.python_fetch,
|
||||
globals.connectivity,
|
||||
Concurrency::default(),
|
||||
globals.native_tls,
|
||||
|
@ -830,8 +830,8 @@ async fn run() -> Result<ExitStatus> {
|
|||
args.force,
|
||||
args.settings,
|
||||
globals.preview,
|
||||
globals.toolchain_preference,
|
||||
globals.toolchain_fetch,
|
||||
globals.python_preference,
|
||||
globals.python_fetch,
|
||||
globals.connectivity,
|
||||
Concurrency::default(),
|
||||
globals.native_tls,
|
||||
|
@ -864,39 +864,39 @@ async fn run() -> Result<ExitStatus> {
|
|||
commands::tool_dir(globals.preview)?;
|
||||
Ok(ExitStatus::Success)
|
||||
}
|
||||
Commands::Toolchain(ToolchainNamespace {
|
||||
command: ToolchainCommand::List(args),
|
||||
Commands::Python(PythonNamespace {
|
||||
command: PythonCommand::List(args),
|
||||
}) => {
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = settings::ToolchainListSettings::resolve(args, filesystem);
|
||||
let args = settings::PythonListSettings::resolve(args, filesystem);
|
||||
show_settings!(args);
|
||||
|
||||
// Initialize the cache.
|
||||
let cache = cache.init()?;
|
||||
|
||||
commands::toolchain_list(
|
||||
commands::python_list(
|
||||
args.kinds,
|
||||
args.all_versions,
|
||||
args.all_platforms,
|
||||
globals.toolchain_preference,
|
||||
globals.toolchain_fetch,
|
||||
globals.python_preference,
|
||||
globals.python_fetch,
|
||||
globals.preview,
|
||||
&cache,
|
||||
printer,
|
||||
)
|
||||
.await
|
||||
}
|
||||
Commands::Toolchain(ToolchainNamespace {
|
||||
command: ToolchainCommand::Install(args),
|
||||
Commands::Python(PythonNamespace {
|
||||
command: PythonCommand::Install(args),
|
||||
}) => {
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = settings::ToolchainInstallSettings::resolve(args, filesystem);
|
||||
let args = settings::PythonInstallSettings::resolve(args, filesystem);
|
||||
show_settings!(args);
|
||||
|
||||
// Initialize the cache.
|
||||
let cache = cache.init()?;
|
||||
|
||||
commands::toolchain_install(
|
||||
commands::python_install(
|
||||
args.targets,
|
||||
args.force,
|
||||
globals.native_tls,
|
||||
|
@ -907,37 +907,37 @@ async fn run() -> Result<ExitStatus> {
|
|||
)
|
||||
.await
|
||||
}
|
||||
Commands::Toolchain(ToolchainNamespace {
|
||||
command: ToolchainCommand::Uninstall(args),
|
||||
Commands::Python(PythonNamespace {
|
||||
command: PythonCommand::Uninstall(args),
|
||||
}) => {
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = settings::ToolchainUninstallSettings::resolve(args, filesystem);
|
||||
let args = settings::PythonUninstallSettings::resolve(args, filesystem);
|
||||
show_settings!(args);
|
||||
|
||||
commands::toolchain_uninstall(args.targets, globals.preview, printer).await
|
||||
commands::python_uninstall(args.targets, globals.preview, printer).await
|
||||
}
|
||||
Commands::Toolchain(ToolchainNamespace {
|
||||
command: ToolchainCommand::Find(args),
|
||||
Commands::Python(PythonNamespace {
|
||||
command: PythonCommand::Find(args),
|
||||
}) => {
|
||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = settings::ToolchainFindSettings::resolve(args, filesystem);
|
||||
let args = settings::PythonFindSettings::resolve(args, filesystem);
|
||||
|
||||
// Initialize the cache.
|
||||
let cache = cache.init()?;
|
||||
|
||||
commands::toolchain_find(
|
||||
commands::python_find(
|
||||
args.request,
|
||||
globals.toolchain_preference,
|
||||
globals.python_preference,
|
||||
globals.preview,
|
||||
&cache,
|
||||
printer,
|
||||
)
|
||||
.await
|
||||
}
|
||||
Commands::Toolchain(ToolchainNamespace {
|
||||
command: ToolchainCommand::Dir,
|
||||
Commands::Python(PythonNamespace {
|
||||
command: PythonCommand::Dir,
|
||||
}) => {
|
||||
commands::toolchain_dir(globals.preview)?;
|
||||
commands::python_dir(globals.preview)?;
|
||||
Ok(ExitStatus::Success)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@ use uv_cli::options::{flag, installer_options, resolver_installer_options, resol
|
|||
use uv_cli::{
|
||||
AddArgs, ColorChoice, Commands, ExternalCommand, GlobalArgs, ListFormat, LockArgs, Maybe,
|
||||
PipCheckArgs, PipCompileArgs, PipFreezeArgs, PipInstallArgs, PipListArgs, PipShowArgs,
|
||||
PipSyncArgs, PipTreeArgs, PipUninstallArgs, RemoveArgs, RunArgs, SyncArgs, ToolInstallArgs,
|
||||
ToolListArgs, ToolRunArgs, ToolUninstallArgs, ToolchainFindArgs, ToolchainInstallArgs,
|
||||
ToolchainListArgs, ToolchainUninstallArgs, VenvArgs,
|
||||
PipSyncArgs, PipTreeArgs, PipUninstallArgs, PythonFindArgs, PythonInstallArgs, PythonListArgs,
|
||||
PythonUninstallArgs, RemoveArgs, RunArgs, SyncArgs, ToolInstallArgs, ToolListArgs, ToolRunArgs,
|
||||
ToolUninstallArgs, VenvArgs,
|
||||
};
|
||||
use uv_client::Connectivity;
|
||||
use uv_configuration::{
|
||||
|
@ -25,13 +25,13 @@ use uv_configuration::{
|
|||
};
|
||||
use uv_distribution::pyproject::DependencyType;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_python::{Prefix, PythonFetch, PythonPreference, PythonVersion, Target};
|
||||
use uv_requirements::RequirementsSource;
|
||||
use uv_resolver::{AnnotationStyle, DependencyMode, ExcludeNewer, PreReleaseMode, ResolutionMode};
|
||||
use uv_settings::{
|
||||
Combine, FilesystemOptions, InstallerOptions, Options, PipOptions, ResolverInstallerOptions,
|
||||
ResolverOptions,
|
||||
};
|
||||
use uv_toolchain::{Prefix, PythonVersion, Target, ToolchainFetch, ToolchainPreference};
|
||||
|
||||
use crate::commands::pip::operations::Modifications;
|
||||
|
||||
|
@ -47,8 +47,8 @@ pub(crate) struct GlobalSettings {
|
|||
pub(crate) isolated: bool,
|
||||
pub(crate) show_settings: bool,
|
||||
pub(crate) preview: PreviewMode,
|
||||
pub(crate) toolchain_preference: ToolchainPreference,
|
||||
pub(crate) toolchain_fetch: ToolchainFetch,
|
||||
pub(crate) python_preference: PythonPreference,
|
||||
pub(crate) python_fetch: PythonFetch,
|
||||
}
|
||||
|
||||
impl GlobalSettings {
|
||||
|
@ -64,17 +64,17 @@ impl GlobalSettings {
|
|||
.unwrap_or(false),
|
||||
);
|
||||
|
||||
// Always use preview mode toolchain preferences during preview commands
|
||||
// Always use preview mode python preferences during preview commands
|
||||
// TODO(zanieb): There should be a cleaner way to do this, we should probably resolve
|
||||
// force preview to true for these commands but it would break our experimental warning
|
||||
// right now
|
||||
let default_toolchain_preference = if matches!(
|
||||
let default_python_preference = if matches!(
|
||||
command,
|
||||
Commands::Project(_) | Commands::Toolchain(_) | Commands::Tool(_)
|
||||
Commands::Project(_) | Commands::Python(_) | Commands::Tool(_)
|
||||
) {
|
||||
ToolchainPreference::default_from(PreviewMode::Enabled)
|
||||
PythonPreference::default_from(PreviewMode::Enabled)
|
||||
} else {
|
||||
ToolchainPreference::default_from(preview)
|
||||
PythonPreference::default_from(preview)
|
||||
};
|
||||
|
||||
Self {
|
||||
|
@ -111,13 +111,13 @@ impl GlobalSettings {
|
|||
isolated: args.isolated,
|
||||
show_settings: args.show_settings,
|
||||
preview,
|
||||
toolchain_preference: args
|
||||
.toolchain_preference
|
||||
.combine(workspace.and_then(|workspace| workspace.globals.toolchain_preference))
|
||||
.unwrap_or(default_toolchain_preference),
|
||||
toolchain_fetch: args
|
||||
.toolchain_fetch
|
||||
.combine(workspace.and_then(|workspace| workspace.globals.toolchain_fetch))
|
||||
python_preference: args
|
||||
.python_preference
|
||||
.combine(workspace.and_then(|workspace| workspace.globals.python_preference))
|
||||
.unwrap_or(default_python_preference),
|
||||
python_fetch: args
|
||||
.python_fetch
|
||||
.combine(workspace.and_then(|workspace| workspace.globals.python_fetch))
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ impl ToolUninstallSettings {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub(crate) enum ToolchainListKinds {
|
||||
pub(crate) enum PythonListKinds {
|
||||
#[default]
|
||||
Default,
|
||||
Installed,
|
||||
|
@ -323,26 +323,26 @@ pub(crate) enum ToolchainListKinds {
|
|||
/// The resolved settings to use for a `tool run` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ToolchainListSettings {
|
||||
pub(crate) kinds: ToolchainListKinds,
|
||||
pub(crate) struct PythonListSettings {
|
||||
pub(crate) kinds: PythonListKinds,
|
||||
pub(crate) all_platforms: bool,
|
||||
pub(crate) all_versions: bool,
|
||||
}
|
||||
|
||||
impl ToolchainListSettings {
|
||||
/// Resolve the [`ToolchainListSettings`] from the CLI and filesystem configuration.
|
||||
impl PythonListSettings {
|
||||
/// Resolve the [`PythonListSettings`] from the CLI and filesystem configuration.
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub(crate) fn resolve(args: ToolchainListArgs, _filesystem: Option<FilesystemOptions>) -> Self {
|
||||
let ToolchainListArgs {
|
||||
pub(crate) fn resolve(args: PythonListArgs, _filesystem: Option<FilesystemOptions>) -> Self {
|
||||
let PythonListArgs {
|
||||
all_versions,
|
||||
all_platforms,
|
||||
only_installed,
|
||||
} = args;
|
||||
|
||||
let kinds = if only_installed {
|
||||
ToolchainListKinds::Installed
|
||||
PythonListKinds::Installed
|
||||
} else {
|
||||
ToolchainListKinds::default()
|
||||
PythonListKinds::default()
|
||||
};
|
||||
|
||||
Self {
|
||||
|
@ -353,59 +353,56 @@ impl ToolchainListSettings {
|
|||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `toolchain install` invocation.
|
||||
/// The resolved settings to use for a `python install` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ToolchainInstallSettings {
|
||||
pub(crate) struct PythonInstallSettings {
|
||||
pub(crate) targets: Vec<String>,
|
||||
pub(crate) force: bool,
|
||||
}
|
||||
|
||||
impl ToolchainInstallSettings {
|
||||
/// Resolve the [`ToolchainInstallSettings`] from the CLI and filesystem configuration.
|
||||
impl PythonInstallSettings {
|
||||
/// Resolve the [`PythonInstallSettings`] from the CLI and filesystem configuration.
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub(crate) fn resolve(
|
||||
args: ToolchainInstallArgs,
|
||||
_filesystem: Option<FilesystemOptions>,
|
||||
) -> Self {
|
||||
let ToolchainInstallArgs { targets, force } = args;
|
||||
pub(crate) fn resolve(args: PythonInstallArgs, _filesystem: Option<FilesystemOptions>) -> Self {
|
||||
let PythonInstallArgs { targets, force } = args;
|
||||
|
||||
Self { targets, force }
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `toolchain uninstall` invocation.
|
||||
/// The resolved settings to use for a `python uninstall` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ToolchainUninstallSettings {
|
||||
pub(crate) struct PythonUninstallSettings {
|
||||
pub(crate) targets: Vec<String>,
|
||||
}
|
||||
|
||||
impl ToolchainUninstallSettings {
|
||||
/// Resolve the [`ToolchainUninstallSettings`] from the CLI and filesystem configuration.
|
||||
impl PythonUninstallSettings {
|
||||
/// Resolve the [`PythonUninstallSettings`] from the CLI and filesystem configuration.
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub(crate) fn resolve(
|
||||
args: ToolchainUninstallArgs,
|
||||
args: PythonUninstallArgs,
|
||||
_filesystem: Option<FilesystemOptions>,
|
||||
) -> Self {
|
||||
let ToolchainUninstallArgs { targets } = args;
|
||||
let PythonUninstallArgs { targets } = args;
|
||||
|
||||
Self { targets }
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved settings to use for a `toolchain find` invocation.
|
||||
/// The resolved settings to use for a `python find` invocation.
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ToolchainFindSettings {
|
||||
pub(crate) struct PythonFindSettings {
|
||||
pub(crate) request: Option<String>,
|
||||
}
|
||||
|
||||
impl ToolchainFindSettings {
|
||||
/// Resolve the [`ToolchainFindSettings`] from the CLI and workspace configuration.
|
||||
impl PythonFindSettings {
|
||||
/// Resolve the [`PythonFindSettings`] from the CLI and workspace configuration.
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub(crate) fn resolve(args: ToolchainFindArgs, _filesystem: Option<FilesystemOptions>) -> Self {
|
||||
let ToolchainFindArgs { request } = args;
|
||||
pub(crate) fn resolve(args: PythonFindArgs, _filesystem: Option<FilesystemOptions>) -> Self {
|
||||
let PythonFindArgs { request } = args;
|
||||
|
||||
Self { request }
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ use regex::Regex;
|
|||
|
||||
use uv_cache::Cache;
|
||||
use uv_fs::Simplified;
|
||||
use uv_toolchain::managed::InstalledToolchains;
|
||||
use uv_toolchain::{
|
||||
EnvironmentPreference, PythonVersion, Toolchain, ToolchainPreference, ToolchainRequest,
|
||||
use uv_python::managed::ManagedPythonInstallations;
|
||||
use uv_python::{
|
||||
EnvironmentPreference, PythonInstallation, PythonPreference, PythonRequest, PythonVersion,
|
||||
};
|
||||
|
||||
// Exclude any packages uploaded after this date.
|
||||
|
@ -157,7 +157,7 @@ impl TestContext {
|
|||
.iter()
|
||||
.map(|version| PythonVersion::from_str(version).unwrap())
|
||||
.zip(
|
||||
python_toolchains_for_versions(&temp_dir, python_versions)
|
||||
python_installations_for_versions(&temp_dir, python_versions)
|
||||
.expect("Failed to find test Python versions"),
|
||||
)
|
||||
.collect();
|
||||
|
@ -284,7 +284,7 @@ impl TestContext {
|
|||
/// * Don't wrap text output based on the terminal we're in, the test output doesn't get printed
|
||||
/// but snapshotted to a string.
|
||||
/// * Use a fake `HOME` to avoid accidentally changing the developer's machine.
|
||||
/// * Hide other Python toolchain with `UV_TOOLCHAIN_DIR` and installed interpreters with
|
||||
/// * Hide other Python python with `UV_PYTHON_INSTALL_DIR` and installed interpreters with
|
||||
/// `UV_TEST_PYTHON_PATH`.
|
||||
/// * Increase the stack size to avoid stack overflows on windows due to large async functions.
|
||||
pub fn add_shared_args(&self, command: &mut Command) {
|
||||
|
@ -294,7 +294,7 @@ impl TestContext {
|
|||
.env("VIRTUAL_ENV", self.venv.as_os_str())
|
||||
.env("UV_NO_WRAP", "1")
|
||||
.env("HOME", self.home_dir.as_os_str())
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_PYTHON_INSTALL_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path())
|
||||
.env("UV_EXCLUDE_NEWER", EXCLUDE_NEWER)
|
||||
.current_dir(self.temp_dir.path());
|
||||
|
@ -371,23 +371,23 @@ impl TestContext {
|
|||
command
|
||||
}
|
||||
|
||||
/// Create a `uv toolchain find` command with options shared across scenarios.
|
||||
pub fn toolchain_find(&self) -> Command {
|
||||
/// Create a `uv python find` command with options shared across scenarios.
|
||||
pub fn python_find(&self) -> Command {
|
||||
let mut command = Command::new(get_bin());
|
||||
command
|
||||
.arg("toolchain")
|
||||
.arg("python")
|
||||
.arg("find")
|
||||
.env("UV_PREVIEW", "1")
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_PYTHON_INSTALL_DIR", "")
|
||||
.current_dir(&self.temp_dir);
|
||||
self.add_shared_args(&mut command);
|
||||
command
|
||||
}
|
||||
|
||||
/// Create a `uv toolchain dir` command with options shared across scenarios.
|
||||
pub fn toolchain_dir(&self) -> Command {
|
||||
/// Create a `uv python dir` command with options shared across scenarios.
|
||||
pub fn python_dir(&self) -> Command {
|
||||
let mut command = Command::new(get_bin());
|
||||
command.arg("toolchain").arg("dir");
|
||||
command.arg("python").arg("dir");
|
||||
self.add_shared_args(&mut command);
|
||||
command
|
||||
}
|
||||
|
@ -601,7 +601,7 @@ impl TestContext {
|
|||
|
||||
/// Create a new virtual environment named `.venv` in the test context.
|
||||
fn create_venv(&self) {
|
||||
let executable = get_toolchain(
|
||||
let executable = get_python(
|
||||
self.python_version
|
||||
.as_ref()
|
||||
.expect("A Python version must be provided to create a test virtual environment"),
|
||||
|
@ -640,18 +640,18 @@ pub fn venv_to_interpreter(venv: &Path) -> PathBuf {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the path to the python interpreter for a specific toolchain version.
|
||||
pub fn get_toolchain(version: &PythonVersion) -> PathBuf {
|
||||
InstalledToolchains::from_settings()
|
||||
.map(|installed_toolchains| {
|
||||
installed_toolchains
|
||||
/// Get the path to the python interpreter for a specific python version.
|
||||
pub fn get_python(version: &PythonVersion) -> PathBuf {
|
||||
ManagedPythonInstallations::from_settings()
|
||||
.map(|installed_pythons| {
|
||||
installed_pythons
|
||||
.find_version(version)
|
||||
.expect("Tests are run on a supported platform")
|
||||
.next()
|
||||
.as_ref()
|
||||
.map(uv_toolchain::managed::InstalledToolchain::executable)
|
||||
.map(uv_python::managed::ManagedPythonInstallation::executable)
|
||||
})
|
||||
// We'll search for the request Python on the PATH if not found in the toolchain versions
|
||||
// We'll search for the request Python on the PATH if not found in the python versions
|
||||
// We hack this into a `PathBuf` to satisfy the compiler but it's just a string
|
||||
.unwrap_or_default()
|
||||
.unwrap_or(PathBuf::from(version.to_string()))
|
||||
|
@ -691,7 +691,7 @@ pub fn python_path_with_versions(
|
|||
python_versions: &[&str],
|
||||
) -> anyhow::Result<OsString> {
|
||||
Ok(std::env::join_paths(
|
||||
python_toolchains_for_versions(temp_dir, python_versions)?
|
||||
python_installations_for_versions(temp_dir, python_versions)?
|
||||
.into_iter()
|
||||
.map(|path| path.parent().unwrap().to_path_buf()),
|
||||
)?)
|
||||
|
@ -700,7 +700,7 @@ pub fn python_path_with_versions(
|
|||
/// Returns a list of Python executables for the given versions.
|
||||
///
|
||||
/// Generally this should be used with `UV_TEST_PYTHON_PATH`.
|
||||
pub fn python_toolchains_for_versions(
|
||||
pub fn python_installations_for_versions(
|
||||
temp_dir: &assert_fs::TempDir,
|
||||
python_versions: &[&str],
|
||||
) -> anyhow::Result<Vec<PathBuf>> {
|
||||
|
@ -708,13 +708,13 @@ pub fn python_toolchains_for_versions(
|
|||
let selected_pythons = python_versions
|
||||
.iter()
|
||||
.map(|python_version| {
|
||||
if let Ok(toolchain) = Toolchain::find(
|
||||
&ToolchainRequest::parse(python_version),
|
||||
if let Ok(python) = PythonInstallation::find(
|
||||
&PythonRequest::parse(python_version),
|
||||
EnvironmentPreference::OnlySystem,
|
||||
ToolchainPreference::Managed,
|
||||
PythonPreference::Managed,
|
||||
&cache,
|
||||
) {
|
||||
toolchain.into_interpreter().sys_executable().to_owned()
|
||||
python.into_interpreter().sys_executable().to_owned()
|
||||
} else {
|
||||
panic!("Could not find Python {python_version} for test");
|
||||
}
|
||||
|
|
|
@ -2034,13 +2034,13 @@ fn lock_requires_python() -> Result<()> {
|
|||
.filters()
|
||||
.into_iter()
|
||||
.chain(context.filters())
|
||||
// Platform independent message for the missing toolchain
|
||||
// Platform independent message for the missing Python installation
|
||||
.chain([(" or `py` launcher", "")])
|
||||
.collect();
|
||||
|
||||
// Install from the lockfile.
|
||||
// Note we need to disable toolchain fetches or we'll just download 3.12
|
||||
uv_snapshot!(filters, context38.sync().arg("--toolchain-fetch").arg("manual"), @r###"
|
||||
// Note we need to disable Python fetches or we'll just download 3.12
|
||||
uv_snapshot!(filters, context38.sync().arg("--python-fetch").arg("manual"), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
|
21
crates/uv/tests/python_dir.rs
Normal file
21
crates/uv/tests/python_dir.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use assert_fs::fixture::PathChild;
|
||||
use common::{uv_snapshot, TestContext};
|
||||
|
||||
mod common;
|
||||
|
||||
#[test]
|
||||
fn python_dir() {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let python_dir = context.temp_dir.child("python");
|
||||
uv_snapshot!(context.filters(), context.python_dir()
|
||||
.env("UV_PYTHON_INSTALL_DIR", python_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
[TEMP_DIR]/python
|
||||
|
||||
----- stderr -----
|
||||
warning: `uv python dir` is experimental and may change without warning.
|
||||
"###);
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
#![cfg(all(feature = "python", feature = "pypi"))]
|
||||
|
||||
use common::{uv_snapshot, TestContext};
|
||||
use uv_toolchain::platform::{Arch, Os};
|
||||
use uv_python::platform::{Arch, Os};
|
||||
|
||||
mod common;
|
||||
|
||||
#[test]
|
||||
fn toolchain_find() {
|
||||
fn python_find() {
|
||||
let mut context: TestContext = TestContext::new_with_versions(&["3.11", "3.12"]);
|
||||
|
||||
// No interpreters on the path
|
||||
if cfg!(windows) {
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().env("UV_TEST_PYTHON_PATH", ""), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().env("UV_TEST_PYTHON_PATH", ""), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
@ -20,7 +20,7 @@ fn toolchain_find() {
|
|||
error: No interpreter found in system path or `py` launcher
|
||||
"###);
|
||||
} else {
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().env("UV_TEST_PYTHON_PATH", ""), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().env("UV_TEST_PYTHON_PATH", ""), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
@ -31,7 +31,7 @@ fn toolchain_find() {
|
|||
}
|
||||
|
||||
// We find the first interpreter on the path
|
||||
uv_snapshot!(context.filters(), context.toolchain_find(), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find(), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -41,7 +41,7 @@ fn toolchain_find() {
|
|||
"###);
|
||||
|
||||
// Request Python 3.12
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().arg("3.12"), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("3.12"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -51,7 +51,7 @@ fn toolchain_find() {
|
|||
"###);
|
||||
|
||||
// Request Python 3.11
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().arg("3.11"), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("3.11"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -61,7 +61,7 @@ fn toolchain_find() {
|
|||
"###);
|
||||
|
||||
// Request CPython
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().arg("cpython"), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("cpython"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -71,7 +71,7 @@ fn toolchain_find() {
|
|||
"###);
|
||||
|
||||
// Request CPython 3.12
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().arg("cpython@3.12"), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("cpython@3.12"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -81,7 +81,7 @@ fn toolchain_find() {
|
|||
"###);
|
||||
|
||||
// Request CPython 3.12 via partial key syntax
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().arg("cpython-3.12"), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("cpython-3.12"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -94,7 +94,7 @@ fn toolchain_find() {
|
|||
let os = Os::from_env();
|
||||
let arch = Arch::from_env();
|
||||
|
||||
uv_snapshot!(context.filters(), context.toolchain_find()
|
||||
uv_snapshot!(context.filters(), context.python_find()
|
||||
.arg(format!("cpython-3.12-{os}-{arch}"))
|
||||
, @r###"
|
||||
success: true
|
||||
|
@ -107,7 +107,7 @@ fn toolchain_find() {
|
|||
|
||||
// Request PyPy (which should be missing)
|
||||
if cfg!(windows) {
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().arg("pypy"), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("pypy"), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
@ -116,7 +116,7 @@ fn toolchain_find() {
|
|||
error: No interpreter found for PyPy in system path or `py` launcher
|
||||
"###);
|
||||
} else {
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().arg("pypy"), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("pypy"), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
@ -129,7 +129,7 @@ fn toolchain_find() {
|
|||
// Swap the order of the Python versions
|
||||
context.python_versions.reverse();
|
||||
|
||||
uv_snapshot!(context.filters(), context.toolchain_find(), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find(), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -139,7 +139,7 @@ fn toolchain_find() {
|
|||
"###);
|
||||
|
||||
// Request Python 3.11
|
||||
uv_snapshot!(context.filters(), context.toolchain_find().arg("3.11"), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("3.11"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue