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 tracing::debug;
|
||||
|
||||
use distribution_types::Name;
|
||||
use distribution_types::{InstalledDist, Name};
|
||||
use platform_host::Platform;
|
||||
use uv_cache::Cache;
|
||||
use uv_fs::Normalized;
|
||||
|
@ -34,7 +34,18 @@ pub(crate) fn pip_freeze(cache: &Cache, strict: bool, mut printer: Printer) -> R
|
|||
.iter()
|
||||
.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.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use std::process::Command;
|
||||
|
||||
use anyhow::Result;
|
||||
use assert_cmd::prelude::*;
|
||||
use assert_fs::prelude::*;
|
||||
|
||||
use crate::common::{get_bin, uv_snapshot, TestContext};
|
||||
|
@ -22,19 +23,6 @@ fn command(context: &TestContext) -> 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.
|
||||
#[test]
|
||||
fn freeze_many() -> Result<()> {
|
||||
|
@ -44,20 +32,15 @@ fn freeze_many() -> Result<()> {
|
|||
requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?;
|
||||
|
||||
// Run `pip sync`.
|
||||
uv_snapshot!(sync_command(&context)
|
||||
.arg("requirements.txt"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
Downloaded 2 packages in [TIME]
|
||||
Installed 2 packages in [TIME]
|
||||
+ markupsafe==2.1.3
|
||||
+ tomli==2.0.1
|
||||
"###
|
||||
);
|
||||
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)
|
||||
|
@ -79,8 +62,6 @@ fn freeze_many() -> Result<()> {
|
|||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn freeze_duplicate() -> Result<()> {
|
||||
use assert_cmd::assert::OutputAssertExt;
|
||||
|
||||
use crate::common::{copy_dir_all, INSTA_FILTERS};
|
||||
|
||||
// Sync a version of `pip` into a virtual environment.
|
||||
|
@ -157,3 +138,40 @@ fn freeze_duplicate() -> Result<()> {
|
|||
|
||||
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