Add some compatibility arguments to `puffin venv` (#1282)

See: https://github.com/astral-sh/puffin/issues/1276.
This commit is contained in:
Charlie Marsh 2024-02-11 22:19:55 -05:00 committed by GitHub
parent 93b7a1140f
commit b386590b3c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 119 additions and 4 deletions

View File

@ -3,6 +3,10 @@ use clap::{Args, ValueEnum};
use puffin_warnings::warn_user;
pub(crate) trait CompatArgs {
fn validate(&self) -> Result<()>;
}
/// Arguments for `pip-compile` compatibility.
///
/// These represent a subset of the `pip-compile` interface that Puffin supports by default.
@ -84,13 +88,13 @@ pub(crate) struct PipCompileCompatArgs {
pip_args: Option<String>,
}
impl PipCompileCompatArgs {
impl CompatArgs for PipCompileCompatArgs {
/// Validate the arguments passed for `pip-compile` compatibility.
///
/// This method will warn when an argument is passed that has no effect but matches Puffin's
/// behavior. If an argument is passed that does _not_ match Puffin's behavior (e.g.,
/// `--no-build-isolation`), this method will return an error.
pub(crate) fn validate(&self) -> Result<()> {
fn validate(&self) -> Result<()> {
if self.allow_unsafe {
warn_user!(
"pip-compile's `--allow-unsafe` has no effect (Puffin can safely pin `pip` and other packages)."
@ -281,13 +285,13 @@ pub(crate) struct PipSyncCompatArgs {
pip_args: Option<String>,
}
impl PipSyncCompatArgs {
impl CompatArgs for PipSyncCompatArgs {
/// Validate the arguments passed for `pip-sync` compatibility.
///
/// This method will warn when an argument is passed that has no effect but matches Puffin's
/// behavior. If an argument is passed that does _not_ match Puffin's behavior, this method will
/// return an error.
pub(crate) fn validate(&self) -> Result<()> {
fn validate(&self) -> Result<()> {
if self.ask {
return Err(anyhow!(
"pip-sync's `--ask` is unsupported (Puffin never asks for confirmation)."
@ -349,3 +353,64 @@ enum AnnotationStyle {
Line,
Split,
}
/// Arguments for `venv` compatibility.
///
/// These represent a subset of the `virtualenv` interface that Puffin supports by default.
#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub(crate) struct VenvCompatArgs {
#[clap(long, hide = true)]
clear: bool,
#[clap(long, hide = true)]
no_seed: bool,
#[clap(long, hide = true)]
no_pip: bool,
#[clap(long, hide = true)]
no_setuptools: bool,
#[clap(long, hide = true)]
no_wheel: bool,
}
impl CompatArgs for VenvCompatArgs {
/// Validate the arguments passed for `venv` compatibility.
///
/// This method will warn when an argument is passed that has no effect but matches Puffin's
/// behavior. If an argument is passed that does _not_ match Puffin's behavior, this method will
/// return an error.
fn validate(&self) -> Result<()> {
if self.clear {
warn_user!(
"virtualenv's `--clear` has no effect (Puffin always clears the virtual environment)."
);
}
if self.no_seed {
warn_user!(
"virtualenv's `--no-seed` has no effect (Puffin omits seed packages by default)."
);
}
if self.no_pip {
warn_user!("virtualenv's `--no-pip` has no effect (Puffin omits `pip` by default).");
}
if self.no_setuptools {
warn_user!(
"virtualenv's `--no-setuptools` has no effect (Puffin omits `setuptools` by default)."
);
}
if self.no_wheel {
warn_user!(
"virtualenv's `--no-wheel` has no effect (Puffin omits `wheel` by default)."
);
}
Ok(())
}
}

View File

@ -21,6 +21,7 @@ use puffin_traits::{NoBuild, PackageNameSpecifier, SetupPyStrategy};
use requirements::ExtrasSpecification;
use crate::commands::{extra_name_with_clap_error, ExitStatus, Upgrade};
use crate::compat::CompatArgs;
use crate::requirements::RequirementsSource;
#[cfg(target_os = "windows")]
@ -625,6 +626,9 @@ struct VenvArgs {
/// format (e.g., `2006-12-02`).
#[arg(long, value_parser = date_or_datetime, hide = true)]
exclude_newer: Option<DateTime<Utc>>,
#[command(flatten)]
compat_args: compat::VenvCompatArgs,
}
#[derive(Args)]
@ -928,6 +932,8 @@ async fn run() -> Result<ExitStatus> {
}) => commands::freeze(&cache, args.strict, printer),
Commands::Clean(args) => commands::clean(&cache, &args.package, printer),
Commands::Venv(args) => {
args.compat_args.validate()?;
let index_locations = IndexLocations::from_args(
args.index_url,
args.extra_index_url,

View File

@ -443,3 +443,47 @@ fn non_empty_dir_exists() -> Result<()> {
Ok(())
}
#[test]
fn virtualenv_compatibility() -> Result<()> {
let temp_dir = assert_fs::TempDir::new()?;
let cache_dir = assert_fs::TempDir::new()?;
let bin = create_bin_with_executables(&temp_dir, &["3.12"]).expect("Failed to create bin dir");
let venv = temp_dir.child(".venv");
// Create a virtual environment at `.venv`, passing the redundant `--clear` flag.
let filter_venv = regex::escape(&venv.normalized_display().to_string());
let filters = &[
(
r"Using Python 3\.\d+\.\d+ interpreter at .+",
"Using Python [VERSION] interpreter at [PATH]",
),
(&filter_venv, "/home/ferris/project/.venv"),
];
puffin_snapshot!(filters, Command::new(get_bin())
.arg("venv")
.arg(venv.as_os_str())
.arg("--clear")
.arg("--python")
.arg("3.12")
.arg("--cache-dir")
.arg(cache_dir.path())
.arg("--exclude-newer")
.arg(EXCLUDE_NEWER)
.env("PUFFIN_TEST_PYTHON_PATH", bin.clone())
.current_dir(&temp_dir), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: virtualenv's `--clear` has no effect (Puffin always clears the virtual environment).
Using Python [VERSION] interpreter at [PATH]
Creating virtualenv at: /home/ferris/project/.venv
"###
);
venv.assert(predicates::path::is_dir());
Ok(())
}