mirror of https://github.com/astral-sh/uv
Compare commits
No commits in common. "main" and "0.9.18" have entirely different histories.
|
|
@ -1,125 +0,0 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
- [Our Pledge](#our-pledge)
|
||||
- [Our Standards](#our-standards)
|
||||
- [Enforcement Responsibilities](#enforcement-responsibilities)
|
||||
- [Scope](#scope)
|
||||
- [Enforcement](#enforcement)
|
||||
- [Enforcement Guidelines](#enforcement-guidelines)
|
||||
- [1. Correction](#1-correction)
|
||||
- [2. Warning](#2-warning)
|
||||
- [3. Temporary Ban](#3-temporary-ban)
|
||||
- [4. Permanent Ban](#4-permanent-ban)
|
||||
- [Attribution](#attribution)
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our community a
|
||||
harassment-free experience for everyone, regardless of age, body size, visible or invisible
|
||||
disability, ethnicity, sex characteristics, gender identity and expression, level of experience,
|
||||
education, socio-economic status, nationality, personal appearance, race, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and
|
||||
healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our community include:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the
|
||||
experience
|
||||
- Focusing on what is best not just for us as individuals, but for the overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address, without their
|
||||
explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior
|
||||
and will take appropriate and fair corrective action in response to any behavior that they deem
|
||||
inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject comments, commits,
|
||||
code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and
|
||||
will communicate reasons for moderation decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when an individual is
|
||||
officially representing the community in public spaces. Examples of representing our community
|
||||
include using an official e-mail address, posting via an official social media account, or acting as
|
||||
an appointed representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community
|
||||
leaders responsible for enforcement at <hey@astral.sh>. All complaints will be reviewed and
|
||||
investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the reporter of any
|
||||
incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining the consequences for
|
||||
any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or
|
||||
unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing clarity around the
|
||||
nature of the violation and an explanation of why the behavior was inappropriate. A public apology
|
||||
may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No interaction with the people
|
||||
involved, including unsolicited interaction with those enforcing the Code of Conduct, for a
|
||||
specified period of time. This includes avoiding interactions in community spaces as well as
|
||||
external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including sustained inappropriate
|
||||
behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public communication with the
|
||||
community for a specified period of time. No public or private interaction with the people involved,
|
||||
including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this
|
||||
period. Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community standards, including
|
||||
sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement
|
||||
of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available
|
||||
[here](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html).
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
For answers to common questions about this code of conduct, see the
|
||||
[FAQ](https://www.contributor-covenant.org/faq). Translations are available
|
||||
[here](https://www.contributor-covenant.org/translations).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
19
README.md
19
README.md
|
|
@ -42,7 +42,7 @@ An extremely fast Python package and project manager, written in Rust.
|
|||
- 🖥️ Supports macOS, Linux, and Windows.
|
||||
|
||||
uv is backed by [Astral](https://astral.sh), the creators of
|
||||
[Ruff](https://github.com/astral-sh/ruff) and [ty](https://github.com/astral-sh/ty).
|
||||
[Ruff](https://github.com/astral-sh/ruff).
|
||||
|
||||
## Installation
|
||||
|
||||
|
|
@ -268,6 +268,14 @@ Installed 43 packages in 208ms
|
|||
|
||||
See the [pip interface documentation](https://docs.astral.sh/uv/pip/index/) to get started.
|
||||
|
||||
## Platform support
|
||||
|
||||
See uv's [platform support](https://docs.astral.sh/uv/reference/platforms/) document.
|
||||
|
||||
## Versioning policy
|
||||
|
||||
See uv's [versioning policy](https://docs.astral.sh/uv/reference/versioning/) document.
|
||||
|
||||
## Contributing
|
||||
|
||||
We are passionate about supporting contributors of all levels of experience and would love to see
|
||||
|
|
@ -284,15 +292,6 @@ It's pronounced as "you - vee" ([`/juː viː/`](https://en.wikipedia.org/wiki/He
|
|||
|
||||
Just "uv", please. See the [style guide](./STYLE.md#styling-uv) for details.
|
||||
|
||||
#### What platforms does uv support?
|
||||
|
||||
See uv's [platform support](https://docs.astral.sh/uv/reference/platforms/) document.
|
||||
|
||||
#### Is uv ready for production?
|
||||
|
||||
Yes, uv is stable and widely used in production. See uv's
|
||||
[versioning policy](https://docs.astral.sh/uv/reference/versioning/) document for details.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
uv's dependency resolver uses [PubGrub](https://github.com/pubgrub-rs/pubgrub) under the hood. We're
|
||||
|
|
|
|||
|
|
@ -3309,9 +3309,7 @@ pub struct InitArgs {
|
|||
///
|
||||
/// Disables creating extra files like `README.md`, the `src/` tree, `.python-version` files,
|
||||
/// etc.
|
||||
///
|
||||
/// When combined with `--script`, the script will only contain the inline metadata header.
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "script")]
|
||||
pub bare: bool,
|
||||
|
||||
/// Create a virtual project, rather than a package.
|
||||
|
|
@ -5373,21 +5371,6 @@ pub struct ToolRunArgs {
|
|||
#[arg(long)]
|
||||
pub python_platform: Option<TargetTriple>,
|
||||
|
||||
/// The backend to use when fetching packages in the PyTorch ecosystem (e.g., `cpu`, `cu126`, or `auto`)
|
||||
///
|
||||
/// When set, uv will ignore the configured index URLs for packages in the PyTorch ecosystem,
|
||||
/// and will instead use the defined backend.
|
||||
///
|
||||
/// For example, when set to `cpu`, uv will use the CPU-only PyTorch index; when set to `cu126`,
|
||||
/// uv will use the PyTorch index for CUDA 12.6.
|
||||
///
|
||||
/// The `auto` mode will attempt to detect the appropriate PyTorch index based on the currently
|
||||
/// installed CUDA drivers.
|
||||
///
|
||||
/// This option is in preview and may change in any future release.
|
||||
#[arg(long, value_enum, env = EnvVars::UV_TORCH_BACKEND)]
|
||||
pub torch_backend: Option<TorchMode>,
|
||||
|
||||
#[arg(long, hide = true)]
|
||||
pub generate_shell_completion: Option<clap_complete_command::Shell>,
|
||||
}
|
||||
|
|
@ -5564,21 +5547,6 @@ pub struct ToolInstallArgs {
|
|||
/// `--python-platform` option is intended for advanced use cases.
|
||||
#[arg(long)]
|
||||
pub python_platform: Option<TargetTriple>,
|
||||
|
||||
/// The backend to use when fetching packages in the PyTorch ecosystem (e.g., `cpu`, `cu126`, or `auto`)
|
||||
///
|
||||
/// When set, uv will ignore the configured index URLs for packages in the PyTorch ecosystem,
|
||||
/// and will instead use the defined backend.
|
||||
///
|
||||
/// For example, when set to `cpu`, uv will use the CPU-only PyTorch index; when set to `cu126`,
|
||||
/// uv will use the PyTorch index for CUDA 12.6.
|
||||
///
|
||||
/// The `auto` mode will attempt to detect the appropriate PyTorch index based on the currently
|
||||
/// installed CUDA drivers.
|
||||
///
|
||||
/// This option is in preview and may change in any future release.
|
||||
#[arg(long, value_enum, env = EnvVars::UV_TORCH_BACKEND)]
|
||||
pub torch_backend: Option<TorchMode>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
|
|
|
|||
|
|
@ -366,7 +366,6 @@ pub fn resolver_options(
|
|||
exclude_newer_package.unwrap_or_default(),
|
||||
),
|
||||
link_mode,
|
||||
torch_backend: None,
|
||||
no_build: flag(no_build, build, "build"),
|
||||
no_build_package: Some(no_build_package),
|
||||
no_binary: flag(no_binary, binary, "binary"),
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ impl RequirementsSpecification {
|
|||
}
|
||||
}
|
||||
RequirementsSource::PylockToml(path) => {
|
||||
if !(path.starts_with("http://") || path.starts_with("https://") || path.exists()) {
|
||||
if !path.is_file() {
|
||||
return Err(anyhow::anyhow!("File not found: `{}`", path.user_display()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use uv_normalize::{ExtraName, GroupName, PackageName};
|
|||
use uv_platform_tags::Tags;
|
||||
use uv_pypi_types::ResolverMarkerEnvironment;
|
||||
|
||||
use crate::lock::{HashedDist, LockErrorKind, Package, TagPolicy};
|
||||
use crate::lock::{LockErrorKind, Package, TagPolicy};
|
||||
use crate::{Lock, LockError};
|
||||
|
||||
pub trait Installable<'lock> {
|
||||
|
|
@ -527,14 +527,18 @@ pub trait Installable<'lock> {
|
|||
marker_env: &ResolverMarkerEnvironment,
|
||||
build_options: &BuildOptions,
|
||||
) -> Result<Node, LockError> {
|
||||
let tag_policy = TagPolicy::Required(tags);
|
||||
let HashedDist { dist, hashes } =
|
||||
package.to_dist(self.install_path(), tag_policy, build_options, marker_env)?;
|
||||
let dist = package.to_dist(
|
||||
self.install_path(),
|
||||
TagPolicy::Required(tags),
|
||||
build_options,
|
||||
marker_env,
|
||||
)?;
|
||||
let version = package.version().cloned();
|
||||
let dist = ResolvedDist::Installable {
|
||||
dist: Arc::new(dist),
|
||||
version,
|
||||
};
|
||||
let hashes = package.hashes();
|
||||
Ok(Node::Dist {
|
||||
dist,
|
||||
hashes,
|
||||
|
|
@ -549,7 +553,7 @@ pub trait Installable<'lock> {
|
|||
tags: &Tags,
|
||||
marker_env: &ResolverMarkerEnvironment,
|
||||
) -> Result<Node, LockError> {
|
||||
let HashedDist { dist, .. } = package.to_dist(
|
||||
let dist = package.to_dist(
|
||||
self.install_path(),
|
||||
TagPolicy::Preferred(tags),
|
||||
&BuildOptions::default(),
|
||||
|
|
|
|||
|
|
@ -171,15 +171,6 @@ static ANDROID_X86_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
|||
marker
|
||||
});
|
||||
|
||||
/// A distribution with its associated hash.
|
||||
///
|
||||
/// This pairs a [`Dist`] with the [`HashDigests`] for the specific wheel or
|
||||
/// sdist that would be installed.
|
||||
pub(crate) struct HashedDist {
|
||||
pub(crate) dist: Dist,
|
||||
pub(crate) hashes: HashDigests,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(try_from = "LockWire")]
|
||||
pub struct Lock {
|
||||
|
|
@ -1770,7 +1761,7 @@ impl Lock {
|
|||
|
||||
if let Some(version) = package.id.version.as_ref() {
|
||||
// For a non-dynamic package, fetch the metadata from the distribution database.
|
||||
let HashedDist { dist, .. } = package.to_dist(
|
||||
let dist = package.to_dist(
|
||||
root,
|
||||
TagPolicy::Preferred(tags),
|
||||
&BuildOptions::default(),
|
||||
|
|
@ -1921,7 +1912,7 @@ impl Lock {
|
|||
// exactly. For example, `hatchling` will flatten any recursive (or self-referential)
|
||||
// extras, while `setuptools` will not.
|
||||
if !satisfied {
|
||||
let HashedDist { dist, .. } = package.to_dist(
|
||||
let dist = package.to_dist(
|
||||
root,
|
||||
TagPolicy::Preferred(tags),
|
||||
&BuildOptions::default(),
|
||||
|
|
@ -2588,26 +2579,20 @@ impl Package {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Convert the [`Package`] to a [`Dist`] that can be used in installation, along with its hash.
|
||||
/// Convert the [`Package`] to a [`Dist`] that can be used in installation.
|
||||
fn to_dist(
|
||||
&self,
|
||||
workspace_root: &Path,
|
||||
tag_policy: TagPolicy<'_>,
|
||||
build_options: &BuildOptions,
|
||||
markers: &MarkerEnvironment,
|
||||
) -> Result<HashedDist, LockError> {
|
||||
) -> Result<Dist, LockError> {
|
||||
let no_binary = build_options.no_binary_package(&self.id.name);
|
||||
let no_build = build_options.no_build_package(&self.id.name);
|
||||
|
||||
if !no_binary {
|
||||
if let Some(best_wheel_index) = self.find_best_wheel(tag_policy) {
|
||||
let hashes = self.wheels[best_wheel_index]
|
||||
.hash
|
||||
.as_ref()
|
||||
.map(|hash| HashDigests::from(vec![hash.0.clone()]))
|
||||
.unwrap_or_else(|| HashDigests::from(vec![]));
|
||||
|
||||
let dist = match &self.id.source {
|
||||
return match &self.id.source {
|
||||
Source::Registry(source) => {
|
||||
let wheels = self
|
||||
.wheels
|
||||
|
|
@ -2619,7 +2604,7 @@ impl Package {
|
|||
best_wheel_index,
|
||||
sdist: None,
|
||||
};
|
||||
Dist::Built(BuiltDist::Registry(reg_built_dist))
|
||||
Ok(Dist::Built(BuiltDist::Registry(reg_built_dist)))
|
||||
}
|
||||
Source::Path(path) => {
|
||||
let filename: WheelFilename =
|
||||
|
|
@ -2631,7 +2616,7 @@ impl Package {
|
|||
install_path: absolute_path(workspace_root, path)?.into_boxed_path(),
|
||||
};
|
||||
let built_dist = BuiltDist::Path(path_dist);
|
||||
Dist::Built(built_dist)
|
||||
Ok(Dist::Built(built_dist))
|
||||
}
|
||||
Source::Direct(url, direct) => {
|
||||
let filename: WheelFilename =
|
||||
|
|
@ -2647,39 +2632,29 @@ impl Package {
|
|||
url: VerbatimUrl::from_url(url),
|
||||
};
|
||||
let built_dist = BuiltDist::DirectUrl(direct_dist);
|
||||
Dist::Built(built_dist)
|
||||
Ok(Dist::Built(built_dist))
|
||||
}
|
||||
Source::Git(_, _) => {
|
||||
return Err(LockErrorKind::InvalidWheelSource {
|
||||
id: self.id.clone(),
|
||||
source_type: "Git",
|
||||
}
|
||||
.into());
|
||||
Source::Git(_, _) => Err(LockErrorKind::InvalidWheelSource {
|
||||
id: self.id.clone(),
|
||||
source_type: "Git",
|
||||
}
|
||||
Source::Directory(_) => {
|
||||
return Err(LockErrorKind::InvalidWheelSource {
|
||||
id: self.id.clone(),
|
||||
source_type: "directory",
|
||||
}
|
||||
.into());
|
||||
.into()),
|
||||
Source::Directory(_) => Err(LockErrorKind::InvalidWheelSource {
|
||||
id: self.id.clone(),
|
||||
source_type: "directory",
|
||||
}
|
||||
Source::Editable(_) => {
|
||||
return Err(LockErrorKind::InvalidWheelSource {
|
||||
id: self.id.clone(),
|
||||
source_type: "editable",
|
||||
}
|
||||
.into());
|
||||
.into()),
|
||||
Source::Editable(_) => Err(LockErrorKind::InvalidWheelSource {
|
||||
id: self.id.clone(),
|
||||
source_type: "editable",
|
||||
}
|
||||
Source::Virtual(_) => {
|
||||
return Err(LockErrorKind::InvalidWheelSource {
|
||||
id: self.id.clone(),
|
||||
source_type: "virtual",
|
||||
}
|
||||
.into());
|
||||
.into()),
|
||||
Source::Virtual(_) => Err(LockErrorKind::InvalidWheelSource {
|
||||
id: self.id.clone(),
|
||||
source_type: "virtual",
|
||||
}
|
||||
.into()),
|
||||
};
|
||||
|
||||
return Ok(HashedDist { dist, hashes });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2688,16 +2663,7 @@ impl Package {
|
|||
// any local source tree, or at least editable source trees, which we allow in
|
||||
// `uv pip`.)
|
||||
if !no_build || sdist.is_virtual() {
|
||||
let hashes = self
|
||||
.sdist
|
||||
.as_ref()
|
||||
.and_then(|s| s.hash())
|
||||
.map(|hash| HashDigests::from(vec![hash.0.clone()]))
|
||||
.unwrap_or_else(|| HashDigests::from(vec![]));
|
||||
return Ok(HashedDist {
|
||||
dist: Dist::Source(sdist),
|
||||
hashes,
|
||||
});
|
||||
return Ok(Dist::Source(sdist));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,6 @@ impl Pep723Script {
|
|||
file: impl AsRef<Path>,
|
||||
requires_python: &VersionSpecifiers,
|
||||
existing_contents: Option<Vec<u8>>,
|
||||
bare: bool,
|
||||
) -> Result<(), Pep723Error> {
|
||||
let file = file.as_ref();
|
||||
|
||||
|
|
@ -306,8 +305,6 @@ impl Pep723Script {
|
|||
indoc::formatdoc! {r"
|
||||
{shebang}{metadata}
|
||||
{contents}" }
|
||||
} else if bare {
|
||||
metadata
|
||||
} else {
|
||||
indoc::formatdoc! {r#"
|
||||
{metadata}
|
||||
|
|
|
|||
|
|
@ -370,7 +370,6 @@ pub struct ResolverOptions {
|
|||
pub config_settings_package: Option<PackageConfigSettings>,
|
||||
pub exclude_newer: ExcludeNewer,
|
||||
pub link_mode: Option<LinkMode>,
|
||||
pub torch_backend: Option<TorchMode>,
|
||||
pub upgrade: Option<Upgrade>,
|
||||
pub build_isolation: Option<BuildIsolation>,
|
||||
pub no_build: Option<bool>,
|
||||
|
|
@ -405,7 +404,6 @@ pub struct ResolverInstallerOptions {
|
|||
pub exclude_newer: Option<ExcludeNewerValue>,
|
||||
pub exclude_newer_package: Option<ExcludeNewerPackage>,
|
||||
pub link_mode: Option<LinkMode>,
|
||||
pub torch_backend: Option<TorchMode>,
|
||||
pub compile_bytecode: Option<bool>,
|
||||
pub no_sources: Option<bool>,
|
||||
pub upgrade: Option<Upgrade>,
|
||||
|
|
@ -414,6 +412,7 @@ pub struct ResolverInstallerOptions {
|
|||
pub no_build_package: Option<Vec<PackageName>>,
|
||||
pub no_binary: Option<bool>,
|
||||
pub no_binary_package: Option<Vec<PackageName>>,
|
||||
pub torch_backend: Option<TorchMode>,
|
||||
}
|
||||
|
||||
impl From<ResolverInstallerSchema> for ResolverInstallerOptions {
|
||||
|
|
@ -439,7 +438,6 @@ impl From<ResolverInstallerSchema> for ResolverInstallerOptions {
|
|||
exclude_newer,
|
||||
exclude_newer_package,
|
||||
link_mode,
|
||||
torch_backend,
|
||||
compile_bytecode,
|
||||
no_sources,
|
||||
upgrade,
|
||||
|
|
@ -450,6 +448,7 @@ impl From<ResolverInstallerSchema> for ResolverInstallerOptions {
|
|||
no_build_package,
|
||||
no_binary,
|
||||
no_binary_package,
|
||||
torch_backend,
|
||||
} = value;
|
||||
Self {
|
||||
index,
|
||||
|
|
@ -474,7 +473,6 @@ impl From<ResolverInstallerSchema> for ResolverInstallerOptions {
|
|||
exclude_newer,
|
||||
exclude_newer_package,
|
||||
link_mode,
|
||||
torch_backend,
|
||||
compile_bytecode,
|
||||
no_sources,
|
||||
upgrade: Upgrade::from_args(
|
||||
|
|
@ -490,6 +488,7 @@ impl From<ResolverInstallerSchema> for ResolverInstallerOptions {
|
|||
no_build_package,
|
||||
no_binary,
|
||||
no_binary_package,
|
||||
torch_backend,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1926,7 +1925,6 @@ impl From<ResolverInstallerSchema> for ResolverOptions {
|
|||
extra_build_dependencies: value.extra_build_dependencies,
|
||||
extra_build_variables: value.extra_build_variables,
|
||||
no_sources: value.no_sources,
|
||||
torch_backend: value.torch_backend,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2006,7 +2004,6 @@ pub struct ToolOptions {
|
|||
pub no_build_package: Option<Vec<PackageName>>,
|
||||
pub no_binary: Option<bool>,
|
||||
pub no_binary_package: Option<Vec<PackageName>>,
|
||||
pub torch_backend: Option<TorchMode>,
|
||||
}
|
||||
|
||||
impl From<ResolverInstallerOptions> for ToolOptions {
|
||||
|
|
@ -2037,7 +2034,6 @@ impl From<ResolverInstallerOptions> for ToolOptions {
|
|||
no_build_package: value.no_build_package,
|
||||
no_binary: value.no_binary,
|
||||
no_binary_package: value.no_binary_package,
|
||||
torch_backend: value.torch_backend,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2072,7 +2068,7 @@ impl From<ToolOptions> for ResolverInstallerOptions {
|
|||
no_build_package: value.no_build_package,
|
||||
no_binary: value.no_binary,
|
||||
no_binary_package: value.no_binary_package,
|
||||
torch_backend: value.torch_backend,
|
||||
torch_backend: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2154,7 +2150,7 @@ pub struct OptionsWire {
|
|||
// `crates/uv-workspace/src/pyproject.rs`. The documentation lives on that struct.
|
||||
// They're respected in both `pyproject.toml` and `uv.toml` files.
|
||||
override_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
|
||||
exclude_dependencies: Option<Vec<PackageName>>,
|
||||
exclude_dependencies: Option<Vec<uv_normalize::PackageName>>,
|
||||
constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
|
||||
build_constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
|
||||
environments: Option<SupportedEnvironments>,
|
||||
|
|
|
|||
|
|
@ -216,7 +216,6 @@ async fn build_impl(
|
|||
upgrade: _,
|
||||
build_options,
|
||||
sources,
|
||||
torch_backend: _,
|
||||
} = settings;
|
||||
|
||||
// Determine the source to build.
|
||||
|
|
|
|||
|
|
@ -500,28 +500,10 @@ pub(crate) async fn pip_install(
|
|||
);
|
||||
|
||||
let (resolution, hasher) = if let Some(pylock) = pylock {
|
||||
// Read the `pylock.toml` from disk or URL, and deserialize it from TOML.
|
||||
let (install_path, content) =
|
||||
if pylock.starts_with("http://") || pylock.starts_with("https://") {
|
||||
// Fetch the `pylock.toml` over HTTP(S).
|
||||
let url = uv_redacted::DisplaySafeUrl::parse(&pylock.to_string_lossy())?;
|
||||
let client = client_builder.build();
|
||||
let response = client
|
||||
.for_host(&url)
|
||||
.get(url::Url::from(url.clone()))
|
||||
.send()
|
||||
.await?;
|
||||
response.error_for_status_ref()?;
|
||||
let content = response.text().await?;
|
||||
// Use the current working directory as the install path for remote lock files.
|
||||
let install_path = std::env::current_dir()?;
|
||||
(install_path, content)
|
||||
} else {
|
||||
let install_path = std::path::absolute(&pylock)?;
|
||||
let install_path = install_path.parent().unwrap().to_path_buf();
|
||||
let content = fs_err::tokio::read_to_string(&pylock).await?;
|
||||
(install_path, content)
|
||||
};
|
||||
// Read the `pylock.toml` from disk, and deserialize it from TOML.
|
||||
let install_path = std::path::absolute(&pylock)?;
|
||||
let install_path = install_path.parent().unwrap();
|
||||
let content = fs_err::tokio::read_to_string(&pylock).await?;
|
||||
let lock = toml::from_str::<PylockToml>(&content).with_context(|| {
|
||||
format!("Not a valid `pylock.toml` file: {}", pylock.user_display())
|
||||
})?;
|
||||
|
|
@ -555,7 +537,7 @@ pub(crate) async fn pip_install(
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
let resolution = lock.to_resolution(
|
||||
&install_path,
|
||||
install_path,
|
||||
marker_env.markers(),
|
||||
&extras,
|
||||
&groups,
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ pub(crate) async fn init(
|
|||
|
||||
init_script(
|
||||
path,
|
||||
bare,
|
||||
python,
|
||||
install_mirrors,
|
||||
client_builder,
|
||||
|
|
@ -169,7 +168,7 @@ pub(crate) async fn init(
|
|||
.await?;
|
||||
|
||||
// Create the `README.md` if it does not already exist.
|
||||
if !no_readme && !bare {
|
||||
if !no_readme {
|
||||
let readme = path.join("README.md");
|
||||
if !readme.exists() {
|
||||
fs_err::write(readme, String::new())?;
|
||||
|
|
@ -202,7 +201,6 @@ pub(crate) async fn init(
|
|||
#[allow(clippy::fn_params_excessive_bools)]
|
||||
async fn init_script(
|
||||
script_path: &Path,
|
||||
bare: bool,
|
||||
python: Option<String>,
|
||||
install_mirrors: PythonInstallMirrors,
|
||||
client_builder: &BaseClientBuilder<'_>,
|
||||
|
|
@ -277,7 +275,7 @@ async fn init_script(
|
|||
fs_err::tokio::create_dir_all(parent).await?;
|
||||
}
|
||||
|
||||
Pep723Script::create(script_path, requires_python.specifiers(), content, bare).await?;
|
||||
Pep723Script::create(script_path, requires_python.specifiers(), content).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -831,7 +829,7 @@ impl InitProjectKind {
|
|||
author.as_ref(),
|
||||
description,
|
||||
no_description,
|
||||
no_readme || bare,
|
||||
no_readme,
|
||||
);
|
||||
|
||||
// Include additional project configuration for packaged applications
|
||||
|
|
@ -910,7 +908,7 @@ impl InitProjectKind {
|
|||
author.as_ref(),
|
||||
description,
|
||||
no_description,
|
||||
no_readme || bare,
|
||||
no_readme,
|
||||
);
|
||||
|
||||
// Always include a build system if the project is packaged.
|
||||
|
|
|
|||
|
|
@ -470,7 +470,6 @@ async fn do_lock(
|
|||
upgrade,
|
||||
build_options,
|
||||
sources,
|
||||
torch_backend: _,
|
||||
} = settings;
|
||||
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ use uv_resolver::{
|
|||
use uv_scripts::Pep723ItemRef;
|
||||
use uv_settings::PythonInstallMirrors;
|
||||
use uv_static::EnvVars;
|
||||
use uv_torch::{TorchSource, TorchStrategy};
|
||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
||||
use uv_virtualenv::remove_virtualenv;
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
|
|
@ -279,9 +278,6 @@ pub(crate) enum ProjectError {
|
|||
#[error(transparent)]
|
||||
RetryParsing(#[from] uv_client::RetryParsingError),
|
||||
|
||||
#[error(transparent)]
|
||||
Accelerator(#[from] uv_torch::AcceleratorError),
|
||||
|
||||
#[error(transparent)]
|
||||
Anyhow(#[from] anyhow::Error),
|
||||
}
|
||||
|
|
@ -1727,7 +1723,6 @@ pub(crate) async fn resolve_names(
|
|||
prerelease: _,
|
||||
resolution: _,
|
||||
sources,
|
||||
torch_backend,
|
||||
upgrade: _,
|
||||
},
|
||||
compile_bytecode: _,
|
||||
|
|
@ -1736,27 +1731,10 @@ pub(crate) async fn resolve_names(
|
|||
|
||||
let client_builder = client_builder.clone().keyring(*keyring_provider);
|
||||
|
||||
// Determine the PyTorch backend.
|
||||
let torch_backend = torch_backend
|
||||
.map(|mode| {
|
||||
let source = if uv_auth::PyxTokenStore::from_settings()
|
||||
.is_ok_and(|store| store.has_credentials())
|
||||
{
|
||||
TorchSource::Pyx
|
||||
} else {
|
||||
TorchSource::default()
|
||||
};
|
||||
TorchStrategy::from_mode(mode, source, interpreter.platform().os())
|
||||
})
|
||||
.transpose()
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
// Initialize the registry client.
|
||||
let client = RegistryClientBuilder::new(client_builder, cache.clone())
|
||||
.index_locations(index_locations.clone())
|
||||
.index_strategy(*index_strategy)
|
||||
.torch_backend(torch_backend.clone())
|
||||
.markers(interpreter.markers())
|
||||
.platform(interpreter.platform())
|
||||
.build();
|
||||
|
|
@ -1902,7 +1880,6 @@ pub(crate) async fn resolve_environment(
|
|||
upgrade: _,
|
||||
build_options,
|
||||
sources,
|
||||
torch_backend,
|
||||
} = settings;
|
||||
|
||||
// Respect all requirements from the provided sources.
|
||||
|
|
@ -1923,33 +1900,10 @@ pub(crate) async fn resolve_environment(
|
|||
let marker_env = pip::resolution_markers(None, python_platform, interpreter);
|
||||
let python_requirement = PythonRequirement::from_interpreter(interpreter);
|
||||
|
||||
// Determine the PyTorch backend.
|
||||
let torch_backend = torch_backend
|
||||
.map(|mode| {
|
||||
let source = if uv_auth::PyxTokenStore::from_settings()
|
||||
.is_ok_and(|store| store.has_credentials())
|
||||
{
|
||||
TorchSource::Pyx
|
||||
} else {
|
||||
TorchSource::default()
|
||||
};
|
||||
TorchStrategy::from_mode(
|
||||
mode,
|
||||
source,
|
||||
python_platform
|
||||
.map(|t| t.platform())
|
||||
.as_ref()
|
||||
.unwrap_or(interpreter.platform())
|
||||
.os(),
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
// Initialize the registry client.
|
||||
let client = RegistryClientBuilder::new(client_builder, cache.clone())
|
||||
.index_locations(index_locations.clone())
|
||||
.index_strategy(*index_strategy)
|
||||
.torch_backend(torch_backend.clone())
|
||||
.markers(interpreter.markers())
|
||||
.platform(interpreter.platform())
|
||||
.build();
|
||||
|
|
@ -2278,7 +2232,6 @@ pub(crate) async fn update_environment(
|
|||
prerelease,
|
||||
resolution,
|
||||
sources,
|
||||
torch_backend,
|
||||
upgrade,
|
||||
},
|
||||
compile_bytecode,
|
||||
|
|
@ -2349,33 +2302,10 @@ pub(crate) async fn update_environment(
|
|||
}
|
||||
}
|
||||
|
||||
// Determine the PyTorch backend.
|
||||
let torch_backend = torch_backend
|
||||
.map(|mode| {
|
||||
let source = if uv_auth::PyxTokenStore::from_settings()
|
||||
.is_ok_and(|store| store.has_credentials())
|
||||
{
|
||||
TorchSource::Pyx
|
||||
} else {
|
||||
TorchSource::default()
|
||||
};
|
||||
TorchStrategy::from_mode(
|
||||
mode,
|
||||
source,
|
||||
python_platform
|
||||
.map(|t| t.platform())
|
||||
.as_ref()
|
||||
.unwrap_or(interpreter.platform())
|
||||
.os(),
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
// Initialize the registry client.
|
||||
let client = RegistryClientBuilder::new(client_builder, cache.clone())
|
||||
.index_locations(index_locations.clone())
|
||||
.index_strategy(*index_strategy)
|
||||
.torch_backend(torch_backend.clone())
|
||||
.markers(interpreter.markers())
|
||||
.platform(interpreter.platform())
|
||||
.build();
|
||||
|
|
|
|||
|
|
@ -676,7 +676,6 @@ pub(super) async fn do_sync(
|
|||
prerelease: PrereleaseMode::default(),
|
||||
resolution: ResolutionMode::default(),
|
||||
sources,
|
||||
torch_backend: None,
|
||||
upgrade: Upgrade::default(),
|
||||
};
|
||||
script_extra_build_requires(
|
||||
|
|
|
|||
|
|
@ -212,7 +212,6 @@ pub(crate) async fn tree(
|
|||
upgrade: _,
|
||||
build_options: _,
|
||||
sources: _,
|
||||
torch_backend: _,
|
||||
} = &settings;
|
||||
|
||||
let capabilities = IndexCapabilities::default();
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use uv_python::{
|
|||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||
use uv_settings::{PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
|
||||
use uv_tool::InstalledTools;
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
use uv_warnings::warn_user;
|
||||
use uv_workspace::WorkspaceCache;
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
|
|
@ -76,12 +76,6 @@ pub(crate) async fn install(
|
|||
printer: Printer,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
if settings.resolver.torch_backend.is_some() {
|
||||
warn_user_once!(
|
||||
"The `--torch-backend` option is experimental and may change without warning."
|
||||
);
|
||||
}
|
||||
|
||||
let reporter = PythonDownloadReporter::single(printer);
|
||||
|
||||
let python_request = python.as_deref().map(PythonRequest::parse);
|
||||
|
|
|
|||
|
|
@ -129,12 +129,6 @@ pub(crate) async fn run(
|
|||
.is_some_and(|ext| ext.eq_ignore_ascii_case("py") || ext.eq_ignore_ascii_case("pyw"))
|
||||
}
|
||||
|
||||
if settings.resolver.torch_backend.is_some() {
|
||||
warn_user_once!(
|
||||
"The `--torch-backend` option is experimental and may change without warning."
|
||||
);
|
||||
}
|
||||
|
||||
// Read from the `.env` file, if necessary.
|
||||
if !no_env_file {
|
||||
for env_file_path in env_file.iter().rev().map(PathBuf::as_path) {
|
||||
|
|
|
|||
|
|
@ -840,7 +840,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
.combine(Refresh::from(args.settings.upgrade.clone())),
|
||||
);
|
||||
|
||||
Box::pin(commands::pip_install(
|
||||
commands::pip_install(
|
||||
&requirements,
|
||||
&constraints,
|
||||
&overrides,
|
||||
|
|
@ -892,7 +892,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
args.dry_run,
|
||||
printer,
|
||||
globals.preview,
|
||||
))
|
||||
)
|
||||
.await
|
||||
}
|
||||
Commands::Pip(PipNamespace {
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ impl InitSettings {
|
|||
no_description,
|
||||
vcs: vcs.or(bare.then_some(VersionControlSystem::None)),
|
||||
build_backend,
|
||||
no_readme,
|
||||
no_readme: no_readme || bare,
|
||||
author_from,
|
||||
pin_python: flag(pin_python, no_pin_python, "pin-python").unwrap_or(!bare),
|
||||
no_workspace,
|
||||
|
|
@ -586,7 +586,6 @@ impl ToolRunSettings {
|
|||
lfs,
|
||||
python,
|
||||
python_platform,
|
||||
torch_backend,
|
||||
generate_shell_completion: _,
|
||||
} = args;
|
||||
|
||||
|
|
@ -616,24 +615,21 @@ impl ToolRunSettings {
|
|||
}
|
||||
}
|
||||
|
||||
let filesystem_options = filesystem.map(FilesystemOptions::into_options);
|
||||
|
||||
let options =
|
||||
resolver_installer_options(installer, build).combine(ResolverInstallerOptions::from(
|
||||
filesystem_options
|
||||
.as_ref()
|
||||
.map(|options| options.top_level.clone())
|
||||
filesystem
|
||||
.clone()
|
||||
.map(FilesystemOptions::into_options)
|
||||
.map(|options| options.top_level)
|
||||
.unwrap_or_default(),
|
||||
));
|
||||
|
||||
let filesystem_install_mirrors = filesystem_options
|
||||
.map(|options| options.install_mirrors.clone())
|
||||
let filesystem_install_mirrors = filesystem
|
||||
.map(FilesystemOptions::into_options)
|
||||
.map(|options| options.install_mirrors)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut settings = ResolverInstallerSettings::from(options.clone());
|
||||
if torch_backend.is_some() {
|
||||
settings.resolver.torch_backend = torch_backend;
|
||||
}
|
||||
let settings = ResolverInstallerSettings::from(options.clone());
|
||||
let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
|
||||
|
||||
Self {
|
||||
|
|
@ -731,27 +727,23 @@ impl ToolInstallSettings {
|
|||
refresh,
|
||||
python,
|
||||
python_platform,
|
||||
torch_backend,
|
||||
} = args;
|
||||
|
||||
let filesystem_options = filesystem.map(FilesystemOptions::into_options);
|
||||
|
||||
let options =
|
||||
resolver_installer_options(installer, build).combine(ResolverInstallerOptions::from(
|
||||
filesystem_options
|
||||
.as_ref()
|
||||
.map(|options| options.top_level.clone())
|
||||
filesystem
|
||||
.clone()
|
||||
.map(FilesystemOptions::into_options)
|
||||
.map(|options| options.top_level)
|
||||
.unwrap_or_default(),
|
||||
));
|
||||
|
||||
let filesystem_install_mirrors = filesystem_options
|
||||
.map(|options| options.install_mirrors.clone())
|
||||
let filesystem_install_mirrors = filesystem
|
||||
.map(FilesystemOptions::into_options)
|
||||
.map(|options| options.install_mirrors)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut settings = ResolverInstallerSettings::from(options.clone());
|
||||
if torch_backend.is_some() {
|
||||
settings.resolver.torch_backend = torch_backend;
|
||||
}
|
||||
let settings = ResolverInstallerSettings::from(options.clone());
|
||||
let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
|
||||
|
||||
Self {
|
||||
|
|
@ -3207,7 +3199,6 @@ pub(crate) struct ResolverSettings {
|
|||
pub(crate) prerelease: PrereleaseMode,
|
||||
pub(crate) resolution: ResolutionMode,
|
||||
pub(crate) sources: SourceStrategy,
|
||||
pub(crate) torch_backend: Option<TorchMode>,
|
||||
pub(crate) upgrade: Upgrade,
|
||||
}
|
||||
|
||||
|
|
@ -3262,7 +3253,6 @@ impl From<ResolverOptions> for ResolverSettings {
|
|||
extra_build_variables: value.extra_build_variables.unwrap_or_default(),
|
||||
exclude_newer: value.exclude_newer,
|
||||
link_mode: value.link_mode.unwrap_or_default(),
|
||||
torch_backend: value.torch_backend,
|
||||
sources: SourceStrategy::from_args(value.no_sources.unwrap_or_default()),
|
||||
upgrade: value.upgrade.unwrap_or_default(),
|
||||
build_options: BuildOptions::new(
|
||||
|
|
@ -3354,7 +3344,6 @@ impl From<ResolverInstallerOptions> for ResolverInstallerSettings {
|
|||
prerelease: value.prerelease.unwrap_or_default(),
|
||||
resolution: value.resolution.unwrap_or_default(),
|
||||
sources: SourceStrategy::from_args(value.no_sources.unwrap_or_default()),
|
||||
torch_backend: value.torch_backend,
|
||||
upgrade: value.upgrade.unwrap_or_default(),
|
||||
},
|
||||
compile_bytecode: value.compile_bytecode.unwrap_or_default(),
|
||||
|
|
|
|||
|
|
@ -700,42 +700,6 @@ fn init_script() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Using `--bare` with `--script` omits the default script content.
|
||||
#[test]
|
||||
fn init_script_bare() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let child = context.temp_dir.child("foo");
|
||||
child.create_dir_all()?;
|
||||
|
||||
let script = child.join("main.py");
|
||||
|
||||
uv_snapshot!(context.filters(), context.init().current_dir(&child).arg("--script").arg("--bare").arg("main.py"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Initialized script at `main.py`
|
||||
"###);
|
||||
|
||||
let script = fs_err::read_to_string(&script)?;
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
script, @r###"
|
||||
# /// script
|
||||
# requires-python = ">=3.12"
|
||||
# dependencies = []
|
||||
# ///
|
||||
"###
|
||||
);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Ensure python versions passed as arguments are present in file metadata
|
||||
#[test]
|
||||
fn init_script_python_version() -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -8231,6 +8231,7 @@ fn lock_invalid_hash() -> Result<()> {
|
|||
╰─▶ Hash mismatch for `idna==3.6`
|
||||
|
||||
Expected:
|
||||
sha256:aecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca
|
||||
sha256:d05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
|
||||
|
||||
Computed:
|
||||
|
|
@ -8241,225 +8242,6 @@ fn lock_invalid_hash() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensure that we can install from a lockfile when the index switches hash algorithms.
|
||||
/// First lock and sync with SHA256 hashes, then switch to SHA512 and lock/sync again
|
||||
/// without clearing the cache.
|
||||
#[test]
|
||||
fn lock_mixed_hashes() -> Result<()> {
|
||||
let context = TestContext::new("3.13");
|
||||
|
||||
let root = context.temp_dir.child("simple-html");
|
||||
fs_err::create_dir_all(&root)?;
|
||||
|
||||
let basic_package = root.child("basic-package");
|
||||
fs_err::create_dir_all(&basic_package)?;
|
||||
|
||||
// Copy the wheel and sdist from `test/links`.
|
||||
let wheel = basic_package.child("basic_package-0.1.0-py3-none-any.whl");
|
||||
fs_err::copy(
|
||||
context
|
||||
.workspace_root
|
||||
.join("test/links/basic_package-0.1.0-py3-none-any.whl"),
|
||||
&wheel,
|
||||
)?;
|
||||
|
||||
let sdist = basic_package.child("basic_package-0.1.0.tar.gz");
|
||||
fs_err::copy(
|
||||
context
|
||||
.workspace_root
|
||||
.join("test/links/basic_package-0.1.0.tar.gz"),
|
||||
&sdist,
|
||||
)?;
|
||||
|
||||
// Phase 1: Create an `index.html` with SHA256 hashes for both wheel and sdist.
|
||||
let index = basic_package.child("index.html");
|
||||
index.write_str(&formatdoc! {r#"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="pypi:repository-version" content="1.1" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Links for basic-package</h1>
|
||||
<a
|
||||
href="{}#sha256=7b6229db79b5800e4e98a351b5628c1c8a944533a2d428aeeaa7275a30d4ea82"
|
||||
>
|
||||
basic_package-0.1.0-py3-none-any.whl
|
||||
</a>
|
||||
<a
|
||||
href="{}#sha256=af478ff91ec60856c99a540b8df13d756513bebb65bc301fb27e0d1f974532b4"
|
||||
>
|
||||
basic_package-0.1.0.tar.gz
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
||||
"#,
|
||||
Url::from_file_path(&wheel).unwrap().as_str(),
|
||||
Url::from_file_path(&sdist).unwrap().as_str(),
|
||||
})?;
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(&formatdoc! { r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = ["basic-package"]
|
||||
|
||||
[tool.uv]
|
||||
extra-index-url = ["{}"]
|
||||
"#,
|
||||
Url::from_file_path(&root).unwrap().as_str()
|
||||
})?;
|
||||
|
||||
let index_url = Url::from_file_path(&root).unwrap().to_string();
|
||||
let filters = [(index_url.as_str(), "file://[TMP]")]
|
||||
.into_iter()
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Lock with SHA256 hashes.
|
||||
uv_snapshot!(context.filters(), context.lock().env_remove(EnvVars::UV_EXCLUDE_NEWER), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
");
|
||||
|
||||
let lock = context.read("uv.lock");
|
||||
|
||||
insta::with_settings!({
|
||||
filters => filters.clone(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
lock, @r#"
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "basic-package"
|
||||
version = "0.1.0"
|
||||
source = { registry = "simple-html" }
|
||||
sdist = { path = "basic-package/basic_package-0.1.0.tar.gz", hash = "sha256:af478ff91ec60856c99a540b8df13d756513bebb65bc301fb27e0d1f974532b4" }
|
||||
wheels = [
|
||||
{ path = "basic-package/basic_package-0.1.0-py3-none-any.whl", hash = "sha256:7b6229db79b5800e4e98a351b5628c1c8a944533a2d428aeeaa7275a30d4ea82" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "basic-package" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "basic-package" }]
|
||||
"#
|
||||
);
|
||||
});
|
||||
|
||||
// Sync with SHA256 hashes to populate the cache.
|
||||
uv_snapshot!(filters.clone(), context.sync().arg("--frozen"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ basic-package==0.1.0
|
||||
");
|
||||
|
||||
// Phase 2: Update the index to use a SHA512 hash for the wheel instead.
|
||||
index.write_str(&formatdoc! {r#"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="pypi:repository-version" content="1.1" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Links for basic-package</h1>
|
||||
<a
|
||||
href="{}#sha512=765bde25938af485e492e25ee0e8cde262462565122c1301213a69bf9ceb2008e3997b652a604092a238c4b1a6a334e697ff3cee3c22f9a617cb14f34e26ef17"
|
||||
>
|
||||
basic_package-0.1.0-py3-none-any.whl
|
||||
</a>
|
||||
<a
|
||||
href="{}#sha256=af478ff91ec60856c99a540b8df13d756513bebb65bc301fb27e0d1f974532b4"
|
||||
>
|
||||
basic_package-0.1.0.tar.gz
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
||||
"#,
|
||||
Url::from_file_path(&wheel).unwrap().as_str(),
|
||||
Url::from_file_path(&sdist).unwrap().as_str(),
|
||||
})?;
|
||||
|
||||
// Lock again with `--refresh` to pick up the SHA512 hash from the updated index.
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--refresh").env_remove(EnvVars::UV_EXCLUDE_NEWER), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
");
|
||||
|
||||
let lock = context.read("uv.lock");
|
||||
|
||||
insta::with_settings!({
|
||||
filters => filters.clone(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
lock, @r#"
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "basic-package"
|
||||
version = "0.1.0"
|
||||
source = { registry = "simple-html" }
|
||||
sdist = { path = "basic-package/basic_package-0.1.0.tar.gz", hash = "sha256:af478ff91ec60856c99a540b8df13d756513bebb65bc301fb27e0d1f974532b4" }
|
||||
wheels = [
|
||||
{ path = "basic-package/basic_package-0.1.0-py3-none-any.whl", hash = "sha512:765bde25938af485e492e25ee0e8cde262462565122c1301213a69bf9ceb2008e3997b652a604092a238c4b1a6a334e697ff3cee3c22f9a617cb14f34e26ef17" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "basic-package" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "basic-package" }]
|
||||
"#
|
||||
);
|
||||
});
|
||||
|
||||
// Reinstalling should re-compute the hash for the `basic-package` wheel to reflect SHA512.
|
||||
uv_snapshot!(filters, context.sync().arg("--frozen").arg("--reinstall"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Prepared 1 package in [TIME]
|
||||
Uninstalled 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
~ basic-package==0.1.0
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Vary the `--resolution-mode`, and ensure that the lockfile is updated.
|
||||
#[test]
|
||||
fn lock_resolution_mode() -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -3565,7 +3565,6 @@ fn resolve_tool() -> anyhow::Result<()> {
|
|||
link_mode: Some(
|
||||
Clone,
|
||||
),
|
||||
torch_backend: None,
|
||||
compile_bytecode: None,
|
||||
no_sources: None,
|
||||
upgrade: None,
|
||||
|
|
@ -3574,6 +3573,7 @@ fn resolve_tool() -> anyhow::Result<()> {
|
|||
no_build_package: None,
|
||||
no_binary: None,
|
||||
no_binary_package: None,
|
||||
torch_backend: None,
|
||||
},
|
||||
settings: ResolverInstallerSettings {
|
||||
resolver: ResolverSettings {
|
||||
|
|
@ -3615,7 +3615,6 @@ fn resolve_tool() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: LowestDirect,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: None,
|
||||
},
|
||||
compile_bytecode: false,
|
||||
|
|
@ -7913,7 +7912,6 @@ fn preview_features() {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: None,
|
||||
},
|
||||
compile_bytecode: false,
|
||||
|
|
@ -8028,7 +8026,6 @@ fn preview_features() {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: None,
|
||||
},
|
||||
compile_bytecode: false,
|
||||
|
|
@ -8143,7 +8140,6 @@ fn preview_features() {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: None,
|
||||
},
|
||||
compile_bytecode: false,
|
||||
|
|
@ -8258,7 +8254,6 @@ fn preview_features() {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: None,
|
||||
},
|
||||
compile_bytecode: false,
|
||||
|
|
@ -8373,7 +8368,6 @@ fn preview_features() {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: None,
|
||||
},
|
||||
compile_bytecode: false,
|
||||
|
|
@ -8490,7 +8484,6 @@ fn preview_features() {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: None,
|
||||
},
|
||||
compile_bytecode: false,
|
||||
|
|
@ -9745,7 +9738,6 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: None,
|
||||
},
|
||||
}
|
||||
|
|
@ -9865,7 +9857,6 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: Packages(
|
||||
{
|
||||
PackageName(
|
||||
|
|
@ -10008,7 +9999,6 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: All,
|
||||
},
|
||||
}
|
||||
|
|
@ -10126,7 +10116,6 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: None,
|
||||
},
|
||||
}
|
||||
|
|
@ -10234,7 +10223,6 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: All,
|
||||
},
|
||||
}
|
||||
|
|
@ -10343,7 +10331,6 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
torch_backend: None,
|
||||
upgrade: Packages(
|
||||
{
|
||||
PackageName(
|
||||
|
|
|
|||
Loading…
Reference in New Issue