mirror of https://github.com/astral-sh/uv
Merge branch 'main' into zb/extra-build-dependencies
This commit is contained in:
commit
bd55fda3a3
|
|
@ -28,8 +28,6 @@ jobs:
|
|||
pattern: wheels_uv-*
|
||||
path: wheels_uv
|
||||
merge-multiple: true
|
||||
- name: Remove wheels unsupported by PyPI
|
||||
run: rm wheels_uv/*riscv*
|
||||
- name: Publish to PyPI
|
||||
run: uv publish -v wheels_uv/*
|
||||
|
||||
|
|
@ -49,7 +47,5 @@ jobs:
|
|||
pattern: wheels_uv_build-*
|
||||
path: wheels_uv_build
|
||||
merge-multiple: true
|
||||
- name: Remove wheels unsupported by PyPI
|
||||
run: rm wheels_uv_build/*riscv*
|
||||
- name: Publish to PyPI
|
||||
run: uv publish -v wheels_uv_build/*
|
||||
|
|
|
|||
26
CHANGELOG.md
26
CHANGELOG.md
|
|
@ -3,6 +3,32 @@
|
|||
<!-- prettier-ignore-start -->
|
||||
|
||||
|
||||
## 0.8.3
|
||||
|
||||
### Python
|
||||
|
||||
- Add CPython 3.14.0rc1
|
||||
|
||||
See the [`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250723) for more details.
|
||||
|
||||
### Enhancements
|
||||
|
||||
- Allow non-standard entrypoint names in `uv_build` ([#14867](https://github.com/astral-sh/uv/pull/14867))
|
||||
- Publish riscv64 wheels to PyPI ([#14852](https://github.com/astral-sh/uv/pull/14852))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Avoid writing redacted credentials to tool receipt ([#14855](https://github.com/astral-sh/uv/pull/14855))
|
||||
- Respect `--with` versions over base environment versions ([#14863](https://github.com/astral-sh/uv/pull/14863))
|
||||
- Respect credentials from all defined indexes ([#14858](https://github.com/astral-sh/uv/pull/14858))
|
||||
- Fix missed stabilization of removal of registry entry during Python uninstall ([#14859](https://github.com/astral-sh/uv/pull/14859))
|
||||
- Improve concurrency safety of Python downloads into cache ([#14846](https://github.com/astral-sh/uv/pull/14846))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Fix typos in `uv_build` reference documentation ([#14853](https://github.com/astral-sh/uv/pull/14853))
|
||||
- Move the "Cargo" install method further down in docs ([#14842](https://github.com/astral-sh/uv/pull/14842))
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Enhancements
|
||||
|
|
|
|||
|
|
@ -759,7 +759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1035,23 +1035,23 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1591,11 +1591,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
|||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.9"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
||||
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2994,13 +2994,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.6"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3654,9 +3654,9 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
|
|||
|
||||
[[package]]
|
||||
name = "shellexpand"
|
||||
version = "3.1.0"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
|
||||
checksum = "8b1fdf65dd6331831494dd616b30351c38e96e45921a27745cf98490458b90bb"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"dirs",
|
||||
|
|
@ -4645,7 +4645,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uv"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anyhow",
|
||||
|
|
@ -4656,7 +4656,7 @@ dependencies = [
|
|||
"base64 0.22.1",
|
||||
"byteorder",
|
||||
"clap",
|
||||
"console 0.15.11",
|
||||
"console 0.16.0",
|
||||
"ctrlc",
|
||||
"dotenvy",
|
||||
"dunce",
|
||||
|
|
@ -4811,7 +4811,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uv-build"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"uv-build-backend",
|
||||
|
|
@ -5037,6 +5037,7 @@ name = "uv-configuration"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.9.1",
|
||||
"clap",
|
||||
"either",
|
||||
"fs-err 3.1.1",
|
||||
|
|
@ -5061,13 +5062,14 @@ dependencies = [
|
|||
"uv-pep508",
|
||||
"uv-platform-tags",
|
||||
"uv-static",
|
||||
"uv-warnings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uv-console"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"console 0.15.11",
|
||||
"console 0.16.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5705,7 +5707,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"configparser",
|
||||
"console 0.15.11",
|
||||
"console 0.16.0",
|
||||
"fs-err 3.1.1",
|
||||
"futures",
|
||||
"rustc-hash",
|
||||
|
|
@ -6006,13 +6008,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uv-version"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
|
||||
[[package]]
|
||||
name = "uv-virtualenv"
|
||||
version = "0.0.4"
|
||||
dependencies = [
|
||||
"console 0.15.11",
|
||||
"console 0.16.0",
|
||||
"fs-err 3.1.1",
|
||||
"itertools 0.14.0",
|
||||
"owo-colors",
|
||||
|
|
@ -6340,7 +6342,7 @@ version = "0.1.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ cargo-util = { version = "0.2.14" }
|
|||
clap = { version = "4.5.17", features = ["derive", "env", "string", "wrap_help"] }
|
||||
clap_complete_command = { version = "0.6.1" }
|
||||
configparser = { version = "3.1.0" }
|
||||
console = { version = "0.15.11", default-features = false }
|
||||
console = { version = "0.16.0", default-features = false, features = ["std"] }
|
||||
csv = { version = "1.3.0" }
|
||||
ctrlc = { version = "3.4.5" }
|
||||
dashmap = { version = "6.1.0" }
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ mod resolver {
|
|||
use uv_client::RegistryClient;
|
||||
use uv_configuration::{
|
||||
BuildOptions, Concurrency, ConfigSettings, Constraints, IndexStrategy,
|
||||
PackageConfigSettings, PreviewMode, SourceStrategy,
|
||||
PackageConfigSettings, Preview, SourceStrategy,
|
||||
};
|
||||
use uv_dispatch::{BuildDispatch, SharedState};
|
||||
use uv_distribution::DistributionDatabase;
|
||||
|
|
@ -198,7 +198,7 @@ mod resolver {
|
|||
sources,
|
||||
workspace_cache,
|
||||
concurrency,
|
||||
PreviewMode::Enabled,
|
||||
Preview::default(),
|
||||
);
|
||||
|
||||
let markers = if universal {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::str::FromStr;
|
|||
|
||||
use itertools::Itertools;
|
||||
use serde::Deserialize;
|
||||
use tracing::{debug, trace};
|
||||
use tracing::{debug, trace, warn};
|
||||
use version_ranges::Ranges;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
|
|
@ -54,10 +54,6 @@ pub enum ValidationError {
|
|||
"Entrypoint groups must consist of letters and numbers separated by dots, invalid group: `{0}`"
|
||||
)]
|
||||
InvalidGroup(String),
|
||||
#[error(
|
||||
"Entrypoint names must consist of letters, numbers, dots, underscores and dashes; invalid name: `{0}`"
|
||||
)]
|
||||
InvalidName(String),
|
||||
#[error("Use `project.scripts` instead of `project.entry-points.console_scripts`")]
|
||||
ReservedScripts,
|
||||
#[error("Use `project.gui-scripts` instead of `project.entry-points.gui_scripts`")]
|
||||
|
|
@ -620,12 +616,14 @@ impl PyProjectToml {
|
|||
|
||||
let _ = writeln!(writer, "[{group}]");
|
||||
for (name, object_reference) in entries {
|
||||
// More strict than the spec, we enforce the recommendation
|
||||
if !name
|
||||
.chars()
|
||||
.all(|c| c.is_alphanumeric() || c == '.' || c == '-' || c == '_')
|
||||
{
|
||||
return Err(ValidationError::InvalidName(name.to_string()));
|
||||
warn!(
|
||||
"Entrypoint names should consist of letters, numbers, dots, underscores and \
|
||||
dashes; non-compliant name: `{name}`"
|
||||
);
|
||||
}
|
||||
|
||||
// TODO(konsti): Validate that the object references are valid Python identifiers.
|
||||
|
|
@ -1403,16 +1401,6 @@ mod tests {
|
|||
assert_snapshot!(script_error(&contents), @"Entrypoint groups must consist of letters and numbers separated by dots, invalid group: `a@b`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_name() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
[project.scripts]
|
||||
"a@b" = "bar"
|
||||
"#
|
||||
});
|
||||
assert_snapshot!(script_error(&contents), @"Entrypoint names must consist of letters, numbers, dots, underscores and dashes; invalid name: `a@b`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_conflict_scripts() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ pub struct BuildBackendSettings {
|
|||
/// with this package as build requirement use the include directory to find additional header
|
||||
/// files.
|
||||
/// - `purelib` and `platlib`: Installed to the `site-packages` directory. It is not recommended
|
||||
/// to uses these two options.
|
||||
/// to use these two options.
|
||||
// TODO(konsti): We should show a flat example instead.
|
||||
// ```toml
|
||||
// [tool.uv.build-backend.data]
|
||||
|
|
@ -165,7 +165,7 @@ pub struct BuildBackendSettings {
|
|||
#[option(
|
||||
default = r#"{}"#,
|
||||
value_type = "dict[str, str]",
|
||||
example = r#"data = { "headers": "include/headers", "scripts": "bin" }"#
|
||||
example = r#"data = { headers = "include/headers", scripts = "bin" }"#
|
||||
)]
|
||||
pub data: WheelDataIncludes,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use tokio::sync::{Mutex, Semaphore};
|
|||
use tracing::{Instrument, debug, info_span, instrument, warn};
|
||||
|
||||
use uv_cache_key::cache_digest;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_configuration::{BuildKind, BuildOutput, ConfigSettings, SourceStrategy};
|
||||
use uv_distribution::BuildRequires;
|
||||
use uv_distribution_types::{IndexLocations, Requirement, Resolution};
|
||||
|
|
@ -289,7 +289,7 @@ impl SourceBuild {
|
|||
mut environment_variables: FxHashMap<OsString, OsString>,
|
||||
level: BuildOutput,
|
||||
concurrent_builds: usize,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, Error> {
|
||||
let temp_dir = build_context.cache().venv_dir()?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uv-build"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
homepage.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "uv-build"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
description = "The uv build backend"
|
||||
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
|
||||
requires-python = ">=3.8"
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ use clap::{Args, Parser, Subcommand};
|
|||
use uv_cache::CacheArgs;
|
||||
use uv_configuration::{
|
||||
ConfigSettingEntry, ConfigSettingPackageEntry, ExportFormat, IndexStrategy,
|
||||
KeyringProviderType, PackageNameSpecifier, ProjectBuildBackend, TargetTriple, TrustedHost,
|
||||
TrustedPublishing, VersionControlSystem,
|
||||
KeyringProviderType, PackageNameSpecifier, PreviewFeatures, ProjectBuildBackend, TargetTriple,
|
||||
TrustedHost, TrustedPublishing, VersionControlSystem,
|
||||
};
|
||||
use uv_distribution_types::{Index, IndexUrl, Origin, PipExtraIndex, PipFindLinks, PipIndex};
|
||||
use uv_normalize::{ExtraName, GroupName, PackageName, PipGroupName};
|
||||
|
|
@ -273,7 +273,7 @@ pub struct GlobalArgs {
|
|||
)]
|
||||
pub allow_insecure_host: Option<Vec<Maybe<TrustedHost>>>,
|
||||
|
||||
/// Whether to enable experimental, preview features.
|
||||
/// Whether to enable all experimental preview features.
|
||||
///
|
||||
/// Preview features may change without warning.
|
||||
#[arg(global = true, long, hide = true, env = EnvVars::UV_PREVIEW, value_parser = clap::builder::BoolishValueParser::new(), overrides_with("no_preview"))]
|
||||
|
|
@ -282,6 +282,25 @@ pub struct GlobalArgs {
|
|||
#[arg(global = true, long, overrides_with("preview"), hide = true)]
|
||||
pub no_preview: bool,
|
||||
|
||||
/// Enable experimental preview features.
|
||||
///
|
||||
/// Preview features may change without warning.
|
||||
///
|
||||
/// Use comma-separated values or pass multiple times to enable multiple features.
|
||||
///
|
||||
/// The following features are available: `python-install-default`, `python-upgrade`,
|
||||
/// `json-output`, `pylock`, `add-bounds`.
|
||||
#[arg(
|
||||
global = true,
|
||||
long = "preview-features",
|
||||
env = EnvVars::UV_PREVIEW_FEATURES,
|
||||
value_delimiter = ',',
|
||||
hide = true,
|
||||
alias = "preview-feature",
|
||||
value_enum,
|
||||
)]
|
||||
pub preview_features: Vec<PreviewFeatures>,
|
||||
|
||||
/// Avoid discovering a `pyproject.toml` or `uv.toml` file.
|
||||
///
|
||||
/// Normally, configuration files are discovered in the current directory,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ uv-pep440 = { workspace = true }
|
|||
uv-pep508 = { workspace = true, features = ["schemars"] }
|
||||
uv-platform-tags = { workspace = true }
|
||||
uv-static = { workspace = true }
|
||||
uv-warnings = { workspace = true }
|
||||
|
||||
bitflags = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive"], optional = true }
|
||||
either = { workspace = true }
|
||||
fs-err = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,37 +1,250 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
use std::{
|
||||
fmt::{Display, Formatter},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use thiserror::Error;
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub struct PreviewFeatures: u32 {
|
||||
const PYTHON_INSTALL_DEFAULT = 1 << 0;
|
||||
const PYTHON_UPGRADE = 1 << 1;
|
||||
const JSON_OUTPUT = 1 << 2;
|
||||
const PYLOCK = 1 << 3;
|
||||
const ADD_BOUNDS = 1 << 4;
|
||||
const EXTRA_BUILD_DEPENDENCIES = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
impl PreviewFeatures {
|
||||
/// Returns the string representation of a single preview feature flag.
|
||||
///
|
||||
/// Panics if given a combination of flags.
|
||||
fn flag_as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::PYTHON_INSTALL_DEFAULT => "python-install-default",
|
||||
Self::PYTHON_UPGRADE => "python-upgrade",
|
||||
Self::JSON_OUTPUT => "json-output",
|
||||
Self::PYLOCK => "pylock",
|
||||
Self::ADD_BOUNDS => "add-bounds",
|
||||
Self::EXTRA_BUILD_DEPENDENCIES => "extra-build-dependencies",
|
||||
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PreviewFeatures {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
if self.is_empty() {
|
||||
write!(f, "none")
|
||||
} else {
|
||||
let features: Vec<&str> = self.iter().map(PreviewFeatures::flag_as_str).collect();
|
||||
write!(f, "{}", features.join(","))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Clone)]
|
||||
pub enum PreviewFeaturesParseError {
|
||||
#[error("Empty string in preview features: {0}")]
|
||||
Empty(String),
|
||||
}
|
||||
|
||||
impl FromStr for PreviewFeatures {
|
||||
type Err = PreviewFeaturesParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut flags = PreviewFeatures::empty();
|
||||
|
||||
for part in s.split(',') {
|
||||
let part = part.trim();
|
||||
if part.is_empty() {
|
||||
return Err(PreviewFeaturesParseError::Empty(
|
||||
"Empty string in preview features".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let flag = match part {
|
||||
"python-install-default" => Self::PYTHON_INSTALL_DEFAULT,
|
||||
"python-upgrade" => Self::PYTHON_UPGRADE,
|
||||
"json-output" => Self::JSON_OUTPUT,
|
||||
"pylock" => Self::PYLOCK,
|
||||
"add-bounds" => Self::ADD_BOUNDS,
|
||||
"extra-build-dependencies" => Self::EXTRA_BUILD_DEPENDENCIES,
|
||||
_ => {
|
||||
warn_user_once!("Unknown preview feature: `{part}`");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
flags |= flag;
|
||||
}
|
||||
|
||||
Ok(flags)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum PreviewMode {
|
||||
#[default]
|
||||
Disabled,
|
||||
Enabled,
|
||||
pub struct Preview {
|
||||
flags: PreviewFeatures,
|
||||
}
|
||||
|
||||
impl PreviewMode {
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
matches!(self, Self::Enabled)
|
||||
impl Preview {
|
||||
pub fn new(flags: PreviewFeatures) -> Self {
|
||||
Self { flags }
|
||||
}
|
||||
|
||||
pub fn is_disabled(&self) -> bool {
|
||||
matches!(self, Self::Disabled)
|
||||
pub fn all() -> Self {
|
||||
Self::new(PreviewFeatures::all())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for PreviewMode {
|
||||
fn from(version: bool) -> Self {
|
||||
if version {
|
||||
PreviewMode::Enabled
|
||||
} else {
|
||||
PreviewMode::Disabled
|
||||
pub fn from_args(
|
||||
preview: bool,
|
||||
no_preview: bool,
|
||||
preview_features: &[PreviewFeatures],
|
||||
) -> Self {
|
||||
if no_preview {
|
||||
return Self::default();
|
||||
}
|
||||
|
||||
if preview {
|
||||
return Self::all();
|
||||
}
|
||||
|
||||
let mut flags = PreviewFeatures::empty();
|
||||
|
||||
for features in preview_features {
|
||||
flags |= *features;
|
||||
}
|
||||
|
||||
Self { flags }
|
||||
}
|
||||
|
||||
pub fn is_enabled(&self, flag: PreviewFeatures) -> bool {
|
||||
self.flags.contains(flag)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PreviewMode {
|
||||
impl Display for Preview {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Disabled => write!(f, "disabled"),
|
||||
Self::Enabled => write!(f, "enabled"),
|
||||
if self.flags.is_empty() {
|
||||
write!(f, "disabled")
|
||||
} else if self.flags == PreviewFeatures::all() {
|
||||
write!(f, "enabled")
|
||||
} else {
|
||||
write!(f, "{}", self.flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_preview_features_from_str() {
|
||||
// Test single feature
|
||||
let features = PreviewFeatures::from_str("python-install-default").unwrap();
|
||||
assert_eq!(features, PreviewFeatures::PYTHON_INSTALL_DEFAULT);
|
||||
|
||||
// Test multiple features
|
||||
let features = PreviewFeatures::from_str("python-upgrade,json-output").unwrap();
|
||||
assert!(features.contains(PreviewFeatures::PYTHON_UPGRADE));
|
||||
assert!(features.contains(PreviewFeatures::JSON_OUTPUT));
|
||||
assert!(!features.contains(PreviewFeatures::PYLOCK));
|
||||
|
||||
// Test with whitespace
|
||||
let features = PreviewFeatures::from_str("pylock , add-bounds").unwrap();
|
||||
assert!(features.contains(PreviewFeatures::PYLOCK));
|
||||
assert!(features.contains(PreviewFeatures::ADD_BOUNDS));
|
||||
|
||||
// Test empty string error
|
||||
assert!(PreviewFeatures::from_str("").is_err());
|
||||
assert!(PreviewFeatures::from_str("pylock,").is_err());
|
||||
assert!(PreviewFeatures::from_str(",pylock").is_err());
|
||||
|
||||
// Test unknown feature (should be ignored with warning)
|
||||
let features = PreviewFeatures::from_str("unknown-feature,pylock").unwrap();
|
||||
assert!(features.contains(PreviewFeatures::PYLOCK));
|
||||
assert_eq!(features.bits().count_ones(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_preview_features_display() {
|
||||
// Test empty
|
||||
let features = PreviewFeatures::empty();
|
||||
assert_eq!(features.to_string(), "none");
|
||||
|
||||
// Test single feature
|
||||
let features = PreviewFeatures::PYTHON_INSTALL_DEFAULT;
|
||||
assert_eq!(features.to_string(), "python-install-default");
|
||||
|
||||
// Test multiple features
|
||||
let features = PreviewFeatures::PYTHON_UPGRADE | PreviewFeatures::JSON_OUTPUT;
|
||||
assert_eq!(features.to_string(), "python-upgrade,json-output");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_preview_display() {
|
||||
// Test disabled
|
||||
let preview = Preview::default();
|
||||
assert_eq!(preview.to_string(), "disabled");
|
||||
|
||||
// Test enabled (all features)
|
||||
let preview = Preview::all();
|
||||
assert_eq!(preview.to_string(), "enabled");
|
||||
|
||||
// Test specific features
|
||||
let preview = Preview::new(PreviewFeatures::PYTHON_UPGRADE | PreviewFeatures::PYLOCK);
|
||||
assert_eq!(preview.to_string(), "python-upgrade,pylock");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_preview_from_args() {
|
||||
// Test no_preview
|
||||
let preview = Preview::from_args(true, true, &[]);
|
||||
assert_eq!(preview.to_string(), "disabled");
|
||||
|
||||
// Test preview (all features)
|
||||
let preview = Preview::from_args(true, false, &[]);
|
||||
assert_eq!(preview.to_string(), "enabled");
|
||||
|
||||
// Test specific features
|
||||
let features = vec![
|
||||
PreviewFeatures::PYTHON_UPGRADE,
|
||||
PreviewFeatures::JSON_OUTPUT,
|
||||
];
|
||||
let preview = Preview::from_args(false, false, &features);
|
||||
assert!(preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE));
|
||||
assert!(preview.is_enabled(PreviewFeatures::JSON_OUTPUT));
|
||||
assert!(!preview.is_enabled(PreviewFeatures::PYLOCK));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_str_single_flags() {
|
||||
assert_eq!(
|
||||
PreviewFeatures::PYTHON_INSTALL_DEFAULT.flag_as_str(),
|
||||
"python-install-default"
|
||||
);
|
||||
assert_eq!(
|
||||
PreviewFeatures::PYTHON_UPGRADE.flag_as_str(),
|
||||
"python-upgrade"
|
||||
);
|
||||
assert_eq!(PreviewFeatures::JSON_OUTPUT.flag_as_str(), "json-output");
|
||||
assert_eq!(PreviewFeatures::PYLOCK.flag_as_str(), "pylock");
|
||||
assert_eq!(PreviewFeatures::ADD_BOUNDS.flag_as_str(), "add-bounds");
|
||||
assert_eq!(
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES.flag_as_str(),
|
||||
"extra-build-dependencies"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "`flag_as_str` can only be used for exactly one feature flag")]
|
||||
fn test_as_str_multiple_flags_panics() {
|
||||
let features = PreviewFeatures::PYTHON_UPGRADE | PreviewFeatures::JSON_OUTPUT;
|
||||
let _ = features.flag_as_str();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use clap::Parser;
|
|||
use tracing::info;
|
||||
|
||||
use uv_cache::{Cache, CacheArgs};
|
||||
use uv_configuration::{Concurrency, PreviewMode};
|
||||
use uv_configuration::{Concurrency, Preview};
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
|
||||
#[derive(Parser)]
|
||||
|
|
@ -26,7 +26,7 @@ pub(crate) async fn compile(args: CompileArgs) -> anyhow::Result<()> {
|
|||
&PythonRequest::default(),
|
||||
EnvironmentPreference::OnlyVirtual,
|
||||
&cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)?
|
||||
.into_interpreter();
|
||||
interpreter.sys_executable().to_path_buf()
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use uv_cache::Cache;
|
|||
use uv_client::RegistryClient;
|
||||
use uv_configuration::{
|
||||
BuildKind, BuildOptions, ConfigSettings, Constraints, IndexStrategy, PackageConfigSettings,
|
||||
PreviewMode, Reinstall, SourceStrategy,
|
||||
Preview, Reinstall, SourceStrategy,
|
||||
};
|
||||
use uv_configuration::{BuildOutput, Concurrency};
|
||||
use uv_distribution::DistributionDatabase;
|
||||
|
|
@ -101,7 +101,7 @@ pub struct BuildDispatch<'a> {
|
|||
sources: SourceStrategy,
|
||||
workspace_cache: WorkspaceCache,
|
||||
concurrency: Concurrency,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
}
|
||||
|
||||
impl<'a> BuildDispatch<'a> {
|
||||
|
|
@ -126,7 +126,7 @@ impl<'a> BuildDispatch<'a> {
|
|||
sources: SourceStrategy,
|
||||
workspace_cache: WorkspaceCache,
|
||||
concurrency: Concurrency,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Self {
|
||||
Self {
|
||||
client,
|
||||
|
|
|
|||
|
|
@ -203,7 +203,11 @@ impl serde::ser::Serialize for IndexUrl {
|
|||
where
|
||||
S: serde::ser::Serializer,
|
||||
{
|
||||
self.to_string().serialize(serializer)
|
||||
match self {
|
||||
Self::Pypi(url) => url.without_credentials().serialize(serializer),
|
||||
Self::Url(url) => url.without_credentials().serialize(serializer),
|
||||
Self::Path(url) => url.without_credentials().serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -396,14 +400,17 @@ impl<'a> IndexLocations {
|
|||
///
|
||||
/// This includes explicit indexes, implicit indexes, flat indexes, and the default index.
|
||||
///
|
||||
/// The indexes will be returned in the order in which they were defined, such that the
|
||||
/// last-defined index is the last item in the vector.
|
||||
/// The indexes will be returned in the reverse of the order in which they were defined, such
|
||||
/// that the last-defined index is the first item in the vector.
|
||||
pub fn allowed_indexes(&'a self) -> Vec<&'a Index> {
|
||||
if self.no_index {
|
||||
self.flat_index.iter().rev().collect()
|
||||
} else {
|
||||
let mut indexes = vec![];
|
||||
|
||||
// TODO(charlie): By only yielding the first default URL, we'll drop credentials if,
|
||||
// e.g., an authenticated default URL is provided in a configuration file, but an
|
||||
// unauthenticated default URL is present in the receipt.
|
||||
let mut seen = FxHashSet::default();
|
||||
let mut default = false;
|
||||
for index in {
|
||||
|
|
@ -429,9 +436,29 @@ impl<'a> IndexLocations {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return a vector containing all known [`Index`] entries.
|
||||
///
|
||||
/// This includes explicit indexes, implicit indexes, flat indexes, and default indexes;
|
||||
/// in short, it includes all defined indexes, even if they're overridden by some other index
|
||||
/// definition.
|
||||
///
|
||||
/// The indexes will be returned in the reverse of the order in which they were defined, such
|
||||
/// that the last-defined index is the first item in the vector.
|
||||
pub fn known_indexes(&'a self) -> impl Iterator<Item = &'a Index> {
|
||||
if self.no_index {
|
||||
Either::Left(self.flat_index.iter().rev())
|
||||
} else {
|
||||
Either::Right(
|
||||
std::iter::once(&*DEFAULT_INDEX)
|
||||
.chain(self.flat_index.iter().rev())
|
||||
.chain(self.indexes.iter().rev()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add all authenticated sources to the cache.
|
||||
pub fn cache_index_credentials(&self) {
|
||||
for index in self.allowed_indexes() {
|
||||
for index in self.known_indexes() {
|
||||
if let Some(credentials) = index.credentials() {
|
||||
let credentials = Arc::new(credentials);
|
||||
uv_auth::store_credentials(index.raw_url(), credentials.clone());
|
||||
|
|
|
|||
|
|
@ -91,13 +91,21 @@ impl CompatibleDist<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
// For installable distributions, return the prioritized distribution it was derived from.
|
||||
pub fn prioritized(&self) -> Option<&PrioritizedDist> {
|
||||
match self {
|
||||
CompatibleDist::InstalledDist(_) => None,
|
||||
CompatibleDist::SourceDist { prioritized, .. }
|
||||
| CompatibleDist::CompatibleWheel { prioritized, .. }
|
||||
| CompatibleDist::IncompatibleWheel { prioritized, .. } => Some(prioritized),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the set of supported platform the distribution, in terms of their markers.
|
||||
pub fn implied_markers(&self) -> MarkerTree {
|
||||
match self {
|
||||
CompatibleDist::InstalledDist(_) => MarkerTree::TRUE,
|
||||
CompatibleDist::SourceDist { prioritized, .. } => prioritized.0.markers,
|
||||
CompatibleDist::CompatibleWheel { prioritized, .. } => prioritized.0.markers,
|
||||
CompatibleDist::IncompatibleWheel { prioritized, .. } => prioritized.0.markers,
|
||||
match self.prioritized() {
|
||||
Some(prioritized) => prioritized.0.markers,
|
||||
None => MarkerTree::TRUE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::{env, io, iter};
|
|||
use std::{path::Path, path::PathBuf, str::FromStr};
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, instrument, trace};
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use which::{which, which_all};
|
||||
|
||||
use uv_cache::Cache;
|
||||
|
|
@ -335,7 +335,7 @@ fn python_executables_from_installed<'a>(
|
|||
implementation: Option<&'a ImplementationName>,
|
||||
platform: PlatformRequest,
|
||||
preference: PythonPreference,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Box<dyn Iterator<Item = Result<(PythonSource, PathBuf), Error>> + 'a> {
|
||||
let from_managed_installations = iter::once_with(move || {
|
||||
ManagedPythonInstallations::from_settings(None)
|
||||
|
|
@ -485,7 +485,7 @@ fn python_executables<'a>(
|
|||
platform: PlatformRequest,
|
||||
environments: EnvironmentPreference,
|
||||
preference: PythonPreference,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Box<dyn Iterator<Item = Result<(PythonSource, PathBuf), Error>> + 'a> {
|
||||
// Always read from `UV_INTERNAL__PARENT_INTERPRETER` — it could be a system interpreter
|
||||
let from_parent_interpreter = iter::once_with(|| {
|
||||
|
|
@ -705,7 +705,7 @@ fn python_interpreters<'a>(
|
|||
environments: EnvironmentPreference,
|
||||
preference: PythonPreference,
|
||||
cache: &'a Cache,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> impl Iterator<Item = Result<(PythonSource, Interpreter), Error>> + 'a {
|
||||
python_interpreters_from_executables(
|
||||
// Perform filtering on the discovered executables based on their source. This avoids
|
||||
|
|
@ -1053,7 +1053,7 @@ pub fn find_python_installations<'a>(
|
|||
environments: EnvironmentPreference,
|
||||
preference: PythonPreference,
|
||||
cache: &'a Cache,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Box<dyn Iterator<Item = Result<FindPythonResult, Error>> + 'a> {
|
||||
let sources = DiscoveryPreferences {
|
||||
python_preference: preference,
|
||||
|
|
@ -1254,7 +1254,7 @@ pub(crate) fn find_python_installation(
|
|||
environments: EnvironmentPreference,
|
||||
preference: PythonPreference,
|
||||
cache: &Cache,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<FindPythonResult, Error> {
|
||||
let installations =
|
||||
find_python_installations(request, environments, preference, cache, preview);
|
||||
|
|
@ -1353,7 +1353,7 @@ pub(crate) fn find_best_python_installation(
|
|||
environments: EnvironmentPreference,
|
||||
preference: PythonPreference,
|
||||
cache: &Cache,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<FindPythonResult, Error> {
|
||||
debug!("Starting Python discovery for {}", request);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use owo_colors::OwoColorize;
|
|||
use tracing::debug;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_fs::{LockedFile, Simplified};
|
||||
use uv_pep440::Version;
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ impl PythonEnvironment {
|
|||
request: &PythonRequest,
|
||||
preference: EnvironmentPreference,
|
||||
cache: &Cache,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, Error> {
|
||||
let installation = match find_python_installation(
|
||||
request,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use tracing::{debug, info};
|
|||
|
||||
use uv_cache::Cache;
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_pep440::{Prerelease, Version};
|
||||
|
||||
use crate::discovery::{
|
||||
|
|
@ -58,7 +58,7 @@ impl PythonInstallation {
|
|||
environments: EnvironmentPreference,
|
||||
preference: PythonPreference,
|
||||
cache: &Cache,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, Error> {
|
||||
let installation =
|
||||
find_python_installation(request, environments, preference, cache, preview)??;
|
||||
|
|
@ -72,7 +72,7 @@ impl PythonInstallation {
|
|||
environments: EnvironmentPreference,
|
||||
preference: PythonPreference,
|
||||
cache: &Cache,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(find_best_python_installation(
|
||||
request,
|
||||
|
|
@ -97,7 +97,7 @@ impl PythonInstallation {
|
|||
python_install_mirror: Option<&str>,
|
||||
pypy_install_mirror: Option<&str>,
|
||||
python_downloads_json_url: Option<&str>,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, Error> {
|
||||
let request = request.unwrap_or(&PythonRequest::Default);
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ impl PythonInstallation {
|
|||
reporter: Option<&dyn Reporter>,
|
||||
python_install_mirror: Option<&str>,
|
||||
pypy_install_mirror: Option<&str>,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, Error> {
|
||||
let installations = ManagedPythonInstallations::from_settings(None)?.init()?;
|
||||
let installations_dir = installations.root();
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ mod tests {
|
|||
use indoc::{formatdoc, indoc};
|
||||
use temp_env::with_vars;
|
||||
use test_log::test;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_static::EnvVars;
|
||||
|
||||
use uv_cache::Cache;
|
||||
|
|
@ -468,7 +468,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::default(),
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
});
|
||||
assert!(
|
||||
|
|
@ -483,7 +483,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::default(),
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
});
|
||||
assert!(
|
||||
|
|
@ -508,7 +508,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::default(),
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
});
|
||||
assert!(
|
||||
|
|
@ -530,7 +530,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::default(),
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert!(
|
||||
|
|
@ -592,7 +592,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::default(),
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert!(
|
||||
|
|
@ -624,7 +624,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::default(),
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
});
|
||||
assert!(
|
||||
|
|
@ -661,7 +661,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::default(),
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert!(
|
||||
|
|
@ -693,7 +693,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -715,7 +715,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -741,7 +741,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -767,7 +767,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -790,7 +790,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
|
||||
|
|
@ -824,7 +824,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
|
||||
|
|
@ -858,7 +858,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -880,7 +880,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -902,7 +902,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
|
||||
|
|
@ -936,7 +936,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
|
||||
|
|
@ -973,7 +973,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert!(
|
||||
|
|
@ -1004,7 +1004,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert!(
|
||||
|
|
@ -1039,7 +1039,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1065,7 +1065,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1092,7 +1092,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlyVirtual,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1117,7 +1117,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlyVirtual,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
|
@ -1139,7 +1139,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1162,7 +1162,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlyVirtual,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1195,7 +1195,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1216,7 +1216,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1243,7 +1243,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
|
||||
|
|
@ -1261,7 +1261,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
|
||||
|
|
@ -1290,7 +1290,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1328,7 +1328,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1356,7 +1356,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1381,7 +1381,7 @@ mod tests {
|
|||
EnvironmentPreference::ExplicitSystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1406,7 +1406,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1431,7 +1431,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlyVirtual,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1469,7 +1469,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1497,7 +1497,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1514,7 +1514,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1531,7 +1531,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -1553,7 +1553,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlyVirtual,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -1570,7 +1570,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
|
@ -1592,7 +1592,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1607,7 +1607,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -1621,7 +1621,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -1650,7 +1650,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1666,7 +1666,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1696,7 +1696,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1712,7 +1712,7 @@ mod tests {
|
|||
EnvironmentPreference::ExplicitSystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1728,7 +1728,7 @@ mod tests {
|
|||
EnvironmentPreference::OnlyVirtual,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1744,7 +1744,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1768,7 +1768,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1783,7 +1783,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1807,7 +1807,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1827,7 +1827,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
},
|
||||
)??;
|
||||
|
|
@ -1856,7 +1856,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1878,7 +1878,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -1908,7 +1908,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -1924,7 +1924,7 @@ mod tests {
|
|||
EnvironmentPreference::ExplicitSystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -1951,7 +1951,7 @@ mod tests {
|
|||
EnvironmentPreference::ExplicitSystem,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
|
|
@ -1976,7 +1976,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -1993,7 +1993,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2008,7 +2008,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2034,7 +2034,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2049,7 +2049,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2075,7 +2075,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2102,7 +2102,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2129,7 +2129,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2156,7 +2156,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2183,7 +2183,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2211,7 +2211,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})?;
|
||||
assert!(
|
||||
|
|
@ -2233,7 +2233,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2248,7 +2248,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2274,7 +2274,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2289,7 +2289,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
assert_eq!(
|
||||
|
|
@ -2327,7 +2327,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
|
|
@ -2345,7 +2345,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
|
|
@ -2387,7 +2387,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
|
|
@ -2405,7 +2405,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
|
|
@ -2442,7 +2442,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
|
|
@ -2465,7 +2465,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
|
|
@ -2488,7 +2488,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
|
|
@ -2527,7 +2527,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
|
||||
|
|
@ -2580,7 +2580,7 @@ mod tests {
|
|||
EnvironmentPreference::Any,
|
||||
PythonPreference::OnlySystem,
|
||||
&context.cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
)
|
||||
})??;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use itertools::Itertools;
|
|||
use same_file::is_same_file;
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, warn};
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::{Preview, PreviewFeatures};
|
||||
#[cfg(windows)]
|
||||
use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
|
||||
|
|
@ -519,7 +519,7 @@ impl ManagedPythonInstallation {
|
|||
|
||||
/// Ensure the environment contains the symlink directory (or junction on Windows)
|
||||
/// pointing to the patch directory for this minor version.
|
||||
pub fn ensure_minor_version_link(&self, preview: PreviewMode) -> Result<(), Error> {
|
||||
pub fn ensure_minor_version_link(&self, preview: Preview) -> Result<(), Error> {
|
||||
if let Some(minor_version_link) = PythonMinorVersionLink::from_installation(self, preview) {
|
||||
minor_version_link.create_directory()?;
|
||||
}
|
||||
|
|
@ -531,7 +531,7 @@ impl ManagedPythonInstallation {
|
|||
///
|
||||
/// Unlike [`ensure_minor_version_link`], will not create a new symlink directory
|
||||
/// if one doesn't already exist,
|
||||
pub fn update_minor_version_link(&self, preview: PreviewMode) -> Result<(), Error> {
|
||||
pub fn update_minor_version_link(&self, preview: Preview) -> Result<(), Error> {
|
||||
if let Some(minor_version_link) = PythonMinorVersionLink::from_installation(self, preview) {
|
||||
if !minor_version_link.exists() {
|
||||
return Ok(());
|
||||
|
|
@ -702,7 +702,7 @@ impl PythonMinorVersionLink {
|
|||
pub fn from_executable(
|
||||
executable: &Path,
|
||||
key: &PythonInstallationKey,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Option<Self> {
|
||||
let implementation = key.implementation();
|
||||
if !matches!(
|
||||
|
|
@ -755,7 +755,7 @@ impl PythonMinorVersionLink {
|
|||
// If preview mode is disabled, still return a `MinorVersionSymlink` for
|
||||
// existing symlinks, allowing continued operations without the `--preview`
|
||||
// flag after initial symlink directory installation.
|
||||
if preview.is_disabled() && !minor_version_link.exists() {
|
||||
if !preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE) && !minor_version_link.exists() {
|
||||
return None;
|
||||
}
|
||||
Some(minor_version_link)
|
||||
|
|
@ -763,7 +763,7 @@ impl PythonMinorVersionLink {
|
|||
|
||||
pub fn from_installation(
|
||||
installation: &ManagedPythonInstallation,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Option<Self> {
|
||||
PythonMinorVersionLink::from_executable(
|
||||
installation.executable(false).as_path(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use ref_cast::RefCast;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
|
@ -98,6 +99,24 @@ impl DisplaySafeUrl {
|
|||
let _ = self.0.set_password(None);
|
||||
}
|
||||
|
||||
/// Returns the URL with any credentials removed.
|
||||
pub fn without_credentials(&self) -> Cow<'_, Url> {
|
||||
if self.0.password().is_none() && self.0.username() == "" {
|
||||
return Cow::Borrowed(&self.0);
|
||||
}
|
||||
|
||||
// For URLs that use the `git` convention (i.e., `ssh://git@github.com/...`), avoid dropping the
|
||||
// username.
|
||||
if is_ssh_git_username(&self.0) {
|
||||
return Cow::Borrowed(&self.0);
|
||||
}
|
||||
|
||||
let mut url = self.0.clone();
|
||||
let _ = url.set_username("");
|
||||
let _ = url.set_password(None);
|
||||
Cow::Owned(url)
|
||||
}
|
||||
|
||||
/// Returns [`Display`] implementation that doesn't mask credentials.
|
||||
#[inline]
|
||||
pub fn displayable_with_credentials(&self) -> impl Display {
|
||||
|
|
|
|||
|
|
@ -266,7 +266,6 @@ impl CandidateSelector {
|
|||
return Some(Candidate {
|
||||
name: package_name,
|
||||
version,
|
||||
prioritized: None,
|
||||
dist: CandidateDist::Compatible(CompatibleDist::InstalledDist(
|
||||
dist,
|
||||
)),
|
||||
|
|
@ -368,7 +367,6 @@ impl CandidateSelector {
|
|||
return Some(Candidate {
|
||||
name: package_name,
|
||||
version,
|
||||
prioritized: None,
|
||||
dist: CandidateDist::Compatible(CompatibleDist::InstalledDist(dist)),
|
||||
choice_kind: VersionChoiceKind::Installed,
|
||||
});
|
||||
|
|
@ -546,10 +544,14 @@ impl CandidateSelector {
|
|||
// exclude-newer in our error messages.
|
||||
if matches!(
|
||||
candidate.dist(),
|
||||
CandidateDist::Incompatible(
|
||||
IncompatibleDist::Source(IncompatibleSource::ExcludeNewer(_))
|
||||
| IncompatibleDist::Wheel(IncompatibleWheel::ExcludeNewer(_))
|
||||
)
|
||||
CandidateDist::Incompatible {
|
||||
incompatible_dist: IncompatibleDist::Source(IncompatibleSource::ExcludeNewer(
|
||||
_
|
||||
)) | IncompatibleDist::Wheel(
|
||||
IncompatibleWheel::ExcludeNewer(_)
|
||||
),
|
||||
..
|
||||
}
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -572,7 +574,7 @@ impl CandidateSelector {
|
|||
// even though there are compatible wheels on PyPI. Thus, we need to ensure that we
|
||||
// return the first _compatible_ candidate across all indexes, if such a candidate
|
||||
// exists.
|
||||
if matches!(candidate.dist(), CandidateDist::Incompatible(_)) {
|
||||
if matches!(candidate.dist(), CandidateDist::Incompatible { .. }) {
|
||||
if incompatible.is_none() {
|
||||
incompatible = Some(candidate);
|
||||
}
|
||||
|
|
@ -602,7 +604,25 @@ impl CandidateSelector {
|
|||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum CandidateDist<'a> {
|
||||
Compatible(CompatibleDist<'a>),
|
||||
Incompatible(IncompatibleDist),
|
||||
Incompatible {
|
||||
/// The reason the prioritized distribution is incompatible.
|
||||
incompatible_dist: IncompatibleDist,
|
||||
/// The prioritized distribution that had no compatible wheelr or sdist.
|
||||
prioritized_dist: &'a PrioritizedDist,
|
||||
},
|
||||
}
|
||||
|
||||
impl CandidateDist<'_> {
|
||||
/// For an installable dist, return the prioritized distribution.
|
||||
fn prioritized(&self) -> Option<&PrioritizedDist> {
|
||||
match self {
|
||||
CandidateDist::Compatible(dist) => dist.prioritized(),
|
||||
CandidateDist::Incompatible {
|
||||
incompatible_dist: _,
|
||||
prioritized_dist: prioritized,
|
||||
} => Some(prioritized),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a PrioritizedDist> for CandidateDist<'a> {
|
||||
|
|
@ -621,7 +641,10 @@ impl<'a> From<&'a PrioritizedDist> for CandidateDist<'a> {
|
|||
} else {
|
||||
IncompatibleDist::Unavailable
|
||||
};
|
||||
CandidateDist::Incompatible(dist)
|
||||
CandidateDist::Incompatible {
|
||||
incompatible_dist: dist,
|
||||
prioritized_dist: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -654,8 +677,6 @@ pub(crate) struct Candidate<'a> {
|
|||
name: &'a PackageName,
|
||||
/// The version of the package.
|
||||
version: &'a Version,
|
||||
/// The prioritized distribution for the package.
|
||||
prioritized: Option<&'a PrioritizedDist>,
|
||||
/// The distributions to use for resolving and installing the package.
|
||||
dist: CandidateDist<'a>,
|
||||
/// Whether this candidate was selected from a preference.
|
||||
|
|
@ -672,7 +693,6 @@ impl<'a> Candidate<'a> {
|
|||
Self {
|
||||
name,
|
||||
version,
|
||||
prioritized: Some(dist),
|
||||
dist: CandidateDist::from(dist),
|
||||
choice_kind,
|
||||
}
|
||||
|
|
@ -709,7 +729,7 @@ impl<'a> Candidate<'a> {
|
|||
|
||||
/// Return the prioritized distribution for the candidate.
|
||||
pub(crate) fn prioritized(&self) -> Option<&PrioritizedDist> {
|
||||
self.prioritized
|
||||
self.dist.prioritized()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1431,7 +1431,7 @@ impl Lock {
|
|||
}
|
||||
|
||||
// Collect the set of available indexes (both `--index-url` and `--find-links` entries).
|
||||
let remotes = indexes.map(|locations| {
|
||||
let mut remotes = indexes.map(|locations| {
|
||||
locations
|
||||
.allowed_indexes()
|
||||
.into_iter()
|
||||
|
|
@ -1444,7 +1444,7 @@ impl Lock {
|
|||
.collect::<BTreeSet<_>>()
|
||||
});
|
||||
|
||||
let locals = indexes.map(|locations| {
|
||||
let mut locals = indexes.map(|locations| {
|
||||
locations
|
||||
.allowed_indexes()
|
||||
.into_iter()
|
||||
|
|
@ -1717,6 +1717,38 @@ impl Lock {
|
|||
return Ok(SatisfiesResult::MissingVersion(&package.id.name));
|
||||
}
|
||||
|
||||
// Add any explicit indexes to the list of known locals or remotes. These indexes may
|
||||
// not be available as top-level configuration (i.e., if they're defined within a
|
||||
// workspace member), but we already validated that the dependencies are up-to-date, so
|
||||
// we can consider them "available".
|
||||
for requirement in &package.metadata.requires_dist {
|
||||
if let RequirementSource::Registry {
|
||||
index: Some(index), ..
|
||||
} = &requirement.source
|
||||
{
|
||||
match &index.url {
|
||||
IndexUrl::Pypi(_) | IndexUrl::Url(_) => {
|
||||
if let Some(remotes) = remotes.as_mut() {
|
||||
remotes.insert(UrlString::from(
|
||||
index.url().without_credentials().as_ref(),
|
||||
));
|
||||
}
|
||||
}
|
||||
IndexUrl::Path(url) => {
|
||||
if let Some(locals) = locals.as_mut() {
|
||||
if let Some(path) = url.to_file_path().ok().and_then(|path| {
|
||||
relative_to(&path, root)
|
||||
.or_else(|_| std::path::absolute(path))
|
||||
.ok()
|
||||
}) {
|
||||
locals.insert(path.into_boxed_path());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse.
|
||||
for dep in &package.dependencies {
|
||||
if seen.insert(&dep.package_id) {
|
||||
|
|
|
|||
|
|
@ -1271,7 +1271,10 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
|
||||
let dist = match candidate.dist() {
|
||||
CandidateDist::Compatible(dist) => dist,
|
||||
CandidateDist::Incompatible(incompatibility) => {
|
||||
CandidateDist::Incompatible {
|
||||
incompatible_dist: incompatibility,
|
||||
prioritized_dist: _,
|
||||
} => {
|
||||
// If the version is incompatible because no distributions are compatible, exit early.
|
||||
return Ok(Some(ResolverVersion::Unavailable(
|
||||
candidate.version().clone(),
|
||||
|
|
@ -3779,9 +3782,7 @@ impl Fork {
|
|||
if self.env.included_by_group(conflicting_item) {
|
||||
return true;
|
||||
}
|
||||
if let Some(conflicting_item) = dep.package.conflicting_item() {
|
||||
self.conflicts.remove(&conflicting_item);
|
||||
}
|
||||
self.conflicts.remove(&conflicting_item);
|
||||
false
|
||||
});
|
||||
Some(self)
|
||||
|
|
|
|||
|
|
@ -225,6 +225,9 @@ impl EnvVars {
|
|||
/// Equivalent to the `--preview` argument. Enables preview mode.
|
||||
pub const UV_PREVIEW: &'static str = "UV_PREVIEW";
|
||||
|
||||
/// Equivalent to the `--preview-features` argument. Enables specific preview features.
|
||||
pub const UV_PREVIEW_FEATURES: &'static str = "UV_PREVIEW_FEATURES";
|
||||
|
||||
/// Equivalent to the `--token` argument for self update. A GitHub token for authentication.
|
||||
pub const UV_GITHUB_TOKEN: &'static str = "UV_GITHUB_TOKEN";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use core::fmt;
|
||||
use fs_err as fs;
|
||||
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_dirs::user_executable_directory;
|
||||
use uv_pep440::Version;
|
||||
use uv_pep508::{InvalidNameError, PackageName};
|
||||
|
|
@ -258,7 +258,7 @@ impl InstalledTools {
|
|||
&self,
|
||||
name: &PackageName,
|
||||
interpreter: Interpreter,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<PythonEnvironment, Error> {
|
||||
let environment_path = self.tool_dir(name);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uv-version"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::path::Path;
|
|||
|
||||
use thiserror::Error;
|
||||
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_python::{Interpreter, PythonEnvironment};
|
||||
|
||||
pub use virtualenv::{OnExisting, remove_virtualenv};
|
||||
|
|
@ -56,7 +56,7 @@ pub fn create_venv(
|
|||
relocatable: bool,
|
||||
seed: bool,
|
||||
upgradeable: bool,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<PythonEnvironment, Error> {
|
||||
// Create the virtualenv at the given location.
|
||||
let virtualenv = virtualenv::create(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use itertools::Itertools;
|
|||
use owo_colors::OwoColorize;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_fs::{CWD, Simplified, cachedir};
|
||||
use uv_pypi_types::Scheme;
|
||||
use uv_python::managed::{PythonMinorVersionLink, create_link_to_executable};
|
||||
|
|
@ -59,7 +59,7 @@ pub(crate) fn create(
|
|||
relocatable: bool,
|
||||
seed: bool,
|
||||
upgradeable: bool,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<VirtualEnvironment, Error> {
|
||||
// Determine the base Python executable; that is, the Python executable that should be
|
||||
// considered the "base" for the virtual environment.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uv"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
|||
use uv_configuration::{
|
||||
BuildKind, BuildOptions, BuildOutput, Concurrency, ConfigSettings, Constraints,
|
||||
DependencyGroupsWithDefaults, HashCheckingMode, IndexStrategy, KeyringProviderType,
|
||||
PackageConfigSettings, PreviewMode, SourceStrategy,
|
||||
PackageConfigSettings, Preview, SourceStrategy,
|
||||
};
|
||||
use uv_dispatch::{BuildDispatch, SharedState};
|
||||
use uv_distribution_filename::{
|
||||
|
|
@ -118,7 +118,7 @@ pub(crate) async fn build_frontend(
|
|||
concurrency: Concurrency,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let build_result = build_impl(
|
||||
project_dir,
|
||||
|
|
@ -186,7 +186,7 @@ async fn build_impl(
|
|||
concurrency: Concurrency,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<BuildResult> {
|
||||
// Extract the resolver settings.
|
||||
let ResolverSettings {
|
||||
|
|
@ -441,7 +441,7 @@ async fn build_package(
|
|||
link_mode: LinkMode,
|
||||
config_setting: &ConfigSettings,
|
||||
config_settings_package: &PackageConfigSettings,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Vec<BuildMessage>, Error> {
|
||||
let output_dir = if let Some(output_dir) = output_dir {
|
||||
Cow::Owned(std::path::absolute(output_dir)?)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use anyhow::Result;
|
|||
use owo_colors::OwoColorize;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_distribution_types::{Diagnostic, InstalledDist};
|
||||
use uv_installer::{SitePackages, SitePackagesDiagnostic};
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
|
|
@ -20,7 +20,7 @@ pub(crate) fn pip_check(
|
|||
system: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let start = Instant::now();
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use uv_cache::Cache;
|
|||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
BuildOptions, Concurrency, ConfigSettings, Constraints, ExportFormat, ExtrasSpecification,
|
||||
IndexStrategy, NoBinary, NoBuild, PackageConfigSettings, PreviewMode, Reinstall,
|
||||
IndexStrategy, NoBinary, NoBuild, PackageConfigSettings, Preview, PreviewFeatures, Reinstall,
|
||||
SourceStrategy, Upgrade,
|
||||
};
|
||||
use uv_configuration::{KeyringProviderType, TargetTriple};
|
||||
|
|
@ -112,11 +112,14 @@ pub(crate) async fn pip_compile(
|
|||
quiet: bool,
|
||||
cache: Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
if preview.is_disabled() && !extra_build_dependencies.is_empty() {
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use itertools::Itertools;
|
|||
use owo_colors::OwoColorize;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_distribution_types::{Diagnostic, InstalledDist, Name};
|
||||
use uv_installer::SitePackages;
|
||||
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
|
||||
|
|
@ -24,7 +24,7 @@ pub(crate) fn pip_freeze(
|
|||
paths: Option<Vec<PathBuf>>,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
// Detect the current Python interpreter.
|
||||
let environment = PythonEnvironment::find(
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use uv_cache::Cache;
|
|||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
BuildOptions, Concurrency, ConfigSettings, Constraints, DryRun, ExtrasSpecification,
|
||||
HashCheckingMode, IndexStrategy, PackageConfigSettings, PreviewMode, Reinstall, SourceStrategy,
|
||||
Upgrade,
|
||||
HashCheckingMode, IndexStrategy, PackageConfigSettings, Preview, PreviewFeatures, Reinstall,
|
||||
SourceStrategy, Upgrade,
|
||||
};
|
||||
use uv_configuration::{KeyringProviderType, TargetTriple};
|
||||
use uv_dispatch::{BuildDispatch, SharedState};
|
||||
|
|
@ -97,13 +97,16 @@ pub(crate) async fn pip_install(
|
|||
cache: Cache,
|
||||
dry_run: DryRun,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> anyhow::Result<ExitStatus> {
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
if preview.is_disabled() && !extra_build_dependencies.is_empty() {
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -141,9 +144,10 @@ pub(crate) async fn pip_install(
|
|||
.await?;
|
||||
|
||||
if pylock.is_some() {
|
||||
if preview.is_disabled() {
|
||||
if !preview.is_enabled(PreviewFeatures::PYLOCK) {
|
||||
warn_user!(
|
||||
"The `--pylock` setting is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `--pylock` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::PYLOCK
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use uv_cache::{Cache, Refresh};
|
|||
use uv_cache_info::Timestamp;
|
||||
use uv_cli::ListFormat;
|
||||
use uv_client::{BaseClientBuilder, RegistryClientBuilder};
|
||||
use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType, PreviewMode};
|
||||
use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType, Preview};
|
||||
use uv_distribution_filename::DistFilename;
|
||||
use uv_distribution_types::{
|
||||
Diagnostic, IndexCapabilities, IndexLocations, InstalledDist, Name, RequiresPython,
|
||||
|
|
@ -54,7 +54,7 @@ pub(crate) async fn pip_list(
|
|||
system: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
// Disallow `--outdated` with `--format freeze`.
|
||||
if outdated && matches!(format, ListFormat::Freeze) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use owo_colors::OwoColorize;
|
|||
use rustc_hash::FxHashMap;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_distribution_types::{Diagnostic, Name};
|
||||
use uv_fs::Simplified;
|
||||
use uv_install_wheel::read_record_file;
|
||||
|
|
@ -28,7 +28,7 @@ pub(crate) fn pip_show(
|
|||
files: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
if packages.is_empty() {
|
||||
#[allow(clippy::print_stderr)]
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ use uv_cache::Cache;
|
|||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
BuildOptions, Concurrency, ConfigSettings, Constraints, DryRun, ExtrasSpecification,
|
||||
HashCheckingMode, IndexStrategy, PackageConfigSettings, PreviewMode, Reinstall, SourceStrategy,
|
||||
Upgrade,
|
||||
HashCheckingMode, IndexStrategy, PackageConfigSettings, Preview, PreviewFeatures, Reinstall,
|
||||
SourceStrategy, Upgrade,
|
||||
};
|
||||
use uv_configuration::{KeyringProviderType, TargetTriple};
|
||||
use uv_dispatch::{BuildDispatch, SharedState};
|
||||
|
|
@ -85,11 +85,14 @@ pub(crate) async fn pip_sync(
|
|||
cache: Cache,
|
||||
dry_run: DryRun,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
if preview.is_disabled() && !extra_build_dependencies.is_empty() {
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -134,9 +137,10 @@ pub(crate) async fn pip_sync(
|
|||
.await?;
|
||||
|
||||
if pylock.is_some() {
|
||||
if preview.is_disabled() {
|
||||
if !preview.is_enabled(PreviewFeatures::PYLOCK) {
|
||||
warn_user!(
|
||||
"The `--pylock` setting is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `--pylock` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::PYLOCK
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use tokio::sync::Semaphore;
|
|||
use uv_cache::{Cache, Refresh};
|
||||
use uv_cache_info::Timestamp;
|
||||
use uv_client::{BaseClientBuilder, RegistryClientBuilder};
|
||||
use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType, PreviewMode};
|
||||
use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType, Preview};
|
||||
use uv_distribution_types::{Diagnostic, IndexCapabilities, IndexLocations, Name, RequiresPython};
|
||||
use uv_installer::SitePackages;
|
||||
use uv_normalize::PackageName;
|
||||
|
|
@ -52,7 +52,7 @@ pub(crate) async fn pip_tree(
|
|||
system: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
// Detect the current Python interpreter.
|
||||
let environment = PythonEnvironment::find(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use tracing::{debug, warn};
|
|||
|
||||
use uv_cache::Cache;
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::{DryRun, KeyringProviderType, PreviewMode};
|
||||
use uv_configuration::{DryRun, KeyringProviderType, Preview};
|
||||
use uv_distribution_types::Requirement;
|
||||
use uv_distribution_types::{InstalledMetadata, Name, UnresolvedRequirement};
|
||||
use uv_fs::Simplified;
|
||||
|
|
@ -37,7 +37,7 @@ pub(crate) async fn pip_uninstall(
|
|||
network_settings: &NetworkSettings,
|
||||
dry_run: DryRun,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ use uv_cache_key::RepositoryUrl;
|
|||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
Concurrency, Constraints, DependencyGroups, DependencyGroupsWithDefaults, DevMode, DryRun,
|
||||
EditableMode, ExtrasSpecification, ExtrasSpecificationWithDefaults, InstallOptions,
|
||||
PreviewMode, SourceStrategy,
|
||||
EditableMode, ExtrasSpecification, ExtrasSpecificationWithDefaults, InstallOptions, Preview,
|
||||
PreviewFeatures, SourceStrategy,
|
||||
};
|
||||
use uv_dispatch::BuildDispatch;
|
||||
use uv_distribution::DistributionDatabase;
|
||||
|
|
@ -95,15 +95,21 @@ pub(crate) async fn add(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
if bounds.is_some() && preview.is_disabled() {
|
||||
warn_user_once!("The bounds option is in preview and may change in any future release.");
|
||||
if bounds.is_some() && !preview.is_enabled(PreviewFeatures::ADD_BOUNDS) {
|
||||
warn_user_once!(
|
||||
"The `bounds` option is in preview and may change in any future release. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::ADD_BOUNDS
|
||||
);
|
||||
}
|
||||
|
||||
if preview.is_disabled() && !settings.resolver.extra_build_dependencies.is_empty() {
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !settings.resolver.extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -963,7 +969,7 @@ async fn lock_and_sync(
|
|||
concurrency: Concurrency,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<(), ProjectError> {
|
||||
let mut lock = project::lock::LockOperation::new(
|
||||
if locked {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::settings::{NetworkSettings, ResolverInstallerSettings};
|
|||
|
||||
use uv_cache::{Cache, CacheBucket};
|
||||
use uv_cache_key::{cache_digest, hash_digest};
|
||||
use uv_configuration::{Concurrency, Constraints, PreviewMode};
|
||||
use uv_configuration::{Concurrency, Constraints, Preview};
|
||||
use uv_distribution_types::{Name, Resolution};
|
||||
use uv_fs::PythonExt;
|
||||
use uv_python::{Interpreter, PythonEnvironment, canonicalize_executable};
|
||||
|
|
@ -119,7 +119,7 @@ impl CachedEnvironment {
|
|||
concurrency: Concurrency,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, ProjectError> {
|
||||
let interpreter = Self::base_interpreter(interpreter, cache)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use owo_colors::OwoColorize;
|
|||
use uv_cache::Cache;
|
||||
use uv_configuration::{
|
||||
Concurrency, DependencyGroups, EditableMode, ExportFormat, ExtrasSpecification, InstallOptions,
|
||||
PreviewMode,
|
||||
Preview,
|
||||
};
|
||||
use uv_normalize::{DefaultExtras, DefaultGroups, PackageName};
|
||||
use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
|
||||
|
|
@ -80,7 +80,7 @@ pub(crate) async fn export(
|
|||
quiet: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
// Identify the target.
|
||||
let workspace_cache = WorkspaceCache::default();
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use uv_cache::Cache;
|
|||
use uv_cli::AuthorFrom;
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::{
|
||||
DependencyGroupsWithDefaults, PreviewMode, ProjectBuildBackend, VersionControlError,
|
||||
DependencyGroupsWithDefaults, Preview, ProjectBuildBackend, VersionControlError,
|
||||
VersionControlSystem,
|
||||
};
|
||||
use uv_fs::{CWD, Simplified};
|
||||
|
|
@ -62,7 +62,7 @@ pub(crate) async fn init(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
match init_kind {
|
||||
InitKind::Script => {
|
||||
|
|
@ -201,7 +201,7 @@ async fn init_script(
|
|||
pin_python: bool,
|
||||
package: bool,
|
||||
no_config: bool,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<()> {
|
||||
if no_workspace {
|
||||
warn_user_once!("`--no-workspace` is a no-op for Python scripts, which are standalone");
|
||||
|
|
@ -296,7 +296,7 @@ async fn init_project(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<()> {
|
||||
// Discover the current workspace, if it exists.
|
||||
let workspace_cache = WorkspaceCache::default();
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ use tracing::debug;
|
|||
use uv_cache::Cache;
|
||||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification,
|
||||
PreviewMode, Reinstall, Upgrade,
|
||||
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Preview,
|
||||
PreviewFeatures, Reinstall, Upgrade,
|
||||
};
|
||||
use uv_dispatch::BuildDispatch;
|
||||
use uv_distribution::DistributionDatabase;
|
||||
|
|
@ -93,7 +93,7 @@ pub(crate) async fn lock(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> anyhow::Result<ExitStatus> {
|
||||
// If necessary, initialize the PEP 723 script.
|
||||
let script = match script {
|
||||
|
|
@ -271,7 +271,7 @@ pub(super) struct LockOperation<'env> {
|
|||
cache: &'env Cache,
|
||||
workspace_cache: &'env WorkspaceCache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
}
|
||||
|
||||
impl<'env> LockOperation<'env> {
|
||||
|
|
@ -286,7 +286,7 @@ impl<'env> LockOperation<'env> {
|
|||
cache: &'env Cache,
|
||||
workspace_cache: &'env WorkspaceCache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Self {
|
||||
Self {
|
||||
mode,
|
||||
|
|
@ -418,7 +418,7 @@ async fn do_lock(
|
|||
cache: &Cache,
|
||||
workspace_cache: &WorkspaceCache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<LockResult, ProjectError> {
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
|
|
@ -443,9 +443,12 @@ async fn do_lock(
|
|||
sources,
|
||||
} = settings;
|
||||
|
||||
if preview.is_disabled() && !extra_build_dependencies.is_empty() {
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ use uv_cache::{Cache, CacheBucket};
|
|||
use uv_cache_key::cache_digest;
|
||||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification,
|
||||
PreviewMode, Reinstall, SourceStrategy, Upgrade,
|
||||
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Preview,
|
||||
PreviewFeatures, Reinstall, SourceStrategy, Upgrade,
|
||||
};
|
||||
use uv_dispatch::{BuildDispatch, SharedState};
|
||||
use uv_distribution::{DistributionDatabase, LoweredRequirement};
|
||||
|
|
@ -648,7 +648,7 @@ impl ScriptInterpreter {
|
|||
active: Option<bool>,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, ProjectError> {
|
||||
// For now, we assume that scripts are never evaluated in the context of a workspace.
|
||||
let workspace = None;
|
||||
|
|
@ -888,7 +888,7 @@ impl ProjectInterpreter {
|
|||
active: Option<bool>,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, ProjectError> {
|
||||
// Resolve the Python request and requirement for the workspace.
|
||||
let WorkspacePython {
|
||||
|
|
@ -1270,7 +1270,7 @@ impl ProjectEnvironment {
|
|||
cache: &Cache,
|
||||
dry_run: DryRun,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, ProjectError> {
|
||||
// Lock the project environment to avoid synchronization issues.
|
||||
let _lock = ProjectInterpreter::lock(workspace)
|
||||
|
|
@ -1280,7 +1280,7 @@ impl ProjectEnvironment {
|
|||
})
|
||||
.ok();
|
||||
|
||||
let upgradeable = preview.is_enabled()
|
||||
let upgradeable = preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE)
|
||||
&& python
|
||||
.as_ref()
|
||||
.is_none_or(|request| !request.includes_patch());
|
||||
|
|
@ -1502,7 +1502,7 @@ impl ScriptEnvironment {
|
|||
cache: &Cache,
|
||||
dry_run: DryRun,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Self, ProjectError> {
|
||||
// Lock the script environment to avoid synchronization issues.
|
||||
let _lock = ScriptInterpreter::lock(script)
|
||||
|
|
@ -1659,7 +1659,7 @@ pub(crate) async fn resolve_names(
|
|||
cache: &Cache,
|
||||
workspace_cache: &WorkspaceCache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<Vec<Requirement>, uv_requirements::Error> {
|
||||
// Partition the requirements into named and unnamed requirements.
|
||||
let (mut requirements, unnamed): (Vec<_>, Vec<_>) =
|
||||
|
|
@ -1834,7 +1834,7 @@ pub(crate) async fn resolve_environment(
|
|||
concurrency: Concurrency,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ResolverOutput, ProjectError> {
|
||||
warn_on_requirements_txt_setting(&spec.requirements, settings);
|
||||
|
||||
|
|
@ -2026,7 +2026,7 @@ pub(crate) async fn sync_environment(
|
|||
concurrency: Concurrency,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<PythonEnvironment, ProjectError> {
|
||||
let InstallerSettingsRef {
|
||||
index_locations,
|
||||
|
|
@ -2198,7 +2198,7 @@ pub(crate) async fn update_environment(
|
|||
workspace_cache: WorkspaceCache,
|
||||
dry_run: DryRun,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<EnvironmentUpdate, ProjectError> {
|
||||
warn_on_requirements_txt_setting(&spec, &settings.resolver);
|
||||
|
||||
|
|
@ -2441,7 +2441,7 @@ pub(crate) async fn init_script_python_requirement(
|
|||
client_builder: &BaseClientBuilder<'_>,
|
||||
cache: &Cache,
|
||||
reporter: &PythonDownloadReporter,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> anyhow::Result<RequiresPython> {
|
||||
let python_request = if let Some(request) = python {
|
||||
// (1) Explicit request from user
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use tracing::{debug, warn};
|
|||
use uv_cache::Cache;
|
||||
use uv_configuration::{
|
||||
Concurrency, DependencyGroups, DryRun, EditableMode, ExtrasSpecification, InstallOptions,
|
||||
PreviewMode,
|
||||
Preview,
|
||||
};
|
||||
use uv_fs::Simplified;
|
||||
use uv_normalize::{DEV_DEPENDENCIES, DefaultExtras, DefaultGroups};
|
||||
|
|
@ -60,7 +60,7 @@ pub(crate) async fn remove(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let target = if let Some(script) = script {
|
||||
// If we found a PEP 723 script and the user provided a project-only setting, warn.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use uv_cli::ExternalCommand;
|
|||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::{
|
||||
Concurrency, Constraints, DependencyGroups, DryRun, EditableMode, ExtrasSpecification,
|
||||
InstallOptions, PreviewMode,
|
||||
InstallOptions, Preview,
|
||||
};
|
||||
use uv_distribution_types::Requirement;
|
||||
use uv_fs::which::is_executable;
|
||||
|
|
@ -94,7 +94,7 @@ pub(crate) async fn run(
|
|||
printer: Printer,
|
||||
env_file: Vec<PathBuf>,
|
||||
no_env_file: bool,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
max_recursion_depth: u32,
|
||||
) -> anyhow::Result<ExitStatus> {
|
||||
// Check if max recursion depth was exceeded. This most commonly happens
|
||||
|
|
@ -1071,8 +1071,8 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
|
||||
ephemeral_env.set_overlay(format!(
|
||||
"import site; site.addsitedir(\"{}\"); site.addsitedir(\"{}\");",
|
||||
base_site_packages.escape_for_python(),
|
||||
requirements_site_packages.escape_for_python(),
|
||||
base_site_packages.escape_for_python(),
|
||||
))?;
|
||||
|
||||
// N.B. The order here matters — earlier interpreters take precedence over the
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
|||
use uv_configuration::{
|
||||
Concurrency, Constraints, DependencyGroups, DependencyGroupsWithDefaults, DryRun, EditableMode,
|
||||
ExtrasSpecification, ExtrasSpecificationWithDefaults, HashCheckingMode, InstallOptions,
|
||||
PreviewMode, TargetTriple, Upgrade,
|
||||
Preview, PreviewFeatures, TargetTriple, Upgrade,
|
||||
};
|
||||
use uv_dispatch::BuildDispatch;
|
||||
use uv_distribution_types::{
|
||||
|
|
@ -80,12 +80,14 @@ pub(crate) async fn sync(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
output_format: SyncFormat,
|
||||
) -> Result<ExitStatus> {
|
||||
if preview.is_enabled() && matches!(output_format, SyncFormat::Json) {
|
||||
if preview.is_enabled(PreviewFeatures::JSON_OUTPUT) && matches!(output_format, SyncFormat::Json)
|
||||
{
|
||||
warn_user!(
|
||||
"The `--output-format json` option is experimental and the schema may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `--output-format json` option is experimental and the schema may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::JSON_OUTPUT
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -579,7 +581,7 @@ pub(super) async fn do_sync(
|
|||
workspace_cache: WorkspaceCache,
|
||||
dry_run: DryRun,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<(), ProjectError> {
|
||||
// Extract the project settings.
|
||||
let InstallerSettingsRef {
|
||||
|
|
@ -600,9 +602,12 @@ pub(super) async fn do_sync(
|
|||
sources,
|
||||
} = settings;
|
||||
|
||||
if preview.is_disabled() && !extra_build_dependencies.is_empty() {
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use tokio::sync::Semaphore;
|
|||
use uv_cache::{Cache, Refresh};
|
||||
use uv_cache_info::Timestamp;
|
||||
use uv_client::RegistryClientBuilder;
|
||||
use uv_configuration::{Concurrency, DependencyGroups, PreviewMode, TargetTriple};
|
||||
use uv_configuration::{Concurrency, DependencyGroups, Preview, TargetTriple};
|
||||
use uv_distribution_types::IndexCapabilities;
|
||||
use uv_normalize::DefaultGroups;
|
||||
use uv_pep508::PackageName;
|
||||
|
|
@ -57,7 +57,7 @@ pub(crate) async fn tree(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
// Find the project requirements.
|
||||
let workspace_cache = WorkspaceCache::default();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use uv_cli::version::VersionInfo;
|
|||
use uv_cli::{VersionBump, VersionFormat};
|
||||
use uv_configuration::{
|
||||
Concurrency, DependencyGroups, DependencyGroupsWithDefaults, DryRun, EditableMode,
|
||||
ExtrasSpecification, InstallOptions, PreviewMode,
|
||||
ExtrasSpecification, InstallOptions, Preview,
|
||||
};
|
||||
use uv_fs::Simplified;
|
||||
use uv_normalize::DefaultExtras;
|
||||
|
|
@ -76,7 +76,7 @@ pub(crate) async fn project_version(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
// Read the metadata
|
||||
let project = find_target(project_dir, package.as_ref(), explicit_project).await?;
|
||||
|
|
@ -414,7 +414,7 @@ async fn print_frozen_version(
|
|||
short: bool,
|
||||
output_format: VersionFormat,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
// Discover the interpreter (this is the same interpreter --no-sync uses).
|
||||
let interpreter = ProjectInterpreter::discover(
|
||||
|
|
@ -509,7 +509,7 @@ async fn lock_and_sync(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
// If frozen, don't touch the lock or sync at all
|
||||
if frozen {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::fmt::Write;
|
|||
use std::path::Path;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_configuration::{DependencyGroupsWithDefaults, PreviewMode};
|
||||
use uv_configuration::{DependencyGroupsWithDefaults, Preview};
|
||||
use uv_fs::Simplified;
|
||||
use uv_python::{
|
||||
EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest,
|
||||
|
|
@ -32,7 +32,7 @@ pub(crate) async fn find(
|
|||
python_preference: PythonPreference,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let environment_preference = if system {
|
||||
EnvironmentPreference::OnlySystem
|
||||
|
|
@ -123,7 +123,7 @@ pub(crate) async fn find_script(
|
|||
no_config: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let interpreter = match ScriptInterpreter::discover(
|
||||
script,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use owo_colors::OwoColorize;
|
|||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::{Preview, PreviewFeatures};
|
||||
use uv_fs::Simplified;
|
||||
use uv_python::downloads::{
|
||||
self, ArchRequest, DownloadResult, ManagedPythonDownload, PythonDownloadRequest,
|
||||
|
|
@ -161,7 +161,7 @@ pub(crate) async fn install(
|
|||
default: bool,
|
||||
python_downloads: PythonDownloads,
|
||||
no_config: bool,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
printer: Printer,
|
||||
) -> Result<ExitStatus> {
|
||||
let start = std::time::Instant::now();
|
||||
|
|
@ -170,15 +170,17 @@ pub(crate) async fn install(
|
|||
// `--default` is used. It's not clear how this overlaps with a global Python pin, but I'd be
|
||||
// surprised if `uv python find` returned the "newest" Python version rather than the one I just
|
||||
// installed with the `--default` flag.
|
||||
if default && !preview.is_enabled() {
|
||||
if default && !preview.is_enabled(PreviewFeatures::PYTHON_INSTALL_DEFAULT) {
|
||||
warn_user!(
|
||||
"The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning"
|
||||
"The `--default` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning",
|
||||
PreviewFeatures::PYTHON_INSTALL_DEFAULT
|
||||
);
|
||||
}
|
||||
|
||||
if upgrade && preview.is_disabled() {
|
||||
if upgrade && !preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE) {
|
||||
warn_user!(
|
||||
"`uv python upgrade` is experimental and may change without warning. Pass `--preview` to disable this warning"
|
||||
"`uv python upgrade` is experimental and may change without warning. Pass `--preview-features {}` to disable this warning",
|
||||
PreviewFeatures::PYTHON_UPGRADE
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -737,12 +739,13 @@ fn create_bin_links(
|
|||
installations: &[&ManagedPythonInstallation],
|
||||
changelog: &mut Changelog,
|
||||
errors: &mut Vec<(InstallErrorKind, PythonInstallationKey, Error)>,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) {
|
||||
// TODO(zanieb): We want more feedback on the `is_default_install` behavior before stabilizing
|
||||
// it. In particular, it may be confusing because it does not apply when versions are loaded
|
||||
// from a `.python-version` file.
|
||||
let targets = if (default || (is_default_install && preview.is_enabled()))
|
||||
let targets = if (default
|
||||
|| (is_default_install && preview.is_enabled(PreviewFeatures::PYTHON_INSTALL_DEFAULT)))
|
||||
&& first_request.matches_installation(installation)
|
||||
{
|
||||
vec![
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use serde::Serialize;
|
|||
use std::collections::BTreeSet;
|
||||
use std::fmt::Write;
|
||||
use uv_cli::PythonListFormat;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_pep440::Version;
|
||||
|
||||
use anyhow::Result;
|
||||
|
|
@ -65,7 +65,7 @@ pub(crate) async fn list(
|
|||
python_downloads: PythonDownloads,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let request = request.as_deref().map(PythonRequest::parse);
|
||||
let base_download_request = if python_preference == PythonPreference::OnlySystem {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use tracing::debug;
|
|||
|
||||
use uv_cache::Cache;
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::{DependencyGroupsWithDefaults, PreviewMode};
|
||||
use uv_configuration::{DependencyGroupsWithDefaults, Preview};
|
||||
use uv_fs::Simplified;
|
||||
use uv_python::{
|
||||
EnvironmentPreference, PYTHON_VERSION_FILENAME, PythonDownloads, PythonInstallation,
|
||||
|
|
@ -39,7 +39,7 @@ pub(crate) async fn pin(
|
|||
network_settings: NetworkSettings,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let workspace_cache = WorkspaceCache::default();
|
||||
let virtual_project = if no_project {
|
||||
|
|
@ -270,7 +270,7 @@ fn warn_if_existing_pin_incompatible_with_project(
|
|||
virtual_project: &VirtualProject,
|
||||
python_preference: PythonPreference,
|
||||
cache: &Cache,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) {
|
||||
// Check if the pinned version is compatible with the project.
|
||||
if let Some(pin_version) = pep440_version_from_request(pin) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use owo_colors::OwoColorize;
|
|||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_fs::Simplified;
|
||||
use uv_python::downloads::PythonDownloadRequest;
|
||||
use uv_python::managed::{
|
||||
|
|
@ -30,7 +30,7 @@ pub(crate) async fn uninstall(
|
|||
targets: Vec<String>,
|
||||
all: bool,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let installations = ManagedPythonInstallations::from_settings(install_dir)?.init()?;
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ async fn do_uninstall(
|
|||
targets: Vec<String>,
|
||||
all: bool,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
|
|
@ -112,13 +112,11 @@ async fn do_uninstall(
|
|||
}
|
||||
if !found {
|
||||
// Clear any remnants in the registry
|
||||
if preview.is_enabled() {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
uv_python::windows_registry::remove_orphan_registry_entries(
|
||||
&installed_installations,
|
||||
);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
uv_python::windows_registry::remove_orphan_registry_entries(
|
||||
&installed_installations,
|
||||
);
|
||||
}
|
||||
|
||||
if matches!(requests.as_slice(), [PythonRequest::Default]) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::{collections::BTreeSet, ffi::OsString};
|
|||
use tracing::{debug, warn};
|
||||
use uv_cache::Cache;
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_distribution_types::Requirement;
|
||||
use uv_distribution_types::{InstalledDist, Name};
|
||||
use uv_fs::Simplified;
|
||||
|
|
@ -81,7 +81,7 @@ pub(crate) async fn refine_interpreter(
|
|||
python_preference: PythonPreference,
|
||||
python_downloads: PythonDownloads,
|
||||
cache: &Cache,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> anyhow::Result<Option<Interpreter>, ProjectError> {
|
||||
let pip::operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(no_solution_err)) =
|
||||
err
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ use anstream::println;
|
|||
use anyhow::Context;
|
||||
use owo_colors::OwoColorize;
|
||||
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_fs::Simplified;
|
||||
use uv_tool::{InstalledTools, tool_executable_dir};
|
||||
|
||||
/// Show the tool directory.
|
||||
pub(crate) fn dir(bin: bool, _preview: PreviewMode) -> anyhow::Result<()> {
|
||||
pub(crate) fn dir(bin: bool, _preview: Preview) -> anyhow::Result<()> {
|
||||
if bin {
|
||||
let executable_directory = tool_executable_dir()?;
|
||||
println!("{}", executable_directory.simplified_display().cyan());
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use tracing::{debug, trace};
|
|||
use uv_cache::{Cache, Refresh};
|
||||
use uv_cache_info::Timestamp;
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::{Concurrency, Constraints, DryRun, PreviewMode, Reinstall, Upgrade};
|
||||
use uv_configuration::{Concurrency, Constraints, DryRun, Preview, Reinstall, Upgrade};
|
||||
use uv_distribution_types::{
|
||||
NameRequirementSpecification, Requirement, RequirementSource,
|
||||
UnresolvedRequirementSpecification,
|
||||
|
|
@ -62,7 +62,7 @@ pub(crate) async fn install(
|
|||
concurrency: Concurrency,
|
||||
cache: Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.retries_from_env()?
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use uv_cache_info::Timestamp;
|
|||
use uv_cli::ExternalCommand;
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::Constraints;
|
||||
use uv_configuration::{Concurrency, PreviewMode};
|
||||
use uv_configuration::{Concurrency, Preview};
|
||||
use uv_distribution_types::InstalledDist;
|
||||
use uv_distribution_types::{
|
||||
IndexUrl, Name, NameRequirementSpecification, Requirement, RequirementSource,
|
||||
|
|
@ -101,7 +101,7 @@ pub(crate) async fn run(
|
|||
printer: Printer,
|
||||
env_file: Vec<PathBuf>,
|
||||
no_env_file: bool,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> anyhow::Result<ExitStatus> {
|
||||
/// Whether or not a path looks like a Python script based on the file extension.
|
||||
fn has_python_script_ext(path: &Path) -> bool {
|
||||
|
|
@ -686,7 +686,7 @@ async fn get_or_create_environment(
|
|||
concurrency: Concurrency,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<(ToolRequirement, PythonEnvironment), ProjectError> {
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.retries_from_env()?
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use tracing::debug;
|
|||
|
||||
use uv_cache::Cache;
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::{Concurrency, Constraints, DryRun, PreviewMode};
|
||||
use uv_configuration::{Concurrency, Constraints, DryRun, Preview};
|
||||
use uv_distribution_types::Requirement;
|
||||
use uv_fs::CWD;
|
||||
use uv_normalize::PackageName;
|
||||
|
|
@ -47,7 +47,7 @@ pub(crate) async fn upgrade(
|
|||
concurrency: Concurrency,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let installed_tools = InstalledTools::from_settings()?.init()?;
|
||||
let _lock = installed_tools.lock().await?;
|
||||
|
|
@ -221,7 +221,7 @@ async fn upgrade_tool(
|
|||
filesystem: &ResolverInstallerOptions,
|
||||
installer_metadata: bool,
|
||||
concurrency: Concurrency,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<UpgradeOutcome> {
|
||||
// Ensure the tool is installed.
|
||||
let existing_tool_receipt = match installed_tools.get_tool_receipt(name) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::fmt::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::vec;
|
||||
|
||||
use anyhow::Result;
|
||||
|
|
@ -12,7 +11,8 @@ use uv_cache::Cache;
|
|||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
BuildOptions, Concurrency, ConfigSettings, Constraints, DependencyGroups, IndexStrategy,
|
||||
KeyringProviderType, NoBinary, NoBuild, PackageConfigSettings, PreviewMode, SourceStrategy,
|
||||
KeyringProviderType, NoBinary, NoBuild, PackageConfigSettings, Preview, PreviewFeatures,
|
||||
SourceStrategy,
|
||||
};
|
||||
use uv_dispatch::{BuildDispatch, SharedState};
|
||||
use uv_distribution_types::Requirement;
|
||||
|
|
@ -83,7 +83,7 @@ pub(crate) async fn venv(
|
|||
cache: &Cache,
|
||||
printer: Printer,
|
||||
relocatable: bool,
|
||||
preview: PreviewMode,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
let workspace_cache = WorkspaceCache::default();
|
||||
let project = if no_project {
|
||||
|
|
@ -200,7 +200,7 @@ pub(crate) async fn venv(
|
|||
path.user_display().cyan()
|
||||
)?;
|
||||
|
||||
let upgradeable = preview.is_enabled()
|
||||
let upgradeable = preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE)
|
||||
&& python_request
|
||||
.as_ref()
|
||||
.is_none_or(|request| !request.includes_patch());
|
||||
|
|
@ -225,15 +225,7 @@ pub(crate) async fn venv(
|
|||
let interpreter = venv.interpreter();
|
||||
|
||||
// Add all authenticated sources to the cache.
|
||||
for index in index_locations.allowed_indexes() {
|
||||
if let Some(credentials) = index.credentials() {
|
||||
let credentials = Arc::new(credentials);
|
||||
uv_auth::store_credentials(index.raw_url(), credentials.clone());
|
||||
if let Some(root_url) = index.root_url() {
|
||||
uv_auth::store_credentials(&root_url, credentials.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
index_locations.cache_index_credentials();
|
||||
|
||||
// Instantiate a client.
|
||||
let client = RegistryClientBuilder::try_from(client_builder)?
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use uv_cli::{
|
|||
ProjectCommand, PythonCommand, PythonNamespace, SelfCommand, SelfNamespace, ToolCommand,
|
||||
ToolNamespace, TopLevelArgs, compat::CompatArgs,
|
||||
};
|
||||
use uv_configuration::min_stack_size;
|
||||
use uv_configuration::{PreviewFeatures, min_stack_size};
|
||||
use uv_fs::{CWD, Simplified};
|
||||
#[cfg(feature = "self-update")]
|
||||
use uv_pep440::release_specifiers_to_ranges;
|
||||
|
|
@ -443,9 +443,14 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipCompileSettings::resolve(args, filesystem);
|
||||
show_settings!(args);
|
||||
if !args.settings.extra_build_dependencies.is_empty() && globals.preview.is_disabled() {
|
||||
if !args.settings.extra_build_dependencies.is_empty()
|
||||
&& !globals
|
||||
.preview
|
||||
.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` setting is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `extra-build-dependencies` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -549,9 +554,14 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipSyncSettings::resolve(args, filesystem);
|
||||
show_settings!(args);
|
||||
if !args.settings.extra_build_dependencies.is_empty() && globals.preview.is_disabled() {
|
||||
if !args.settings.extra_build_dependencies.is_empty()
|
||||
&& !globals
|
||||
.preview
|
||||
.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` setting is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `extra-build-dependencies` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -633,9 +643,14 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let mut args = PipInstallSettings::resolve(args, filesystem);
|
||||
show_settings!(args);
|
||||
if !args.settings.extra_build_dependencies.is_empty() && globals.preview.is_disabled() {
|
||||
if !args.settings.extra_build_dependencies.is_empty()
|
||||
&& !globals
|
||||
.preview
|
||||
.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` setting is experimental and may change without warning. Pass `--preview` to disable this warning."
|
||||
"The `extra-build-dependencies` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ use uv_client::Connectivity;
|
|||
use uv_configuration::{
|
||||
BuildOptions, Concurrency, ConfigSettings, DependencyGroups, DryRun, EditableMode,
|
||||
ExportFormat, ExtrasSpecification, HashCheckingMode, IndexStrategy, InstallOptions,
|
||||
KeyringProviderType, NoBinary, NoBuild, PackageConfigSettings, PreviewMode,
|
||||
ProjectBuildBackend, Reinstall, RequiredVersion, SourceStrategy, TargetTriple, TrustedHost,
|
||||
TrustedPublishing, Upgrade, VersionControlSystem,
|
||||
KeyringProviderType, NoBinary, NoBuild, PackageConfigSettings, Preview, ProjectBuildBackend,
|
||||
Reinstall, RequiredVersion, SourceStrategy, TargetTriple, TrustedHost, TrustedPublishing,
|
||||
Upgrade, VersionControlSystem,
|
||||
};
|
||||
use uv_distribution_types::{DependencyMetadata, Index, IndexLocations, IndexUrl, Requirement};
|
||||
use uv_install_wheel::LinkMode;
|
||||
|
|
@ -63,7 +63,7 @@ pub(crate) struct GlobalSettings {
|
|||
pub(crate) network_settings: NetworkSettings,
|
||||
pub(crate) concurrency: Concurrency,
|
||||
pub(crate) show_settings: bool,
|
||||
pub(crate) preview: PreviewMode,
|
||||
pub(crate) preview: Preview,
|
||||
pub(crate) python_preference: PythonPreference,
|
||||
pub(crate) python_downloads: PythonDownloads,
|
||||
pub(crate) no_progress: bool,
|
||||
|
|
@ -117,10 +117,12 @@ impl GlobalSettings {
|
|||
.unwrap_or_else(Concurrency::threads),
|
||||
},
|
||||
show_settings: args.show_settings,
|
||||
preview: PreviewMode::from(
|
||||
preview: Preview::from_args(
|
||||
flag(args.preview, args.no_preview, "preview")
|
||||
.combine(workspace.and_then(|workspace| workspace.globals.preview))
|
||||
.unwrap_or(false),
|
||||
args.no_preview,
|
||||
&args.preview_features,
|
||||
),
|
||||
python_preference,
|
||||
python_downloads: flag(
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use regex::Regex;
|
|||
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use uv_cache::Cache;
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_configuration::Preview;
|
||||
use uv_fs::Simplified;
|
||||
use uv_python::managed::ManagedPythonInstallations;
|
||||
use uv_python::{
|
||||
|
|
@ -706,6 +706,11 @@ impl TestContext {
|
|||
),
|
||||
r#"requires = ["uv_build>=[CURRENT_VERSION],<[NEXT_BREAKING]"]"#.to_string(),
|
||||
));
|
||||
// Filter script environment hashes
|
||||
filters.push((
|
||||
r"environments-v(\d+)[\\/](\w+)-[a-z0-9]+".to_string(),
|
||||
"environments-v$1/$2-[HASH]".to_string(),
|
||||
));
|
||||
|
||||
Self {
|
||||
root: ChildPath::new(root.path()),
|
||||
|
|
@ -1500,7 +1505,7 @@ pub fn python_installations_for_versions(
|
|||
EnvironmentPreference::OnlySystem,
|
||||
PythonPreference::Managed,
|
||||
&cache,
|
||||
PreviewMode::Disabled,
|
||||
Preview::default(),
|
||||
) {
|
||||
python.into_interpreter().sys_executable().to_owned()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -13021,7 +13021,7 @@ fn add_bounds() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The bounds option is in preview and may change in any future release.
|
||||
warning: The `bounds` option is in preview and may change in any future release. Pass `--preview-features add-bounds` to disable this warning.
|
||||
Resolved 2 packages in [TIME]
|
||||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
|
|
@ -13061,7 +13061,7 @@ fn add_bounds() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The bounds option is in preview and may change in any future release.
|
||||
warning: The `bounds` option is in preview and may change in any future release. Pass `--preview-features add-bounds` to disable this warning.
|
||||
Resolved 4 packages in [TIME]
|
||||
Prepared 2 packages in [TIME]
|
||||
Installed 2 packages in [TIME]
|
||||
|
|
|
|||
|
|
@ -29411,3 +29411,490 @@ fn test_tilde_equals_python_version() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that lockfile validation includes explicit indexes from path dependencies.
|
||||
/// <https://github.com/astral-sh/uv/issues/11419>
|
||||
#[test]
|
||||
fn lock_path_dependency_explicit_index() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
// Create the path dependency with explicit index
|
||||
let pkg_a = context.temp_dir.child("pkg_a");
|
||||
fs_err::create_dir_all(&pkg_a)?;
|
||||
|
||||
let pyproject_toml = pkg_a.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-a"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["iniconfig"]
|
||||
|
||||
[tool.uv.sources]
|
||||
iniconfig = { index = "inner-index" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "inner-index"
|
||||
url = "https://pypi-proxy.fly.dev/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create a project that depends on pkg_a
|
||||
let pkg_b = context.temp_dir.child("pkg_b");
|
||||
fs_err::create_dir_all(&pkg_b)?;
|
||||
|
||||
let pyproject_toml = pkg_b.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-b"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["pkg-a"]
|
||||
|
||||
[tool.uv.sources]
|
||||
pkg-a = { path = "../pkg_a/", editable = true }
|
||||
black = { index = "outer-index" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "outer-index"
|
||||
url = "https://outer-index.com/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().current_dir(&pkg_b), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 3 packages in [TIME]
|
||||
");
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--check").current_dir(&pkg_b), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 3 packages in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that lockfile validation includes explicit indexes from path dependencies
|
||||
/// defined in a non-root workspace member.
|
||||
#[test]
|
||||
fn lock_path_dependency_explicit_index_workspace_member() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
// Create the path dependency with explicit index
|
||||
let pkg_a = context.temp_dir.child("pkg_a");
|
||||
fs_err::create_dir_all(&pkg_a)?;
|
||||
|
||||
let pyproject_toml = pkg_a.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-a"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["iniconfig"]
|
||||
|
||||
[tool.uv.sources]
|
||||
iniconfig = { index = "inner-index" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "inner-index"
|
||||
url = "https://pypi-proxy.fly.dev/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create a project that depends on pkg_a
|
||||
let member = context.temp_dir.child("member");
|
||||
fs_err::create_dir_all(&member)?;
|
||||
|
||||
let pyproject_toml = member.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "member"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["pkg-a"]
|
||||
|
||||
[tool.uv.sources]
|
||||
pkg-a = { path = "../pkg_a/", editable = true }
|
||||
black = { index = "middle-index" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "middle-index"
|
||||
url = "https://middle-index.com/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create a root with workspace member
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "root-project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["member"]
|
||||
|
||||
[tool.uv.workspace]
|
||||
members = ["member"]
|
||||
|
||||
[tool.uv.sources]
|
||||
member = { workspace = true }
|
||||
anyio = { index = "outer-index" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "outer-index"
|
||||
url = "https://outer-index.com/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 4 packages in [TIME]
|
||||
");
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--check"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 4 packages in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that lockfile validation works correctly when path dependency has
|
||||
/// both explicit and non-explicit indexes.
|
||||
#[test]
|
||||
fn lock_path_dependency_mixed_indexes() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
// Create the path dependency with both explicit and non-explicit indexes.
|
||||
let pkg_a = context.temp_dir.child("pkg_a");
|
||||
fs_err::create_dir_all(&pkg_a)?;
|
||||
|
||||
let pyproject_toml = pkg_a.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-a"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["iniconfig", "anyio"]
|
||||
|
||||
[tool.uv.sources]
|
||||
iniconfig = { index = "explicit-index" }
|
||||
anyio = { index = "non-explicit-index" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "non-explicit-index"
|
||||
url = "https://pypi-proxy.fly.dev/simple"
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "explicit-index"
|
||||
url = "https://pypi.org/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create a project that depends on pkg_a.
|
||||
let pkg_b = context.temp_dir.child("pkg_b");
|
||||
fs_err::create_dir_all(&pkg_b)?;
|
||||
|
||||
let pyproject_toml = pkg_b.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-b"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["pkg-a"]
|
||||
|
||||
[tool.uv.sources]
|
||||
pkg-a = { path = "../pkg_a/", editable = true }
|
||||
black = { index = "outer-index" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "outer-index"
|
||||
url = "https://outer-index.com/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().current_dir(&pkg_b), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 6 packages in [TIME]
|
||||
");
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--check").current_dir(&pkg_b), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 6 packages in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that path dependencies without an index don't affect validation.
|
||||
#[test]
|
||||
fn lock_path_dependency_no_index() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
// Create the path dependency without explicit indexes.
|
||||
let pkg_a = context.temp_dir.child("pkg_a");
|
||||
fs_err::create_dir_all(&pkg_a)?;
|
||||
|
||||
let pyproject_toml = pkg_a.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-a"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["requests"]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create a project that depends on pkg_a.
|
||||
let pkg_b = context.temp_dir.child("pkg_b");
|
||||
fs_err::create_dir_all(&pkg_b)?;
|
||||
|
||||
let pyproject_toml = pkg_b.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-b"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["pkg-a"]
|
||||
|
||||
[tool.uv.sources]
|
||||
pkg-a = { path = "../pkg_a/", editable = true }
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().current_dir(&pkg_b), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 7 packages in [TIME]
|
||||
");
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--check").current_dir(&pkg_b), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 7 packages in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that a nested path dependency with an explicit index validates correctly.
|
||||
#[test]
|
||||
fn lock_nested_path_dependency_explicit_index() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
// Create the inner dependency with explicit index.
|
||||
let pkg_a = context.temp_dir.child("pkg_a");
|
||||
fs_err::create_dir_all(&pkg_a)?;
|
||||
|
||||
let pyproject_toml = pkg_a.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-a"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["iniconfig"]
|
||||
|
||||
[tool.uv.sources]
|
||||
iniconfig = { index = "inner-index" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "inner-index"
|
||||
url = "https://pypi-proxy.fly.dev/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create intermediate dependency that depends on pkg_a.
|
||||
let pkg_b = context.temp_dir.child("pkg_b");
|
||||
fs_err::create_dir_all(&pkg_b)?;
|
||||
|
||||
let pyproject_toml = pkg_b.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-b"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["pkg-a"]
|
||||
|
||||
[tool.uv.sources]
|
||||
pkg-a = { path = "../pkg_a/", editable = true }
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create a project that depends on intermediate dependency.
|
||||
let pkg_c = context.temp_dir.child("pkg_c");
|
||||
fs_err::create_dir_all(&pkg_c)?;
|
||||
|
||||
let pyproject_toml = pkg_c.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-c"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["pkg-b"]
|
||||
|
||||
[tool.uv.sources]
|
||||
pkg-b = { path = "../pkg_b/", editable = true }
|
||||
black = { index = "outer-index" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "outer-index"
|
||||
url = "https://outer-index.com/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().current_dir(&pkg_c), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 4 packages in [TIME]
|
||||
");
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--check").current_dir(&pkg_c), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 4 packages in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that validating circular path dependency indexes doesn't cause an infinite loop.
|
||||
#[test]
|
||||
fn lock_circular_path_dependency_explicit_index() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
// Create pkg_a (with explicit index) that depends on pkg_b.
|
||||
let pkg_a = context.temp_dir.child("pkg_a");
|
||||
fs_err::create_dir_all(&pkg_a)?;
|
||||
|
||||
let pyproject_toml = pkg_a.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-a"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = ["pkg-b", "iniconfig"]
|
||||
|
||||
[tool.uv.sources]
|
||||
pkg-b = { path = "../pkg_b/" }
|
||||
iniconfig = { index = "index-a" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "index-a"
|
||||
url = "https://pypi-proxy.fly.dev/simple"
|
||||
explicit = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create pkg_b that depends on pkg_a. This is a circular dependency.
|
||||
let pkg_b = context.temp_dir.child("pkg_b");
|
||||
fs_err::create_dir_all(&pkg_b)?;
|
||||
|
||||
let pyproject_toml = pkg_b.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "pkg-b"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = ["pkg-a", "anyio"]
|
||||
|
||||
[tool.uv.sources]
|
||||
pkg-a = { path = "../pkg_a/" }
|
||||
anyio = { index = "index-b" }
|
||||
|
||||
[[tool.uv.index]]
|
||||
name = "index-b"
|
||||
url = "https://pypi.org/simple"
|
||||
explicit = true
|
||||
default = true
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// This should not hang or crash due to the circular dependency.
|
||||
uv_snapshot!(context.filters(), context.lock().current_dir(&pkg_a), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 8 packages in [TIME]
|
||||
");
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--check").current_dir(&pkg_a), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Resolved 8 packages in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1057,6 +1057,7 @@ fn extra_unconditional() -> Result<()> {
|
|||
----- stderr -----
|
||||
Resolved 6 packages in [TIME]
|
||||
"###);
|
||||
|
||||
// This should error since we're enabling two conflicting extras.
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###"
|
||||
success: false
|
||||
|
|
@ -1652,6 +1653,249 @@ fn extra_nested_across_workspace() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// The project declares conflicting extras, but one of the extras directly depends on the other.
|
||||
#[test]
|
||||
fn extra_depends_on_conflicting_extra() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "example"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[project.optional-dependencies]
|
||||
foo = ["sortedcontainers==2.3.0", "example[bar]"]
|
||||
bar = ["sortedcontainers==2.4.0"]
|
||||
|
||||
[tool.uv]
|
||||
conflicts = [
|
||||
[
|
||||
{ extra = "foo" },
|
||||
{ extra = "bar" },
|
||||
],
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["example"]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// This should fail to resolve, because the extras are always required together and
|
||||
// `example[foo]` is unusable.
|
||||
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× No solution found when resolving dependencies:
|
||||
╰─▶ Because example[foo] depends on sortedcontainers==2.3.0 and sortedcontainers==2.4.0, we can conclude that example[foo]'s requirements are unsatisfiable.
|
||||
And because your project requires example[foo], we can conclude that your project's requirements are unsatisfiable.
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Like [`extra_depends_on_conflicting_extra`], but the conflict between the extras is mediated by
|
||||
/// another package.
|
||||
#[test]
|
||||
fn extra_depends_on_conflicting_extra_transitive() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "example"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[project.optional-dependencies]
|
||||
foo = ["sortedcontainers==2.3.0", "indirection"]
|
||||
bar = ["sortedcontainers==2.4.0"]
|
||||
|
||||
[tool.uv]
|
||||
conflicts = [
|
||||
[
|
||||
{ extra = "foo" },
|
||||
{ extra = "bar" },
|
||||
],
|
||||
]
|
||||
|
||||
[tool.uv.sources]
|
||||
indirection = { workspace = true }
|
||||
|
||||
[tool.uv.workspace]
|
||||
members = ["indirection"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["example"]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create the indirection subproject
|
||||
let subproject_dir = context.temp_dir.child("indirection");
|
||||
subproject_dir.create_dir_all()?;
|
||||
|
||||
let sub_pyproject_toml = subproject_dir.child("pyproject.toml");
|
||||
sub_pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "indirection"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["example[bar]"]
|
||||
|
||||
[tool.uv.sources]
|
||||
example = { workspace = true }
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// This succeeds, but probably shouldn't. There's an unconditional conflict in `example[foo]
|
||||
// -> indirection[bar] -> example[bar]`, which means `example[foo]` can never be used.
|
||||
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 4 packages in [TIME]
|
||||
");
|
||||
|
||||
let lock = context.read("uv.lock");
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
lock, @r#"
|
||||
version = 1
|
||||
revision = 2
|
||||
requires-python = ">=3.12"
|
||||
conflicts = [[
|
||||
{ package = "example", extra = "bar" },
|
||||
{ package = "example", extra = "foo" },
|
||||
]]
|
||||
|
||||
[options]
|
||||
exclude-newer = "2024-03-25T00:00:00Z"
|
||||
|
||||
[manifest]
|
||||
members = [
|
||||
"example",
|
||||
"indirection",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "example"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
|
||||
[package.optional-dependencies]
|
||||
bar = [
|
||||
{ name = "sortedcontainers", version = "2.4.0", source = { registry = "https://pypi.org/simple" } },
|
||||
]
|
||||
foo = [
|
||||
{ name = "indirection" },
|
||||
{ name = "sortedcontainers", version = "2.3.0", source = { registry = "https://pypi.org/simple" } },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "indirection", marker = "extra == 'foo'", editable = "indirection" },
|
||||
{ name = "sortedcontainers", marker = "extra == 'bar'", specifier = "==2.4.0" },
|
||||
{ name = "sortedcontainers", marker = "extra == 'foo'", specifier = "==2.3.0" },
|
||||
]
|
||||
provides-extras = ["foo", "bar"]
|
||||
|
||||
[[package]]
|
||||
name = "indirection"
|
||||
version = "0.1.0"
|
||||
source = { editable = "indirection" }
|
||||
dependencies = [
|
||||
{ name = "example" },
|
||||
{ name = "example", extra = ["bar"], marker = "extra == 'extra-7-example-bar'" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "example", extras = ["bar"], editable = "." }]
|
||||
|
||||
[[package]]
|
||||
name = "sortedcontainers"
|
||||
version = "2.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/14/10/6a9481890bae97da9edd6e737c9c3dec6aea3fc2fa53b0934037b35c89ea/sortedcontainers-2.3.0.tar.gz", hash = "sha256:59cc937650cf60d677c16775597c89a960658a09cf7c1a668f86e1e4464b10a1", size = 30509, upload-time = "2020-11-09T00:03:52.258Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/4d/a7046ae1a1a4cc4e9bbed194c387086f06b25038be596543d026946330c9/sortedcontainers-2.3.0-py2.py3-none-any.whl", hash = "sha256:37257a32add0a3ee490bb170b599e93095eed89a55da91fa9f48753ea12fd73f", size = 29479, upload-time = "2020-11-09T00:03:50.723Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sortedcontainers"
|
||||
version = "2.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" },
|
||||
]
|
||||
"#
|
||||
);
|
||||
});
|
||||
|
||||
// Install from the lockfile
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ example==0.1.0 (from file://[TEMP_DIR]/)
|
||||
");
|
||||
|
||||
// Install with `foo`
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen").arg("--extra").arg("foo"), @r"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Found conflicting extras `example[bar]` and `example[foo]` enabled simultaneously
|
||||
");
|
||||
|
||||
// Install the child package
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen").arg("--package").arg("indirection"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Prepared 2 packages in [TIME]
|
||||
Installed 2 packages in [TIME]
|
||||
+ indirection==0.1.0 (from file://[TEMP_DIR]/indirection)
|
||||
+ sortedcontainers==2.4.0
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This tests a "basic" case for specifying conflicting groups.
|
||||
#[test]
|
||||
fn group_basic() -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -2479,8 +2479,7 @@ fn install_git_private_https_pat_not_authorized() {
|
|||
├─▶ failed to clone into: [CACHE_DIR]/git-v0/db/8401f5508e3e612d
|
||||
╰─▶ process didn't exit successfully: `git fetch --force --update-head-ok 'https://git:***@github.com/astral-test/uv-private-pypackage' '+HEAD:refs/remotes/origin/HEAD'` (exit status: 128)
|
||||
--- stderr
|
||||
remote: Support for password authentication was removed on August 13, 2021.
|
||||
remote: Please see https://docs.github.com/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
|
||||
remote: Invalid username or token. Password authentication is not supported for Git operations.
|
||||
fatal: Authentication failed for 'https://github.com/astral-test/uv-private-pypackage/'
|
||||
");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -837,16 +837,7 @@ fn python_find_script() {
|
|||
.with_filtered_python_names()
|
||||
.with_filtered_exe_suffix();
|
||||
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/[\w-]+",
|
||||
"environments-v2/[HASHEDNAME]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.init().arg("--script").arg("foo.py"), @r###"
|
||||
uv_snapshot!(context.filters(), context.init().arg("--script").arg("foo.py"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -855,22 +846,22 @@ fn python_find_script() {
|
|||
Initialized script at `foo.py`
|
||||
"###);
|
||||
|
||||
uv_snapshot!(filters, context.sync().arg("--script").arg("foo.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("foo.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Creating script environment at: [CACHE_DIR]/environments-v2/[HASHEDNAME]
|
||||
Creating script environment at: [CACHE_DIR]/environments-v2/foo-[HASH]
|
||||
Resolved in [TIME]
|
||||
Audited in [TIME]
|
||||
");
|
||||
|
||||
uv_snapshot!(filters, context.python_find().arg("--script").arg("foo.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("--script").arg("foo.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
[CACHE_DIR]/environments-v2/[HASHEDNAME]/[BIN]/[PYTHON]
|
||||
[CACHE_DIR]/environments-v2/foo-[HASH]/[BIN]/[PYTHON]
|
||||
|
||||
----- stderr -----
|
||||
");
|
||||
|
|
@ -936,15 +927,6 @@ fn python_find_script_no_such_version() {
|
|||
.with_filtered_python_names()
|
||||
.with_filtered_exe_suffix()
|
||||
.with_filtered_python_sources();
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/[\w-]+",
|
||||
"environments-v2/[HASHEDNAME]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let script = context.temp_dir.child("foo.py");
|
||||
script
|
||||
.write_str(indoc! {r#"
|
||||
|
|
@ -955,13 +937,13 @@ fn python_find_script_no_such_version() {
|
|||
"#})
|
||||
.unwrap();
|
||||
|
||||
uv_snapshot!(filters, context.sync().arg("--script").arg("foo.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("foo.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Creating script environment at: [CACHE_DIR]/environments-v2/[HASHEDNAME]
|
||||
Creating script environment at: [CACHE_DIR]/environments-v2/foo-[HASH]
|
||||
Resolved in [TIME]
|
||||
Audited in [TIME]
|
||||
");
|
||||
|
|
@ -975,7 +957,7 @@ fn python_find_script_no_such_version() {
|
|||
"#})
|
||||
.unwrap();
|
||||
|
||||
uv_snapshot!(filters, context.python_find().arg("--script").arg("foo.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.python_find().arg("--script").arg("foo.py"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
|
|
|||
|
|
@ -630,14 +630,14 @@ fn python_install_preview() {
|
|||
"###);
|
||||
|
||||
// Should be a no-op when already installed
|
||||
uv_snapshot!(context.filters(), context.python_install().arg("--preview"), @r###"
|
||||
uv_snapshot!(context.filters(), context.python_install().arg("--preview"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Python is already installed. Use `uv python install <request>` to install another version.
|
||||
"###);
|
||||
");
|
||||
|
||||
// You can opt-in to a reinstall
|
||||
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--reinstall"), @r"
|
||||
|
|
@ -1260,7 +1260,7 @@ fn python_install_default() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning
|
||||
warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
|
||||
Installed Python 3.13.5 in [TIME]
|
||||
+ cpython-3.13.5-[PLATFORM] (python, python3)
|
||||
");
|
||||
|
|
@ -1294,7 +1294,7 @@ fn python_install_default() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning
|
||||
warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
|
||||
Installed Python 3.13.5 in [TIME]
|
||||
+ cpython-3.13.5-[PLATFORM] (python, python3, python3.13)
|
||||
");
|
||||
|
|
@ -1379,7 +1379,7 @@ fn python_install_default() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning
|
||||
warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
|
||||
error: The `--default` flag cannot be used with multiple targets
|
||||
");
|
||||
|
||||
|
|
@ -1390,7 +1390,7 @@ fn python_install_default() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning
|
||||
warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
|
||||
Installed Python 3.12.11 in [TIME]
|
||||
+ cpython-3.12.11-[PLATFORM] (python, python3, python3.12)
|
||||
");
|
||||
|
|
|
|||
|
|
@ -1167,14 +1167,17 @@ fn run_with() -> Result<()> {
|
|||
let test_script = context.temp_dir.child("main.py");
|
||||
test_script.write_str(indoc! { r"
|
||||
import sniffio
|
||||
|
||||
print(sniffio.__version__)
|
||||
"
|
||||
})?;
|
||||
|
||||
// Requesting an unsatisfied requirement should install it.
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("iniconfig").arg("main.py"), @r###"
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("iniconfig").arg("main.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
1.3.0
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
|
|
@ -1186,24 +1189,26 @@ fn run_with() -> Result<()> {
|
|||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ iniconfig==2.0.0
|
||||
"###);
|
||||
");
|
||||
|
||||
// Requesting a satisfied requirement should use the base environment.
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("sniffio").arg("main.py"), @r###"
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("sniffio").arg("main.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
1.3.0
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
Audited 2 packages in [TIME]
|
||||
"###);
|
||||
");
|
||||
|
||||
// Unless the user requests a different version.
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("sniffio<1.3.0").arg("main.py"), @r###"
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("sniffio<1.3.0").arg("main.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
1.2.0
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
|
|
@ -1212,15 +1217,16 @@ fn run_with() -> Result<()> {
|
|||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ sniffio==1.2.0
|
||||
"###);
|
||||
");
|
||||
|
||||
// If we request a dependency that isn't in the base environment, we should still respect any
|
||||
// other dependencies. In this case, `sniffio==1.3.0` is not the latest-compatible version, but
|
||||
// we should use it anyway.
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("anyio").arg("main.py"), @r###"
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("anyio").arg("main.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
1.3.0
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
|
|
@ -1231,13 +1237,14 @@ fn run_with() -> Result<()> {
|
|||
+ anyio==4.3.0
|
||||
+ idna==3.6
|
||||
+ sniffio==1.3.0
|
||||
"###);
|
||||
");
|
||||
|
||||
// Even if we run with` --no-sync`.
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("anyio==4.2.0").arg("--no-sync").arg("main.py"), @r###"
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("anyio==4.2.0").arg("--no-sync").arg("main.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
1.3.0
|
||||
|
||||
----- stderr -----
|
||||
Resolved 3 packages in [TIME]
|
||||
|
|
@ -1246,7 +1253,7 @@ fn run_with() -> Result<()> {
|
|||
+ anyio==4.2.0
|
||||
+ idna==3.6
|
||||
+ sniffio==1.3.0
|
||||
"###);
|
||||
");
|
||||
|
||||
// If the dependencies can't be resolved, we should reference `--with`.
|
||||
uv_snapshot!(context.filters(), context.run().arg("--with").arg("add").arg("main.py"), @r###"
|
||||
|
|
@ -4024,17 +4031,8 @@ fn run_active_script_environment() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v1/main-\w+",
|
||||
"environments-v1/main-[HASH]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Running `uv run --script` with `VIRTUAL_ENV` should _not_ warn.
|
||||
uv_snapshot!(&filters, context.run()
|
||||
uv_snapshot!(context.filters(), context.run()
|
||||
.arg("--script")
|
||||
.arg("main.py")
|
||||
.env(EnvVars::VIRTUAL_ENV, "foo"), @r###"
|
||||
|
|
@ -4051,7 +4049,7 @@ fn run_active_script_environment() -> Result<()> {
|
|||
"###);
|
||||
|
||||
// Using `--no-active` should also _not_ warn.
|
||||
uv_snapshot!(&filters, context.run()
|
||||
uv_snapshot!(context.filters(), context.run()
|
||||
.arg("--no-active")
|
||||
.arg("--script")
|
||||
.arg("main.py")
|
||||
|
|
@ -4070,7 +4068,7 @@ fn run_active_script_environment() -> Result<()> {
|
|||
.assert(predicate::path::missing());
|
||||
|
||||
// Using `--active` should create the environment
|
||||
uv_snapshot!(&filters, context.run()
|
||||
uv_snapshot!(context.filters(), context.run()
|
||||
.arg("--active")
|
||||
.arg("--script")
|
||||
.arg("main.py")
|
||||
|
|
@ -4092,7 +4090,7 @@ fn run_active_script_environment() -> Result<()> {
|
|||
.assert(predicate::path::is_dir());
|
||||
|
||||
// Requesting a different Python version should invalidate the environment
|
||||
uv_snapshot!(&filters, context.run()
|
||||
uv_snapshot!(context.filters(), context.run()
|
||||
.arg("--active")
|
||||
.arg("-p").arg("3.12")
|
||||
.arg("--script")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1655,7 +1655,7 @@ fn sync_extra_build_dependencies() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning.
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features extra-build-dependencies` to disable this warning.
|
||||
Resolved [N] packages in [TIME]
|
||||
Prepared [N] packages in [TIME]
|
||||
Installed [N] packages in [TIME]
|
||||
|
|
@ -1685,7 +1685,7 @@ fn sync_extra_build_dependencies() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning.
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features extra-build-dependencies` to disable this warning.
|
||||
Resolved [N] packages in [TIME]
|
||||
× Failed to build `child @ file://[TEMP_DIR]/child`
|
||||
├─▶ The build backend returned an error
|
||||
|
|
@ -1754,7 +1754,7 @@ fn sync_extra_build_dependencies() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning.
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features extra-build-dependencies` to disable this warning.
|
||||
Resolved [N] packages in [TIME]
|
||||
× Failed to build `bad-child @ file://[TEMP_DIR]/bad_child`
|
||||
├─▶ The build backend returned an error
|
||||
|
|
@ -1790,7 +1790,7 @@ fn sync_extra_build_dependencies() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning.
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features extra-build-dependencies` to disable this warning.
|
||||
Resolved [N] packages in [TIME]
|
||||
Prepared [N] packages in [TIME]
|
||||
Installed [N] packages in [TIME]
|
||||
|
|
@ -1866,7 +1866,7 @@ fn sync_extra_build_dependencies_sources() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning.
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features extra-build-dependencies` to disable this warning.
|
||||
Resolved [N] packages in [TIME]
|
||||
Prepared [N] packages in [TIME]
|
||||
Installed [N] packages in [TIME]
|
||||
|
|
@ -1946,7 +1946,7 @@ fn sync_extra_build_dependencies_sources_from_child() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview` to disable this warning.
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features extra-build-dependencies` to disable this warning.
|
||||
Resolved [N] packages in [TIME]
|
||||
× Failed to build `child @ file://[TEMP_DIR]/child`
|
||||
├─▶ The build backend returned an error
|
||||
|
|
@ -5487,17 +5487,8 @@ fn sync_active_script_environment() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/script-[a-z0-9]+",
|
||||
"environments-v2/script-[HASH]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Running `uv sync --script` with `VIRTUAL_ENV` should warn
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").env(EnvVars::VIRTUAL_ENV, "foo"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py").env(EnvVars::VIRTUAL_ENV, "foo"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -5519,7 +5510,7 @@ fn sync_active_script_environment() -> Result<()> {
|
|||
.assert(predicate::path::missing());
|
||||
|
||||
// Using `--active` should create the environment
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").env(EnvVars::VIRTUAL_ENV, "foo").arg("--active"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py").env(EnvVars::VIRTUAL_ENV, "foo").arg("--active"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -5539,7 +5530,7 @@ fn sync_active_script_environment() -> Result<()> {
|
|||
.assert(predicate::path::is_dir());
|
||||
|
||||
// A subsequent sync will re-use the environment
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").env(EnvVars::VIRTUAL_ENV, "foo").arg("--active"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py").env(EnvVars::VIRTUAL_ENV, "foo").arg("--active"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -5551,7 +5542,7 @@ fn sync_active_script_environment() -> Result<()> {
|
|||
");
|
||||
|
||||
// Requesting another Python version will invalidate the environment
|
||||
uv_snapshot!(&filters, context.sync()
|
||||
uv_snapshot!(context.filters(), context.sync()
|
||||
.arg("--script")
|
||||
.arg("script.py")
|
||||
.env(EnvVars::VIRTUAL_ENV, "foo")
|
||||
|
|
@ -5593,17 +5584,8 @@ fn sync_active_script_environment_json() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/script-[a-z0-9]+",
|
||||
"environments-v2/script-[HASH]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Running `uv sync --script` with `VIRTUAL_ENV` should warn
|
||||
uv_snapshot!(&filters, context.sync()
|
||||
uv_snapshot!(context.filters(), context.sync()
|
||||
.arg("--script").arg("script.py")
|
||||
.arg("--output-format").arg("json")
|
||||
.env(EnvVars::VIRTUAL_ENV, "foo"), @r#"
|
||||
|
|
@ -5649,7 +5631,7 @@ fn sync_active_script_environment_json() -> Result<()> {
|
|||
.assert(predicate::path::missing());
|
||||
|
||||
// Using `--active` should create the environment
|
||||
uv_snapshot!(&filters, context.sync()
|
||||
uv_snapshot!(context.filters(), context.sync()
|
||||
.arg("--script").arg("script.py")
|
||||
.arg("--output-format").arg("json")
|
||||
.env(EnvVars::VIRTUAL_ENV, "foo").arg("--active"), @r#"
|
||||
|
|
@ -5693,7 +5675,7 @@ fn sync_active_script_environment_json() -> Result<()> {
|
|||
.assert(predicate::path::is_dir());
|
||||
|
||||
// A subsequent sync will re-use the environment
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").env(EnvVars::VIRTUAL_ENV, "foo").arg("--active"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py").env(EnvVars::VIRTUAL_ENV, "foo").arg("--active"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -5705,7 +5687,7 @@ fn sync_active_script_environment_json() -> Result<()> {
|
|||
");
|
||||
|
||||
// Requesting another Python version will invalidate the environment
|
||||
uv_snapshot!(&filters, context.sync()
|
||||
uv_snapshot!(context.filters(), context.sync()
|
||||
.arg("--script").arg("script.py")
|
||||
.arg("--output-format").arg("json")
|
||||
.env(EnvVars::VIRTUAL_ENV, "foo")
|
||||
|
|
@ -9591,16 +9573,7 @@ fn sync_script() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/script-\w+",
|
||||
"environments-v2/script-[HASH]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -9632,7 +9605,7 @@ fn sync_script() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -9658,7 +9631,7 @@ fn sync_script() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -9683,7 +9656,7 @@ fn sync_script() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -9701,7 +9674,7 @@ fn sync_script() -> Result<()> {
|
|||
");
|
||||
|
||||
// `--locked` and `--frozen` should fail with helpful error messages.
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--locked"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py").arg("--locked"), @r"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
|
@ -9711,7 +9684,7 @@ fn sync_script() -> Result<()> {
|
|||
error: `uv sync --locked` requires a script lockfile; run `uv lock --script script.py` to lock the script
|
||||
");
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--frozen"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py").arg("--frozen"), @r"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
|
@ -9741,17 +9714,8 @@ fn sync_locked_script() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/script-\w+",
|
||||
"environments-v2/script-[HASH]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Lock the script.
|
||||
uv_snapshot!(&filters, context.lock().arg("--script").arg("script.py"), @r###"
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--script").arg("script.py"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -9811,7 +9775,7 @@ fn sync_locked_script() -> Result<()> {
|
|||
);
|
||||
});
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -9841,7 +9805,7 @@ fn sync_locked_script() -> Result<()> {
|
|||
})?;
|
||||
|
||||
// Re-run with `--locked`.
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--locked"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py").arg("--locked"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
|
@ -9852,7 +9816,7 @@ fn sync_locked_script() -> Result<()> {
|
|||
The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`.
|
||||
");
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -9943,7 +9907,7 @@ fn sync_locked_script() -> Result<()> {
|
|||
})?;
|
||||
|
||||
// Re-run with `--locked`.
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--locked"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py").arg("--locked"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
|
@ -9955,7 +9919,7 @@ fn sync_locked_script() -> Result<()> {
|
|||
The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`.
|
||||
");
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -10000,16 +9964,7 @@ fn sync_script_with_compatible_build_constraints() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/script-\w+",
|
||||
"environments-v2/script-[HASH]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
|
@ -10035,14 +9990,6 @@ fn sync_script_with_incompatible_build_constraints() -> Result<()> {
|
|||
let context = TestContext::new("3.9");
|
||||
|
||||
let test_script = context.temp_dir.child("script.py");
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/script-\w+",
|
||||
"environments-v2/script-[HASH]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Incompatible build constraints.
|
||||
test_script.write_str(indoc! { r#"
|
||||
|
|
@ -10061,7 +10008,7 @@ fn sync_script_with_incompatible_build_constraints() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
|
|
|||
|
|
@ -3629,3 +3629,206 @@ fn tool_install_mismatched_name() {
|
|||
error: Package name (`black`) provided with `--from` does not match install request (`flask`)
|
||||
"###);
|
||||
}
|
||||
|
||||
/// When installing from an authenticated index, the credentials should be omitted from the receipt.
|
||||
#[test]
|
||||
fn tool_install_credentials() {
|
||||
let context = TestContext::new("3.12")
|
||||
.with_exclude_newer("2025-01-18T00:00:00Z")
|
||||
.with_filtered_counts()
|
||||
.with_filtered_exe_suffix();
|
||||
let tool_dir = context.temp_dir.child("tools");
|
||||
let bin_dir = context.temp_dir.child("bin");
|
||||
|
||||
// Install `executable-application`
|
||||
uv_snapshot!(context.filters(), context.tool_install()
|
||||
.arg("executable-application")
|
||||
.arg("--index")
|
||||
.arg("https://public:heron@pypi-proxy.fly.dev/basic-auth/simple")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.env(EnvVars::PATH, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved [N] packages in [TIME]
|
||||
Prepared [N] packages in [TIME]
|
||||
Installed [N] packages in [TIME]
|
||||
+ executable-application==0.3.0
|
||||
Installed 1 executable: app
|
||||
"###);
|
||||
|
||||
tool_dir
|
||||
.child("executable-application")
|
||||
.assert(predicate::path::is_dir());
|
||||
tool_dir
|
||||
.child("executable-application")
|
||||
.child("uv-receipt.toml")
|
||||
.assert(predicate::path::exists());
|
||||
|
||||
let executable = bin_dir.child(format!("app{}", std::env::consts::EXE_SUFFIX));
|
||||
assert!(executable.exists());
|
||||
|
||||
// On Windows, we can't snapshot an executable file.
|
||||
#[cfg(not(windows))]
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
// Should run black in the virtual environment
|
||||
assert_snapshot!(fs_err::read_to_string(executable).unwrap(), @r###"
|
||||
#![TEMP_DIR]/tools/executable-application/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
from executable_application import main
|
||||
if __name__ == "__main__":
|
||||
if sys.argv[0].endswith("-script.pyw"):
|
||||
sys.argv[0] = sys.argv[0][:-11]
|
||||
elif sys.argv[0].endswith(".exe"):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
"###);
|
||||
|
||||
});
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
// We should have a tool receipt
|
||||
assert_snapshot!(fs_err::read_to_string(tool_dir.join("executable-application").join("uv-receipt.toml")).unwrap(), @r#"
|
||||
[tool]
|
||||
requirements = [{ name = "executable-application" }]
|
||||
entrypoints = [
|
||||
{ name = "app", install-path = "[TEMP_DIR]/bin/app" },
|
||||
]
|
||||
|
||||
[tool.options]
|
||||
index = [{ url = "https://pypi-proxy.fly.dev/basic-auth/simple", explicit = false, default = false, format = "simple", authenticate = "auto" }]
|
||||
exclude-newer = "2025-01-18T00:00:00Z"
|
||||
"#);
|
||||
});
|
||||
}
|
||||
|
||||
/// When installing from an authenticated index, the credentials should be omitted from the receipt.
|
||||
#[test]
|
||||
fn tool_install_default_credentials() -> Result<()> {
|
||||
let context = TestContext::new("3.12")
|
||||
.with_exclude_newer("2025-01-18T00:00:00Z")
|
||||
.with_filtered_counts()
|
||||
.with_filtered_exe_suffix();
|
||||
let tool_dir = context.temp_dir.child("tools");
|
||||
let bin_dir = context.temp_dir.child("bin");
|
||||
|
||||
// Write a `uv.toml` with a default index that has credentials.
|
||||
let uv_toml = context.temp_dir.child("uv.toml");
|
||||
uv_toml.write_str(indoc::indoc! {r#"
|
||||
[[index]]
|
||||
url = "https://public:heron@pypi-proxy.fly.dev/basic-auth/simple"
|
||||
default = true
|
||||
authenticate = "always"
|
||||
"#})?;
|
||||
|
||||
// Install `executable-application`
|
||||
uv_snapshot!(context.filters(), context.tool_install()
|
||||
.arg("executable-application")
|
||||
.arg("--config-file")
|
||||
.arg(uv_toml.as_os_str())
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.env(EnvVars::PATH, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved [N] packages in [TIME]
|
||||
Prepared [N] packages in [TIME]
|
||||
Installed [N] packages in [TIME]
|
||||
+ executable-application==0.3.0
|
||||
Installed 1 executable: app
|
||||
"###);
|
||||
|
||||
tool_dir
|
||||
.child("executable-application")
|
||||
.assert(predicate::path::is_dir());
|
||||
tool_dir
|
||||
.child("executable-application")
|
||||
.child("uv-receipt.toml")
|
||||
.assert(predicate::path::exists());
|
||||
|
||||
let executable = bin_dir.child(format!("app{}", std::env::consts::EXE_SUFFIX));
|
||||
assert!(executable.exists());
|
||||
|
||||
// On Windows, we can't snapshot an executable file.
|
||||
#[cfg(not(windows))]
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
// Should run black in the virtual environment
|
||||
assert_snapshot!(fs_err::read_to_string(executable).unwrap(), @r###"
|
||||
#![TEMP_DIR]/tools/executable-application/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
from executable_application import main
|
||||
if __name__ == "__main__":
|
||||
if sys.argv[0].endswith("-script.pyw"):
|
||||
sys.argv[0] = sys.argv[0][:-11]
|
||||
elif sys.argv[0].endswith(".exe"):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
"###);
|
||||
|
||||
});
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
// We should have a tool receipt
|
||||
assert_snapshot!(fs_err::read_to_string(tool_dir.join("executable-application").join("uv-receipt.toml")).unwrap(), @r#"
|
||||
[tool]
|
||||
requirements = [{ name = "executable-application" }]
|
||||
entrypoints = [
|
||||
{ name = "app", install-path = "[TEMP_DIR]/bin/app" },
|
||||
]
|
||||
|
||||
[tool.options]
|
||||
index = [{ url = "https://pypi-proxy.fly.dev/basic-auth/simple", explicit = false, default = true, format = "simple", authenticate = "always" }]
|
||||
exclude-newer = "2025-01-18T00:00:00Z"
|
||||
"#);
|
||||
});
|
||||
|
||||
// Attempt to upgrade without providing the credentials (from the config file).
|
||||
uv_snapshot!(context.filters(), context.tool_upgrade()
|
||||
.arg("executable-application")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.env(EnvVars::PATH, bin_dir.as_os_str()), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Failed to upgrade executable-application
|
||||
Caused by: Failed to fetch: `https://pypi-proxy.fly.dev/basic-auth/simple/executable-application/`
|
||||
Caused by: Missing credentials for https://pypi-proxy.fly.dev/basic-auth/simple/executable-application/
|
||||
");
|
||||
|
||||
// Attempt to upgrade.
|
||||
uv_snapshot!(context.filters(), context.tool_upgrade()
|
||||
.arg("executable-application")
|
||||
.arg("--config-file")
|
||||
.arg(uv_toml.as_os_str())
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.env(EnvVars::PATH, bin_dir.as_os_str()), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Nothing to upgrade
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ To use uv as a build backend in an existing project, add `uv_build` to the
|
|||
|
||||
```toml title="pyproject.toml"
|
||||
[build-system]
|
||||
requires = ["uv_build>=0.8.2,<0.9.0"]
|
||||
requires = ["uv_build>=0.8.3,<0.9.0"]
|
||||
build-backend = "uv_build"
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ uv provides a standalone installer to download and install uv:
|
|||
Request a specific version by including it in the URL:
|
||||
|
||||
```console
|
||||
$ curl -LsSf https://astral.sh/uv/0.8.2/install.sh | sh
|
||||
$ curl -LsSf https://astral.sh/uv/0.8.3/install.sh | sh
|
||||
```
|
||||
|
||||
=== "Windows"
|
||||
|
|
@ -41,7 +41,7 @@ uv provides a standalone installer to download and install uv:
|
|||
Request a specific version by including it in the URL:
|
||||
|
||||
```pwsh-session
|
||||
PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.8.2/install.ps1 | iex"
|
||||
PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.8.3/install.ps1 | iex"
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ the second stage, we'll copy this directory over to the final image, omitting th
|
|||
other unnecessary files.
|
||||
|
||||
```dockerfile title="Dockerfile"
|
||||
FROM ghcr.io/astral-sh/uv:0.8.2 AS uv
|
||||
FROM ghcr.io/astral-sh/uv:0.8.3 AS uv
|
||||
|
||||
# First, bundle the dependencies into the task root.
|
||||
FROM public.ecr.aws/lambda/python:3.13 AS builder
|
||||
|
|
@ -334,7 +334,7 @@ And confirm that opening http://127.0.0.1:8000/ in a web browser displays, "Hell
|
|||
Finally, we'll update the Dockerfile to include the local library in the deployment package:
|
||||
|
||||
```dockerfile title="Dockerfile"
|
||||
FROM ghcr.io/astral-sh/uv:0.8.2 AS uv
|
||||
FROM ghcr.io/astral-sh/uv:0.8.3 AS uv
|
||||
|
||||
# First, bundle the dependencies into the task root.
|
||||
FROM public.ecr.aws/lambda/python:3.13 AS builder
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ $ docker run --rm -it ghcr.io/astral-sh/uv:debian uv --help
|
|||
The following distroless images are available:
|
||||
|
||||
- `ghcr.io/astral-sh/uv:latest`
|
||||
- `ghcr.io/astral-sh/uv:{major}.{minor}.{patch}`, e.g., `ghcr.io/astral-sh/uv:0.8.2`
|
||||
- `ghcr.io/astral-sh/uv:{major}.{minor}.{patch}`, e.g., `ghcr.io/astral-sh/uv:0.8.3`
|
||||
- `ghcr.io/astral-sh/uv:{major}.{minor}`, e.g., `ghcr.io/astral-sh/uv:0.8` (the latest patch
|
||||
version)
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ And the following derived images are available:
|
|||
|
||||
As with the distroless image, each derived image is published with uv version tags as
|
||||
`ghcr.io/astral-sh/uv:{major}.{minor}.{patch}-{base}` and
|
||||
`ghcr.io/astral-sh/uv:{major}.{minor}-{base}`, e.g., `ghcr.io/astral-sh/uv:0.8.2-alpine`.
|
||||
`ghcr.io/astral-sh/uv:{major}.{minor}-{base}`, e.g., `ghcr.io/astral-sh/uv:0.8.3-alpine`.
|
||||
|
||||
In addition, starting with `0.8` each derived image also sets `UV_TOOL_BIN_DIR` to `/usr/local/bin`
|
||||
to allow `uv tool install` to work as expected with the default user.
|
||||
|
|
@ -116,7 +116,7 @@ Note this requires `curl` to be available.
|
|||
In either case, it is best practice to pin to a specific uv version, e.g., with:
|
||||
|
||||
```dockerfile
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.8.2 /uv /uvx /bin/
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.8.3 /uv /uvx /bin/
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
|
@ -134,7 +134,7 @@ COPY --from=ghcr.io/astral-sh/uv:0.8.2 /uv /uvx /bin/
|
|||
Or, with the installer:
|
||||
|
||||
```dockerfile
|
||||
ADD https://astral.sh/uv/0.8.2/install.sh /uv-installer.sh
|
||||
ADD https://astral.sh/uv/0.8.3/install.sh /uv-installer.sh
|
||||
```
|
||||
|
||||
### Installing a project
|
||||
|
|
@ -560,5 +560,5 @@ Verified OK
|
|||
!!! tip
|
||||
|
||||
These examples use `latest`, but best practice is to verify the attestation for a specific
|
||||
version tag, e.g., `ghcr.io/astral-sh/uv:0.8.2`, or (even better) the specific image digest,
|
||||
version tag, e.g., `ghcr.io/astral-sh/uv:0.8.3`, or (even better) the specific image digest,
|
||||
such as `ghcr.io/astral-sh/uv:0.5.27@sha256:5adf09a5a526f380237408032a9308000d14d5947eafa687ad6c6a2476787b4f`.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ jobs:
|
|||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
# Install a specific version of uv.
|
||||
version: "0.8.2"
|
||||
version: "0.8.3"
|
||||
```
|
||||
|
||||
## Setting up Python
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ To make sure your `uv.lock` file is up to date even if your `pyproject.toml` fil
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||
# uv version.
|
||||
rev: 0.8.2
|
||||
rev: 0.8.3
|
||||
hooks:
|
||||
- id: uv-lock
|
||||
```
|
||||
|
|
@ -30,7 +30,7 @@ To keep a `requirements.txt` file in sync with your `uv.lock` file:
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||
# uv version.
|
||||
rev: 0.8.2
|
||||
rev: 0.8.3
|
||||
hooks:
|
||||
- id: uv-export
|
||||
```
|
||||
|
|
@ -41,7 +41,7 @@ To compile requirements files:
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||
# uv version.
|
||||
rev: 0.8.2
|
||||
rev: 0.8.3
|
||||
hooks:
|
||||
# Compile requirements
|
||||
- id: pip-compile
|
||||
|
|
@ -54,7 +54,7 @@ To compile alternative requirements files, modify `args` and `files`:
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||
# uv version.
|
||||
rev: 0.8.2
|
||||
rev: 0.8.3
|
||||
hooks:
|
||||
# Compile requirements
|
||||
- id: pip-compile
|
||||
|
|
@ -68,7 +68,7 @@ To run the hook over multiple files at the same time, add additional entries:
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||
# uv version.
|
||||
rev: 0.8.2
|
||||
rev: 0.8.3
|
||||
hooks:
|
||||
# Compile requirements
|
||||
- id: pip-compile
|
||||
|
|
|
|||
|
|
@ -306,6 +306,10 @@ Equivalent to the `--prerelease` command-line argument. For example, if set to
|
|||
|
||||
Equivalent to the `--preview` argument. Enables preview mode.
|
||||
|
||||
### `UV_PREVIEW_FEATURES`
|
||||
|
||||
Equivalent to the `--preview-features` argument. Enables specific preview features.
|
||||
|
||||
### `UV_PROJECT`
|
||||
|
||||
Equivalent to the `--project` command-line argument.
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ data files are included by placing them in the Python module instead of using da
|
|||
with this package as build requirement use the include directory to find additional header
|
||||
files.
|
||||
- `purelib` and `platlib`: Installed to the `site-packages` directory. It is not recommended
|
||||
to uses these two options.
|
||||
to use these two options.
|
||||
|
||||
**Default value**: `{}`
|
||||
|
||||
|
|
@ -457,7 +457,7 @@ data files are included by placing them in the Python module instead of using da
|
|||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.uv.build-backend]
|
||||
data = { "headers": "include/headers", "scripts": "bin" }
|
||||
data = { headers = "include/headers", scripts = "bin" }
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ build-backend = "maturin"
|
|||
|
||||
[project]
|
||||
name = "uv"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
description = "An extremely fast Python package and project manager, written in Rust."
|
||||
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
|
||||
requires-python = ">=3.8"
|
||||
|
|
|
|||
|
|
@ -670,7 +670,7 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"description": "Data includes for wheels.\n\nEach entry is a directory, whose contents are copied to the matching directory in the wheel\nin `<name>-<version>.data/(purelib|platlib|headers|scripts|data)`. Upon installation, this\ndata is moved to its target location, as defined by\n<https://docs.python.org/3.12/library/sysconfig.html#installation-paths>. Usually, small\ndata files are included by placing them in the Python module instead of using data includes.\n\n- `scripts`: Installed to the directory for executables, `<venv>/bin` on Unix or\n `<venv>\\Scripts` on Windows. This directory is added to `PATH` when the virtual\n environment is activated or when using `uv run`, so this data type can be used to install\n additional binaries. Consider using `project.scripts` instead for Python entrypoints.\n- `data`: Installed over the virtualenv environment root.\n\n Warning: This may override existing files!\n\n- `headers`: Installed to the include directory. Compilers building Python packages\n with this package as build requirement use the include directory to find additional header\n files.\n- `purelib` and `platlib`: Installed to the `site-packages` directory. It is not recommended\n to uses these two options.",
|
||||
"description": "Data includes for wheels.\n\nEach entry is a directory, whose contents are copied to the matching directory in the wheel\nin `<name>-<version>.data/(purelib|platlib|headers|scripts|data)`. Upon installation, this\ndata is moved to its target location, as defined by\n<https://docs.python.org/3.12/library/sysconfig.html#installation-paths>. Usually, small\ndata files are included by placing them in the Python module instead of using data includes.\n\n- `scripts`: Installed to the directory for executables, `<venv>/bin` on Unix or\n `<venv>\\Scripts` on Windows. This directory is added to `PATH` when the virtual\n environment is activated or when using `uv run`, so this data type can be used to install\n additional binaries. Consider using `project.scripts` instead for Python entrypoints.\n- `data`: Installed over the virtualenv environment root.\n\n Warning: This may override existing files!\n\n- `headers`: Installed to the include directory. Compilers building Python packages\n with this package as build requirement use the include directory to find additional header\n files.\n- `purelib` and `platlib`: Installed to the `site-packages` directory. It is not recommended\n to use these two options.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WheelDataIncludes"
|
||||
|
|
|
|||
Loading…
Reference in New Issue