mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-29 13:34:47 +00:00
Allow round-trip via freeze
command (#1936)
## Summary We're printing the `Display` representation of `InstalledDist`, which isn't guaranteed to be (and in fact isn't) a valid PEP 508 requirement, making it impossible to use the `freeze` output as an input to an install. Closes https://github.com/astral-sh/uv/issues/1931.
This commit is contained in:
parent
8ff6182815
commit
ca489ac3bb
2 changed files with 60 additions and 31 deletions
|
@ -6,7 +6,7 @@ use itertools::Itertools;
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use distribution_types::Name;
|
use distribution_types::{InstalledDist, Name};
|
||||||
use platform_host::Platform;
|
use platform_host::Platform;
|
||||||
use uv_cache::Cache;
|
use uv_cache::Cache;
|
||||||
use uv_fs::Normalized;
|
use uv_fs::Normalized;
|
||||||
|
@ -34,7 +34,18 @@ pub(crate) fn pip_freeze(cache: &Cache, strict: bool, mut printer: Printer) -> R
|
||||||
.iter()
|
.iter()
|
||||||
.sorted_unstable_by(|a, b| a.name().cmp(b.name()).then(a.version().cmp(b.version())))
|
.sorted_unstable_by(|a, b| a.name().cmp(b.name()).then(a.version().cmp(b.version())))
|
||||||
{
|
{
|
||||||
println!("{dist}");
|
match dist {
|
||||||
|
InstalledDist::Registry(dist) => {
|
||||||
|
println!("{}=={}", dist.name().bold(), dist.version);
|
||||||
|
}
|
||||||
|
InstalledDist::Url(dist) => {
|
||||||
|
if dist.editable {
|
||||||
|
println!("-e {}", dist.url);
|
||||||
|
} else {
|
||||||
|
println!("{} @ {}", dist.name().bold(), dist.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate that the environment is consistent.
|
// Validate that the environment is consistent.
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use assert_cmd::prelude::*;
|
||||||
use assert_fs::prelude::*;
|
use assert_fs::prelude::*;
|
||||||
|
|
||||||
use crate::common::{get_bin, uv_snapshot, TestContext};
|
use crate::common::{get_bin, uv_snapshot, TestContext};
|
||||||
|
@ -22,19 +23,6 @@ fn command(context: &TestContext) -> Command {
|
||||||
command
|
command
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `pip sync` command with options shared across scenarios.
|
|
||||||
fn sync_command(context: &TestContext) -> Command {
|
|
||||||
let mut command = Command::new(get_bin());
|
|
||||||
command
|
|
||||||
.arg("pip")
|
|
||||||
.arg("sync")
|
|
||||||
.arg("--cache-dir")
|
|
||||||
.arg(context.cache_dir.path())
|
|
||||||
.env("VIRTUAL_ENV", context.venv.as_os_str())
|
|
||||||
.current_dir(&context.temp_dir);
|
|
||||||
command
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List multiple installed packages in a virtual environment.
|
/// List multiple installed packages in a virtual environment.
|
||||||
#[test]
|
#[test]
|
||||||
fn freeze_many() -> Result<()> {
|
fn freeze_many() -> Result<()> {
|
||||||
|
@ -44,20 +32,15 @@ fn freeze_many() -> Result<()> {
|
||||||
requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?;
|
requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?;
|
||||||
|
|
||||||
// Run `pip sync`.
|
// Run `pip sync`.
|
||||||
uv_snapshot!(sync_command(&context)
|
Command::new(get_bin())
|
||||||
.arg("requirements.txt"), @r###"
|
.arg("pip")
|
||||||
success: true
|
.arg("sync")
|
||||||
exit_code: 0
|
.arg(requirements_txt.path())
|
||||||
----- stdout -----
|
.arg("--cache-dir")
|
||||||
|
.arg(context.cache_dir.path())
|
||||||
----- stderr -----
|
.env("VIRTUAL_ENV", context.venv.as_os_str())
|
||||||
Resolved 2 packages in [TIME]
|
.assert()
|
||||||
Downloaded 2 packages in [TIME]
|
.success();
|
||||||
Installed 2 packages in [TIME]
|
|
||||||
+ markupsafe==2.1.3
|
|
||||||
+ tomli==2.0.1
|
|
||||||
"###
|
|
||||||
);
|
|
||||||
|
|
||||||
// Run `pip freeze`.
|
// Run `pip freeze`.
|
||||||
uv_snapshot!(command(&context)
|
uv_snapshot!(command(&context)
|
||||||
|
@ -79,8 +62,6 @@ fn freeze_many() -> Result<()> {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn freeze_duplicate() -> Result<()> {
|
fn freeze_duplicate() -> Result<()> {
|
||||||
use assert_cmd::assert::OutputAssertExt;
|
|
||||||
|
|
||||||
use crate::common::{copy_dir_all, INSTA_FILTERS};
|
use crate::common::{copy_dir_all, INSTA_FILTERS};
|
||||||
|
|
||||||
// Sync a version of `pip` into a virtual environment.
|
// Sync a version of `pip` into a virtual environment.
|
||||||
|
@ -157,3 +138,40 @@ fn freeze_duplicate() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List a direct URL package in a virtual environment.
|
||||||
|
#[test]
|
||||||
|
fn freeze_url() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
let requirements_txt = context.temp_dir.child("requirements.txt");
|
||||||
|
requirements_txt.write_str("anyio\niniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl")?;
|
||||||
|
|
||||||
|
// Run `pip sync`.
|
||||||
|
Command::new(get_bin())
|
||||||
|
.arg("pip")
|
||||||
|
.arg("sync")
|
||||||
|
.arg(requirements_txt.path())
|
||||||
|
.arg("--cache-dir")
|
||||||
|
.arg(context.cache_dir.path())
|
||||||
|
.env("VIRTUAL_ENV", context.venv.as_os_str())
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
// Run `pip freeze`.
|
||||||
|
uv_snapshot!(command(&context)
|
||||||
|
.arg("--strict"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
anyio==4.3.0
|
||||||
|
iniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
warning: The package `anyio` requires `idna >=2.8`, but it's not installed.
|
||||||
|
warning: The package `anyio` requires `sniffio >=1.1`, but it's not installed.
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue