Allow --editable to override editable = false annotations (#15712)
## Summary We support `--no-editable` on the CLI, but now that workspace members and path dependencies can be marked as `editable = false`, I think it makes sense for `--editable` to override that.
This commit is contained in:
@@ -3155,9 +3155,14 @@ pub struct RunArgs {
|
||||
#[arg(long, conflicts_with_all = ["group", "all_groups", "no_dev"])]
|
||||
pub only_dev: bool,
|
||||
|
||||
/// Install any non-editable dependencies, including the project and any workspace members, as
|
||||
/// editable.
|
||||
#[arg(long, overrides_with = "no_editable", hide = true)]
|
||||
pub editable: bool,
|
||||
|
||||
/// Install any editable dependencies, including the project and any workspace members, as
|
||||
/// non-editable.
|
||||
#[arg(long, value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_NO_EDITABLE)]
|
||||
#[arg(long, overrides_with = "editable", value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_NO_EDITABLE)]
|
||||
pub no_editable: bool,
|
||||
|
||||
/// Do not remove extraneous packages present in the environment.
|
||||
@@ -3463,9 +3468,14 @@ pub struct SyncArgs {
|
||||
#[arg(long, conflicts_with_all = ["only_group", "only_dev"])]
|
||||
pub all_groups: bool,
|
||||
|
||||
/// Install any non-editable dependencies, including the project and any workspace members, as
|
||||
/// editable.
|
||||
#[arg(long, overrides_with = "no_editable", hide = true)]
|
||||
pub editable: bool,
|
||||
|
||||
/// Install any editable dependencies, including the project and any workspace members, as
|
||||
/// non-editable.
|
||||
#[arg(long, value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_NO_EDITABLE)]
|
||||
#[arg(long, overrides_with = "editable", value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_NO_EDITABLE)]
|
||||
pub no_editable: bool,
|
||||
|
||||
/// Do not remove extraneous packages present in the environment.
|
||||
@@ -4307,9 +4317,14 @@ pub struct ExportArgs {
|
||||
#[arg(long, overrides_with("no_header"), hide = true)]
|
||||
pub header: bool,
|
||||
|
||||
/// Export any non-editable dependencies, including the project and any workspace members, as
|
||||
/// editable.
|
||||
#[arg(long, overrides_with = "no_editable", hide = true)]
|
||||
pub editable: bool,
|
||||
|
||||
/// Export any editable dependencies, including the project and any workspace members, as
|
||||
/// non-editable.
|
||||
#[arg(long, value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_NO_EDITABLE)]
|
||||
#[arg(long, overrides_with = "editable", value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_NO_EDITABLE)]
|
||||
pub no_editable: bool,
|
||||
|
||||
/// Include hashes for all dependencies.
|
||||
|
||||
@@ -5,13 +5,12 @@ pub enum EditableMode {
|
||||
NonEditable,
|
||||
}
|
||||
|
||||
impl EditableMode {
|
||||
/// Determine the editable mode based on the command-line arguments.
|
||||
pub fn from_args(no_editable: bool) -> Self {
|
||||
if no_editable {
|
||||
Self::NonEditable
|
||||
} else {
|
||||
impl From<bool> for EditableMode {
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
Self::Editable
|
||||
} else {
|
||||
Self::NonEditable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,7 +620,7 @@ impl<'lock> PylockToml {
|
||||
extras: &ExtrasSpecificationWithDefaults,
|
||||
dev: &DependencyGroupsWithDefaults,
|
||||
annotate: bool,
|
||||
editable: EditableMode,
|
||||
editable: Option<EditableMode>,
|
||||
install_options: &'lock InstallOptions,
|
||||
) -> Result<Self, PylockTomlErrorKind> {
|
||||
// Extract the packages from the lock file.
|
||||
@@ -736,8 +736,9 @@ impl<'lock> PylockToml {
|
||||
.into_boxed_path(),
|
||||
),
|
||||
editable: match editable {
|
||||
EditableMode::NonEditable => None,
|
||||
EditableMode::Editable => sdist.editable,
|
||||
None => sdist.editable,
|
||||
Some(EditableMode::NonEditable) => None,
|
||||
Some(EditableMode::Editable) => Some(true),
|
||||
},
|
||||
subdirectory: None,
|
||||
}),
|
||||
|
||||
@@ -24,7 +24,7 @@ use crate::{Installable, LockError};
|
||||
pub struct RequirementsTxtExport<'lock> {
|
||||
nodes: Vec<ExportableRequirement<'lock>>,
|
||||
hashes: bool,
|
||||
editable: EditableMode,
|
||||
editable: Option<EditableMode>,
|
||||
}
|
||||
|
||||
impl<'lock> RequirementsTxtExport<'lock> {
|
||||
@@ -34,7 +34,7 @@ impl<'lock> RequirementsTxtExport<'lock> {
|
||||
extras: &ExtrasSpecificationWithDefaults,
|
||||
dev: &DependencyGroupsWithDefaults,
|
||||
annotate: bool,
|
||||
editable: EditableMode,
|
||||
editable: Option<EditableMode>,
|
||||
hashes: bool,
|
||||
install_options: &'lock InstallOptions,
|
||||
) -> Result<Self, LockError> {
|
||||
@@ -129,10 +129,10 @@ impl std::fmt::Display for RequirementsTxtExport<'_> {
|
||||
}
|
||||
}
|
||||
Source::Editable(path) => match self.editable {
|
||||
EditableMode::Editable => {
|
||||
None | Some(EditableMode::Editable) => {
|
||||
write!(f, "-e {}", anchor(path).portable_display())?;
|
||||
}
|
||||
EditableMode::NonEditable => {
|
||||
Some(EditableMode::NonEditable) => {
|
||||
if path.is_absolute() {
|
||||
write!(
|
||||
f,
|
||||
|
||||
@@ -18,8 +18,7 @@ use uv_cache_key::RepositoryUrl;
|
||||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
Concurrency, Constraints, DependencyGroups, DependencyGroupsWithDefaults, DevMode, DryRun,
|
||||
EditableMode, ExtrasSpecification, ExtrasSpecificationWithDefaults, InstallOptions,
|
||||
SourceStrategy,
|
||||
ExtrasSpecification, ExtrasSpecificationWithDefaults, InstallOptions, SourceStrategy,
|
||||
};
|
||||
use uv_dispatch::BuildDispatch;
|
||||
use uv_distribution::{DistributionDatabase, LoweredExtraBuildDependencies};
|
||||
@@ -1149,7 +1148,7 @@ async fn lock_and_sync(
|
||||
venv,
|
||||
extras,
|
||||
groups,
|
||||
EditableMode::Editable,
|
||||
None,
|
||||
InstallOptions::new(
|
||||
no_install_project,
|
||||
no_install_workspace,
|
||||
|
||||
@@ -64,7 +64,7 @@ pub(crate) async fn export(
|
||||
output_file: Option<PathBuf>,
|
||||
extras: ExtrasSpecification,
|
||||
groups: DependencyGroups,
|
||||
editable: EditableMode,
|
||||
editable: Option<EditableMode>,
|
||||
locked: bool,
|
||||
frozen: bool,
|
||||
include_annotations: bool,
|
||||
|
||||
@@ -10,7 +10,7 @@ use tracing::{debug, warn};
|
||||
use uv_cache::Cache;
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::{
|
||||
Concurrency, DependencyGroups, DryRun, EditableMode, ExtrasSpecification, InstallOptions,
|
||||
Concurrency, DependencyGroups, DryRun, ExtrasSpecification, InstallOptions,
|
||||
};
|
||||
use uv_fs::Simplified;
|
||||
use uv_normalize::PackageName;
|
||||
@@ -355,7 +355,7 @@ pub(crate) async fn remove(
|
||||
venv,
|
||||
&extras,
|
||||
&groups,
|
||||
EditableMode::Editable,
|
||||
None,
|
||||
InstallOptions::default(),
|
||||
Modifications::Exact,
|
||||
None,
|
||||
|
||||
@@ -93,7 +93,7 @@ pub(crate) async fn run(
|
||||
no_config: bool,
|
||||
extras: ExtrasSpecification,
|
||||
groups: DependencyGroups,
|
||||
editable: EditableMode,
|
||||
editable: Option<EditableMode>,
|
||||
modifications: Modifications,
|
||||
python: Option<String>,
|
||||
python_platform: Option<TargetTriple>,
|
||||
|
||||
@@ -64,7 +64,7 @@ pub(crate) async fn sync(
|
||||
package: Option<PackageName>,
|
||||
extras: ExtrasSpecification,
|
||||
groups: DependencyGroups,
|
||||
editable: EditableMode,
|
||||
editable: Option<EditableMode>,
|
||||
install_options: InstallOptions,
|
||||
modifications: Modifications,
|
||||
python: Option<String>,
|
||||
@@ -559,7 +559,7 @@ pub(super) async fn do_sync(
|
||||
venv: &PythonEnvironment,
|
||||
extras: &ExtrasSpecificationWithDefaults,
|
||||
groups: &DependencyGroupsWithDefaults,
|
||||
editable: EditableMode,
|
||||
editable: Option<EditableMode>,
|
||||
install_options: InstallOptions,
|
||||
modifications: Modifications,
|
||||
python_platform: Option<&TargetTriple>,
|
||||
@@ -826,20 +826,48 @@ fn apply_no_virtual_project(resolution: Resolution) -> Resolution {
|
||||
}
|
||||
|
||||
/// If necessary, convert any editable requirements to non-editable.
|
||||
fn apply_editable_mode(resolution: Resolution, editable: EditableMode) -> Resolution {
|
||||
fn apply_editable_mode(resolution: Resolution, editable: Option<EditableMode>) -> Resolution {
|
||||
match editable {
|
||||
// No modifications are necessary for editable mode; retain any editable distributions.
|
||||
EditableMode::Editable => resolution,
|
||||
None => resolution,
|
||||
|
||||
// Filter out any editable distributions.
|
||||
EditableMode::NonEditable => resolution.map(|dist| {
|
||||
// Filter out any non-editable distributions.
|
||||
Some(EditableMode::Editable) => resolution.map(|dist| {
|
||||
let ResolvedDist::Installable { dist, version } = dist else {
|
||||
return None;
|
||||
};
|
||||
let Dist::Source(SourceDist::Directory(DirectorySourceDist {
|
||||
name,
|
||||
install_path,
|
||||
editable: Some(true),
|
||||
editable: None | Some(false),
|
||||
r#virtual,
|
||||
url,
|
||||
})) = dist.as_ref()
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(ResolvedDist::Installable {
|
||||
dist: Arc::new(Dist::Source(SourceDist::Directory(DirectorySourceDist {
|
||||
name: name.clone(),
|
||||
install_path: install_path.clone(),
|
||||
editable: Some(true),
|
||||
r#virtual: *r#virtual,
|
||||
url: url.clone(),
|
||||
}))),
|
||||
version: version.clone(),
|
||||
})
|
||||
}),
|
||||
|
||||
// Filter out any editable distributions.
|
||||
Some(EditableMode::NonEditable) => resolution.map(|dist| {
|
||||
let ResolvedDist::Installable { dist, version } = dist else {
|
||||
return None;
|
||||
};
|
||||
let Dist::Source(SourceDist::Directory(DirectorySourceDist {
|
||||
name,
|
||||
install_path,
|
||||
editable: None | Some(true),
|
||||
r#virtual,
|
||||
url,
|
||||
})) = dist.as_ref()
|
||||
|
||||
@@ -11,8 +11,8 @@ use uv_cli::version::VersionInfo;
|
||||
use uv_cli::{VersionBump, VersionFormat};
|
||||
use uv_client::BaseClientBuilder;
|
||||
use uv_configuration::{
|
||||
Concurrency, DependencyGroups, DependencyGroupsWithDefaults, DryRun, EditableMode,
|
||||
ExtrasSpecification, InstallOptions,
|
||||
Concurrency, DependencyGroups, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification,
|
||||
InstallOptions,
|
||||
};
|
||||
use uv_fs::Simplified;
|
||||
use uv_normalize::DefaultExtras;
|
||||
@@ -640,7 +640,7 @@ async fn lock_and_sync(
|
||||
venv,
|
||||
&extras,
|
||||
&groups,
|
||||
EditableMode::Editable,
|
||||
None,
|
||||
install_options,
|
||||
Modifications::Sufficient,
|
||||
None,
|
||||
|
||||
@@ -326,7 +326,7 @@ pub(crate) struct RunSettings {
|
||||
pub(crate) frozen: bool,
|
||||
pub(crate) extras: ExtrasSpecification,
|
||||
pub(crate) groups: DependencyGroups,
|
||||
pub(crate) editable: EditableMode,
|
||||
pub(crate) editable: Option<EditableMode>,
|
||||
pub(crate) modifications: Modifications,
|
||||
pub(crate) with: Vec<String>,
|
||||
pub(crate) with_editable: Vec<String>,
|
||||
@@ -372,6 +372,7 @@ impl RunSettings {
|
||||
all_groups,
|
||||
module: _,
|
||||
only_dev,
|
||||
editable,
|
||||
no_editable,
|
||||
inexact,
|
||||
exact,
|
||||
@@ -428,7 +429,7 @@ impl RunSettings {
|
||||
only_group,
|
||||
all_groups,
|
||||
),
|
||||
editable: EditableMode::from_args(no_editable),
|
||||
editable: flag(editable, no_editable, "editable").map(EditableMode::from),
|
||||
modifications: if flag(exact, inexact, "inexact").unwrap_or(false) {
|
||||
Modifications::Exact
|
||||
} else {
|
||||
@@ -1200,7 +1201,7 @@ pub(crate) struct SyncSettings {
|
||||
pub(crate) active: Option<bool>,
|
||||
pub(crate) extras: ExtrasSpecification,
|
||||
pub(crate) groups: DependencyGroups,
|
||||
pub(crate) editable: EditableMode,
|
||||
pub(crate) editable: Option<EditableMode>,
|
||||
pub(crate) install_options: InstallOptions,
|
||||
pub(crate) modifications: Modifications,
|
||||
pub(crate) all_packages: bool,
|
||||
@@ -1230,6 +1231,7 @@ impl SyncSettings {
|
||||
no_default_groups,
|
||||
only_group,
|
||||
all_groups,
|
||||
editable,
|
||||
no_editable,
|
||||
inexact,
|
||||
exact,
|
||||
@@ -1297,7 +1299,7 @@ impl SyncSettings {
|
||||
only_group,
|
||||
all_groups,
|
||||
),
|
||||
editable: EditableMode::from_args(no_editable),
|
||||
editable: flag(editable, no_editable, "editable").map(EditableMode::from),
|
||||
install_options: InstallOptions::new(
|
||||
no_install_project,
|
||||
no_install_workspace,
|
||||
@@ -1794,7 +1796,7 @@ pub(crate) struct ExportSettings {
|
||||
pub(crate) prune: Vec<PackageName>,
|
||||
pub(crate) extras: ExtrasSpecification,
|
||||
pub(crate) groups: DependencyGroups,
|
||||
pub(crate) editable: EditableMode,
|
||||
pub(crate) editable: Option<EditableMode>,
|
||||
pub(crate) hashes: bool,
|
||||
pub(crate) install_options: InstallOptions,
|
||||
pub(crate) output_file: Option<PathBuf>,
|
||||
@@ -1834,6 +1836,7 @@ impl ExportSettings {
|
||||
no_annotate,
|
||||
header,
|
||||
no_header,
|
||||
editable,
|
||||
no_editable,
|
||||
hashes,
|
||||
no_hashes,
|
||||
@@ -1879,7 +1882,7 @@ impl ExportSettings {
|
||||
only_group,
|
||||
all_groups,
|
||||
),
|
||||
editable: EditableMode::from_args(no_editable),
|
||||
editable: flag(editable, no_editable, "editable").map(EditableMode::from),
|
||||
hashes: flag(hashes, no_hashes, "hashes").unwrap_or(true),
|
||||
install_options: InstallOptions::new(
|
||||
no_emit_project,
|
||||
|
||||
@@ -13743,7 +13743,7 @@ fn toggle_workspace_editable() -> Result<()> {
|
||||
|
||||
let lock = context.read("uv.lock");
|
||||
|
||||
// The child should be editable by default.
|
||||
// Setting `--no-editable` should make the child non-editable.
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
@@ -13796,6 +13796,25 @@ fn toggle_workspace_editable() -> Result<()> {
|
||||
);
|
||||
});
|
||||
|
||||
// Verify that `_child.pth` does not exist in the site-packages directory.
|
||||
assert!(!context.site_packages().join("_child.pth").exists());
|
||||
|
||||
// But `--editable` on the command line should override the lockfile.
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--editable"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 3 packages in [TIME]
|
||||
Uninstalled 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
~ child==0.1.0 (from file://[TEMP_DIR]/child)
|
||||
");
|
||||
|
||||
// Verify that `_child.pth` exists in the site-packages directory.
|
||||
assert!(context.site_packages().join("_child.pth").exists());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user