Add --no-sources to avoid reading from tool.uv.sources (#5801)

## Summary

Closes https://github.com/astral-sh/uv/issues/5791.
This commit is contained in:
Charlie Marsh 2024-08-06 10:14:19 -04:00 committed by GitHub
parent 478d32c655
commit 089f50a845
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 455 additions and 40 deletions

View file

@ -84,6 +84,7 @@ mod resolver {
use uv_client::RegistryClient;
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, IndexStrategy, PreviewMode, SetupPyStrategy,
SourceStrategy,
};
use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase;
@ -149,6 +150,7 @@ mod resolver {
let installed_packages = EmptyInstalledPackages;
let interpreter = venv.interpreter();
let python_requirement = PythonRequirement::from_interpreter(interpreter);
let sources = SourceStrategy::default();
let options = OptionsBuilder::new().exclude_newer(exclude_newer).build();
let build_constraints = [];
@ -170,6 +172,7 @@ mod resolver {
LinkMode::default(),
&build_options,
exclude_newer,
sources,
concurrency,
PreviewMode::Disabled,
);

View file

@ -2919,6 +2919,12 @@ pub struct InstallerArgs {
help_heading = "Installer options"
)]
pub no_compile_bytecode: bool,
/// Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
/// standards-compliant, publishable package metadata, as opposed to using any local or Git
/// sources.
#[arg(long)]
pub no_sources: bool,
}
/// Arguments that are used by commands that need to resolve (but not install) packages.
@ -3035,6 +3041,12 @@ pub struct ResolverArgs {
help_heading = "Installer options"
)]
pub link_mode: Option<install_wheel_rs::linker::LinkMode>,
/// Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
/// standards-compliant, publishable package metadata, as opposed to using any local or Git
/// sources.
#[arg(long)]
pub no_sources: bool,
}
/// Arguments that are used by commands that need to resolve and install packages.
@ -3199,6 +3211,12 @@ pub struct ResolverInstallerArgs {
help_heading = "Installer options"
)]
pub no_compile_bytecode: bool,
/// Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
/// standards-compliant, publishable package metadata, as opposed to using any local or Git
/// sources.
#[arg(long)]
pub no_sources: bool,
}
#[derive(Args)]

View file

@ -44,6 +44,7 @@ impl From<ResolverArgs> for PipOptions {
config_setting,
exclude_newer,
link_mode,
no_sources,
} = args;
Self {
@ -61,6 +62,7 @@ impl From<ResolverArgs> for PipOptions {
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
exclude_newer,
link_mode,
no_sources: if no_sources { Some(true) } else { None },
..PipOptions::from(index_args)
}
}
@ -80,6 +82,7 @@ impl From<InstallerArgs> for PipOptions {
link_mode,
compile_bytecode,
no_compile_bytecode,
no_sources,
} = args;
Self {
@ -92,6 +95,7 @@ impl From<InstallerArgs> for PipOptions {
exclude_newer,
link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
no_sources: if no_sources { Some(true) } else { None },
..PipOptions::from(index_args)
}
}
@ -117,6 +121,7 @@ impl From<ResolverInstallerArgs> for PipOptions {
link_mode,
compile_bytecode,
no_compile_bytecode,
no_sources,
} = args;
Self {
@ -137,6 +142,7 @@ impl From<ResolverInstallerArgs> for PipOptions {
exclude_newer,
link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
no_sources: if no_sources { Some(true) } else { None },
..PipOptions::from(index_args)
}
}
@ -181,6 +187,7 @@ pub fn resolver_options(resolver_args: ResolverArgs, build_args: BuildArgs) -> R
config_setting,
exclude_newer,
link_mode,
no_sources,
} = resolver_args;
let BuildArgs {
@ -224,6 +231,7 @@ pub fn resolver_options(resolver_args: ResolverArgs, build_args: BuildArgs) -> R
no_build_package: Some(no_build_package),
no_binary: flag(no_binary, binary),
no_binary_package: Some(no_binary_package),
no_sources: if no_sources { Some(true) } else { None },
}
}
@ -250,6 +258,7 @@ pub fn resolver_installer_options(
link_mode,
compile_bytecode,
no_compile_bytecode,
no_sources,
} = resolver_installer_args;
let BuildArgs {
@ -296,5 +305,6 @@ pub fn resolver_installer_options(
no_build_package: Some(no_build_package),
no_binary: flag(no_binary, binary),
no_binary_package: Some(no_binary_package),
no_sources: if no_sources { Some(true) } else { None },
}
}

View file

@ -9,6 +9,7 @@ pub use name_specifiers::*;
pub use overrides::*;
pub use package_options::*;
pub use preview::*;
pub use sources::*;
pub use target_triple::*;
mod authentication;
@ -22,4 +23,5 @@ mod name_specifiers;
mod overrides;
mod package_options;
mod preview;
mod sources;
mod target_triple;

View file

@ -0,0 +1,19 @@
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum SourceStrategy {
/// Use `tool.uv.sources` when resolving dependencies.
#[default]
Enabled,
/// Ignore `tool.uv.sources` when resolving dependencies.
Disabled,
}
impl SourceStrategy {
/// Return the [`SourceStrategy`] from the command-line arguments, if any.
pub fn from_args(no_sources: bool) -> Self {
if no_sources {
Self::Disabled
} else {
Self::Enabled
}
}
}

View file

@ -12,7 +12,7 @@ use uv_cache::{Cache, CacheArgs};
use uv_client::RegistryClientBuilder;
use uv_configuration::{
BuildKind, BuildOptions, Concurrency, ConfigSettings, IndexStrategy, PreviewMode,
SetupPyStrategy,
SetupPyStrategy, SourceStrategy,
};
use uv_dispatch::BuildDispatch;
use uv_git::GitResolver;
@ -68,6 +68,7 @@ pub(crate) async fn build(args: BuildArgs) -> Result<PathBuf> {
let index_urls = IndexLocations::default();
let index_strategy = IndexStrategy::default();
let setup_py = SetupPyStrategy::default();
let sources = SourceStrategy::default();
let python = PythonEnvironment::find(
&PythonRequest::default(),
EnvironmentPreference::OnlyVirtual,
@ -93,6 +94,7 @@ pub(crate) async fn build(args: BuildArgs) -> Result<PathBuf> {
install_wheel_rs::linker::LinkMode::default(),
&build_options,
exclude_newer,
sources,
concurrency,
PreviewMode::Enabled,
);

View file

@ -17,7 +17,8 @@ use uv_build::{SourceBuild, SourceBuildContext};
use uv_cache::Cache;
use uv_client::RegistryClient;
use uv_configuration::{
BuildKind, BuildOptions, ConfigSettings, Constraints, IndexStrategy, Reinstall, SetupPyStrategy,
BuildKind, BuildOptions, ConfigSettings, Constraints, IndexStrategy, Reinstall,
SetupPyStrategy, SourceStrategy,
};
use uv_configuration::{Concurrency, PreviewMode};
use uv_distribution::DistributionDatabase;
@ -51,6 +52,7 @@ pub struct BuildDispatch<'a> {
exclude_newer: Option<ExcludeNewer>,
source_build_context: SourceBuildContext,
build_extra_env_vars: FxHashMap<OsString, OsString>,
sources: SourceStrategy,
concurrency: Concurrency,
preview_mode: PreviewMode,
}
@ -73,6 +75,7 @@ impl<'a> BuildDispatch<'a> {
link_mode: install_wheel_rs::linker::LinkMode,
build_options: &'a BuildOptions,
exclude_newer: Option<ExcludeNewer>,
sources: SourceStrategy,
concurrency: Concurrency,
preview_mode: PreviewMode,
) -> Self {
@ -93,9 +96,10 @@ impl<'a> BuildDispatch<'a> {
link_mode,
build_options,
exclude_newer,
concurrency,
source_build_context: SourceBuildContext::default(),
build_extra_env_vars: FxHashMap::default(),
sources,
concurrency,
preview_mode,
}
}
@ -131,6 +135,10 @@ impl<'a> BuildContext for BuildDispatch<'a> {
self.build_options
}
fn sources(&self) -> SourceStrategy {
self.sources
}
fn index_locations(&self) -> &IndexLocations {
self.index_locations
}

View file

@ -7,7 +7,7 @@ use crate::metadata::lowering::LoweringError;
pub use crate::metadata::requires_dist::RequiresDist;
use pep440_rs::{Version, VersionSpecifiers};
use pypi_types::{HashDigest, Metadata23};
use uv_configuration::PreviewMode;
use uv_configuration::{PreviewMode, SourceStrategy};
use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_workspace::WorkspaceError;
@ -58,6 +58,7 @@ impl Metadata {
metadata: Metadata23,
install_path: &Path,
lock_path: &Path,
sources: SourceStrategy,
preview_mode: PreviewMode,
) -> Result<Self, MetadataError> {
// Lower the requirements.
@ -74,6 +75,7 @@ impl Metadata {
},
install_path,
lock_path,
sources,
preview_mode,
)
.await?;

View file

@ -1,7 +1,7 @@
use std::collections::BTreeMap;
use std::path::Path;
use uv_configuration::PreviewMode;
use uv_configuration::{PreviewMode, SourceStrategy};
use uv_normalize::{ExtraName, GroupName, PackageName, DEV_DEPENDENCIES};
use uv_workspace::{DiscoveryOptions, ProjectWorkspace};
@ -39,8 +39,11 @@ impl RequiresDist {
metadata: pypi_types::RequiresDist,
install_path: &Path,
lock_path: &Path,
sources: SourceStrategy,
preview_mode: PreviewMode,
) -> Result<Self, MetadataError> {
match sources {
SourceStrategy::Enabled => {
// TODO(konsti): Limit discovery for Git checkouts to Git root.
// TODO(konsti): Cache workspace discovery.
let Some(project_workspace) = ProjectWorkspace::from_maybe_project_root(
@ -55,6 +58,9 @@ impl RequiresDist {
Self::from_project_workspace(metadata, &project_workspace, preview_mode)
}
SourceStrategy::Disabled => Ok(Self::from_metadata23(metadata)),
}
}
fn from_project_workspace(
metadata: pypi_types::RequiresDist,

View file

@ -46,8 +46,8 @@ mod revision;
/// Fetch and build a source distribution from a remote source, or from a local cache.
pub(crate) struct SourceDistributionBuilder<'a, T: BuildContext> {
build_context: &'a T,
reporter: Option<Arc<dyn Reporter>>,
preview_mode: PreviewMode,
reporter: Option<Arc<dyn Reporter>>,
}
/// The name of the file that contains the revision ID for a remote distribution, encoded via `MsgPack`.
@ -64,8 +64,8 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
pub(crate) fn new(build_context: &'a T, preview_mode: PreviewMode) -> Self {
Self {
build_context,
reporter: None,
preview_mode,
reporter: None,
}
}
@ -426,6 +426,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
requires_dist,
project_root,
project_root,
self.build_context.sources(),
self.preview_mode,
)
.await?;
@ -990,6 +991,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
metadata,
resource.install_path.as_ref(),
resource.lock_path.as_ref(),
self.build_context.sources(),
self.preview_mode,
)
.await?,
@ -1015,6 +1017,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
metadata,
resource.install_path.as_ref(),
resource.lock_path.as_ref(),
self.build_context.sources(),
self.preview_mode,
)
.await?,
@ -1047,6 +1050,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
metadata,
resource.install_path.as_ref(),
resource.lock_path.as_ref(),
self.build_context.sources(),
self.preview_mode,
)
.await?,
@ -1257,6 +1261,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
metadata,
fetch.path(),
fetch.path(),
self.build_context.sources(),
self.preview_mode,
)
.await?,
@ -1279,7 +1284,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
.map_err(Error::CacheWrite)?;
return Ok(ArchiveMetadata::from(
Metadata::from_workspace(metadata, fetch.path(), fetch.path(), self.preview_mode)
Metadata::from_workspace(
metadata,
fetch.path(),
fetch.path(),
self.build_context.sources(),
self.preview_mode,
)
.await?,
));
}
@ -1306,7 +1317,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
.map_err(Error::CacheWrite)?;
Ok(ArchiveMetadata::from(
Metadata::from_workspace(metadata, fetch.path(), fetch.path(), self.preview_mode)
Metadata::from_workspace(
metadata,
fetch.path(),
fetch.path(),
self.build_context.sources(),
self.preview_mode,
)
.await?,
))
}

View file

@ -184,6 +184,7 @@ pub struct ResolverOptions {
pub no_build_package: Option<Vec<PackageName>>,
pub no_binary: Option<bool>,
pub no_binary_package: Option<Vec<PackageName>>,
pub no_sources: Option<bool>,
}
/// Shared settings, relevant to all operations that must resolve and install dependencies. The
@ -359,6 +360,17 @@ pub struct ResolverInstallerOptions {
"#
)]
pub compile_bytecode: Option<bool>,
/// Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
/// standards-compliant, publishable package metadata, as opposed to using any local or Git
/// sources.
#[option(
default = "false",
value_type = "bool",
example = r#"
no-sources = true
"#
)]
pub no_sources: Option<bool>,
/// Allow package upgrades, ignoring pinned versions in any existing output file.
#[option(
default = "false",
@ -1036,6 +1048,17 @@ pub struct PipOptions {
"#
)]
pub verify_hashes: Option<bool>,
/// Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
/// standards-compliant, publishable package metadata, as opposed to using any local or Git
/// sources.
#[option(
default = "false",
value_type = "bool",
example = r#"
no-sources = true
"#
)]
pub no_sources: Option<bool>,
/// Allow package upgrades, ignoring pinned versions in any existing output file.
#[option(
default = "false",

View file

@ -7,7 +7,7 @@ use distribution_types::{CachedDist, IndexLocations, InstalledDist, Resolution,
use pep508_rs::PackageName;
use pypi_types::Requirement;
use uv_cache::Cache;
use uv_configuration::{BuildKind, BuildOptions};
use uv_configuration::{BuildKind, BuildOptions, SourceStrategy};
use uv_git::GitResolver;
use uv_python::PythonEnvironment;
@ -63,6 +63,9 @@ pub trait BuildContext {
/// This method exists to avoid fetching source distributions if we know we can't build them.
fn build_options(&self) -> &BuildOptions;
/// Whether to incorporate `tool.uv.sources` when resolving requirements.
fn sources(&self) -> SourceStrategy;
/// The index locations being searched.
fn index_locations(&self) -> &IndexLocations;

View file

@ -16,7 +16,7 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, NoBinary,
NoBuild, PreviewMode, Reinstall, SetupPyStrategy, Upgrade,
NoBuild, PreviewMode, Reinstall, SetupPyStrategy, SourceStrategy, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::BuildDispatch;
@ -81,6 +81,7 @@ pub(crate) async fn pip_compile(
python_platform: Option<TargetTriple>,
universal: bool,
exclude_newer: Option<ExcludeNewer>,
sources: SourceStrategy,
annotation_style: AnnotationStyle,
link_mode: LinkMode,
python: Option<String>,
@ -323,6 +324,7 @@ pub(crate) async fn pip_compile(
link_mode,
&build_options,
exclude_newer,
sources,
concurrency,
preview,
);

View file

@ -13,7 +13,7 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, HashCheckingMode,
IndexStrategy, PreviewMode, Reinstall, SetupPyStrategy, Upgrade,
IndexStrategy, PreviewMode, Reinstall, SetupPyStrategy, SourceStrategy, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::BuildDispatch;
@ -64,6 +64,7 @@ pub(crate) async fn pip_install(
python_platform: Option<TargetTriple>,
strict: bool,
exclude_newer: Option<ExcludeNewer>,
sources: SourceStrategy,
python: Option<String>,
system: bool,
break_system_packages: bool,
@ -313,6 +314,7 @@ pub(crate) async fn pip_install(
link_mode,
&build_options,
exclude_newer,
sources,
concurrency,
preview,
);

View file

@ -12,7 +12,7 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, HashCheckingMode,
IndexStrategy, PreviewMode, Reinstall, SetupPyStrategy, Upgrade,
IndexStrategy, PreviewMode, Reinstall, SetupPyStrategy, SourceStrategy, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::BuildDispatch;
@ -61,6 +61,7 @@ pub(crate) async fn pip_sync(
break_system_packages: bool,
target: Option<Target>,
prefix: Option<Prefix>,
sources: SourceStrategy,
concurrency: Concurrency,
native_tls: bool,
preview: PreviewMode,
@ -259,6 +260,7 @@ pub(crate) async fn pip_sync(
link_mode,
&build_options,
exclude_newer,
sources,
concurrency,
preview,
);

View file

@ -5,7 +5,9 @@ use std::collections::hash_map::Entry;
use uv_auth::store_credentials_from_url;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode, SetupPyStrategy};
use uv_configuration::{
Concurrency, ExtrasSpecification, PreviewMode, SetupPyStrategy, SourceStrategy,
};
use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase;
use uv_fs::CWD;
@ -123,8 +125,8 @@ pub(crate) async fn add(
FlatIndex::from_entries(entries, Some(&tags), &hasher, &settings.build_options)
};
// TODO: read locked build constraints
let build_constraints = [];
let sources = SourceStrategy::Enabled;
// Create a build dispatch.
let build_dispatch = BuildDispatch::new(
@ -144,6 +146,7 @@ pub(crate) async fn add(
settings.link_mode,
&settings.build_options,
settings.exclude_newer,
sources,
concurrency,
preview,
);

View file

@ -223,6 +223,7 @@ async fn do_lock(
link_mode,
upgrade,
build_options,
sources,
} = settings;
// When locking, include the project itself (as editable).
@ -423,6 +424,7 @@ async fn do_lock(
link_mode,
build_options,
exclude_newer,
sources,
concurrency,
preview,
);
@ -502,6 +504,7 @@ async fn do_lock(
link_mode,
build_options,
exclude_newer,
sources,
concurrency,
preview,
);

View file

@ -408,6 +408,7 @@ pub(crate) async fn resolve_names(
exclude_newer,
link_mode,
compile_bytecode: _,
sources,
upgrade: _,
reinstall: _,
build_options,
@ -456,6 +457,7 @@ pub(crate) async fn resolve_names(
*link_mode,
build_options,
*exclude_newer,
*sources,
concurrency,
preview,
);
@ -498,6 +500,7 @@ pub(crate) async fn resolve_environment<'a>(
link_mode,
upgrade: _,
build_options,
sources,
} = settings;
// Respect all requirements from the provided sources.
@ -579,6 +582,7 @@ pub(crate) async fn resolve_environment<'a>(
link_mode,
build_options,
exclude_newer,
sources,
concurrency,
preview,
);
@ -636,6 +640,7 @@ pub(crate) async fn sync_environment(
compile_bytecode,
reinstall,
build_options,
sources,
} = settings;
let site_packages = SitePackages::from_environment(&venv)?;
@ -695,6 +700,7 @@ pub(crate) async fn sync_environment(
link_mode,
build_options,
exclude_newer,
sources,
concurrency,
preview,
);
@ -754,6 +760,7 @@ pub(crate) async fn update_environment(
exclude_newer,
link_mode,
compile_bytecode,
sources,
upgrade,
reinstall,
build_options,
@ -860,6 +867,7 @@ pub(crate) async fn update_environment(
*link_mode,
build_options,
*exclude_newer,
*sources,
concurrency,
preview,
);

View file

@ -152,6 +152,7 @@ pub(super) async fn do_sync(
compile_bytecode,
reinstall,
build_options,
sources,
} = settings;
// Validate that the Python version is supported by the lockfile.
@ -229,6 +230,7 @@ pub(super) async fn do_sync(
link_mode,
build_options,
exclude_newer,
sources,
concurrency,
preview,
);

View file

@ -17,7 +17,7 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, IndexStrategy, KeyringProviderType, NoBinary,
NoBuild, PreviewMode, SetupPyStrategy,
NoBuild, PreviewMode, SetupPyStrategy, SourceStrategy,
};
use uv_dispatch::BuildDispatch;
use uv_fs::{Simplified, CWD};
@ -269,15 +269,16 @@ async fn venv_impl(
// Initialize any shared state.
let state = SharedState::default();
// For seed packages, assume the default settings and concurrency is sufficient.
let config_settings = ConfigSettings::default();
// For seed packages, assume a bunch of default settings and concurrency are sufficient.
let build_constraints = [];
let concurrency = Concurrency::default();
let config_settings = ConfigSettings::default();
let setup_py = SetupPyStrategy::default();
let sources = SourceStrategy::Disabled;
// Do not allow builds
let build_options = BuildOptions::new(NoBinary::None, NoBuild::All);
let build_constraints = [];
// Prep the build context.
let build_dispatch = BuildDispatch::new(
&client,
@ -290,12 +291,13 @@ async fn venv_impl(
&state.git,
&state.in_flight,
index_strategy,
SetupPyStrategy::default(),
setup_py,
&config_settings,
BuildIsolation::Isolated,
link_mode,
&build_options,
exclude_newer,
sources,
concurrency,
preview,
);

View file

@ -279,6 +279,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
args.settings.python_platform,
args.settings.universal,
args.settings.exclude_newer,
args.settings.sources,
args.settings.annotation_style,
args.settings.link_mode,
args.settings.python,
@ -354,6 +355,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
args.settings.break_system_packages,
args.settings.target,
args.settings.prefix,
args.settings.sources,
args.settings.concurrency,
globals.native_tls,
globals.preview,
@ -438,6 +440,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
args.settings.python_platform,
args.settings.strict,
args.settings.exclude_newer,
args.settings.sources,
args.settings.python,
args.settings.system,
args.settings.break_system_packages,

View file

@ -21,7 +21,7 @@ use uv_client::Connectivity;
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, HashCheckingMode,
IndexStrategy, KeyringProviderType, NoBinary, NoBuild, PreviewMode, Reinstall, SetupPyStrategy,
TargetTriple, Upgrade,
SourceStrategy, TargetTriple, Upgrade,
};
use uv_normalize::PackageName;
use uv_python::{Prefix, PythonFetch, PythonPreference, PythonVersion, Target};
@ -1512,6 +1512,7 @@ pub(crate) struct InstallerSettingsRef<'a> {
pub(crate) compile_bytecode: bool,
pub(crate) reinstall: &'a Reinstall,
pub(crate) build_options: &'a BuildOptions,
pub(crate) sources: SourceStrategy,
}
/// The resolved settings to use for an invocation of the uv CLI when resolving dependencies.
@ -1531,6 +1532,7 @@ pub(crate) struct ResolverSettings {
pub(crate) link_mode: LinkMode,
pub(crate) upgrade: Upgrade,
pub(crate) build_options: BuildOptions,
pub(crate) sources: SourceStrategy,
}
#[derive(Debug, Clone, Copy)]
@ -1545,6 +1547,7 @@ pub(crate) struct ResolverSettingsRef<'a> {
pub(crate) link_mode: LinkMode,
pub(crate) upgrade: &'a Upgrade,
pub(crate) build_options: &'a BuildOptions,
pub(crate) sources: SourceStrategy,
}
impl ResolverSettings {
@ -1563,6 +1566,7 @@ impl ResolverSettings {
exclude_newer,
link_mode,
compile_bytecode: _,
no_sources,
upgrade,
upgrade_package,
reinstall: _,
@ -1624,6 +1628,9 @@ impl ResolverSettings {
.unwrap_or_default(),
),
),
sources: SourceStrategy::from_args(
args.no_sources.combine(no_sources).unwrap_or_default(),
),
}
}
@ -1639,6 +1646,7 @@ impl ResolverSettings {
link_mode: self.link_mode,
upgrade: &self.upgrade,
build_options: &self.build_options,
sources: self.sources,
}
}
}
@ -1660,6 +1668,7 @@ pub(crate) struct ResolverInstallerSettings {
pub(crate) exclude_newer: Option<ExcludeNewer>,
pub(crate) link_mode: LinkMode,
pub(crate) compile_bytecode: bool,
pub(crate) sources: SourceStrategy,
pub(crate) upgrade: Upgrade,
pub(crate) reinstall: Reinstall,
pub(crate) build_options: BuildOptions,
@ -1676,6 +1685,7 @@ pub(crate) struct ResolverInstallerSettingsRef<'a> {
pub(crate) exclude_newer: Option<ExcludeNewer>,
pub(crate) link_mode: LinkMode,
pub(crate) compile_bytecode: bool,
pub(crate) sources: SourceStrategy,
pub(crate) upgrade: &'a Upgrade,
pub(crate) reinstall: &'a Reinstall,
pub(crate) build_options: &'a BuildOptions,
@ -1700,6 +1710,7 @@ impl ResolverInstallerSettings {
exclude_newer,
link_mode,
compile_bytecode,
no_sources,
upgrade,
upgrade_package,
reinstall,
@ -1738,6 +1749,9 @@ impl ResolverInstallerSettings {
.unwrap_or_default(),
exclude_newer: args.exclude_newer.combine(exclude_newer),
link_mode: args.link_mode.combine(link_mode).unwrap_or_default(),
sources: SourceStrategy::from_args(
args.no_sources.combine(no_sources).unwrap_or_default(),
),
compile_bytecode: args
.compile_bytecode
.combine(compile_bytecode)
@ -1785,6 +1799,7 @@ impl ResolverInstallerSettings {
exclude_newer: self.exclude_newer,
link_mode: self.link_mode,
compile_bytecode: self.compile_bytecode,
sources: self.sources,
upgrade: &self.upgrade,
reinstall: &self.reinstall,
build_options: &self.build_options,
@ -1837,6 +1852,7 @@ pub(crate) struct PipSettings {
pub(crate) annotation_style: AnnotationStyle,
pub(crate) link_mode: LinkMode,
pub(crate) compile_bytecode: bool,
pub(crate) sources: SourceStrategy,
pub(crate) hash_checking: Option<HashCheckingMode>,
pub(crate) upgrade: Upgrade,
pub(crate) reinstall: Reinstall,
@ -1897,6 +1913,7 @@ impl PipSettings {
compile_bytecode,
require_hashes,
verify_hashes,
no_sources,
upgrade,
upgrade_package,
reinstall,
@ -1919,6 +1936,7 @@ impl PipSettings {
exclude_newer: top_level_exclude_newer,
link_mode: top_level_link_mode,
compile_bytecode: top_level_compile_bytecode,
no_sources: top_level_no_sources,
upgrade: top_level_upgrade,
upgrade_package: top_level_upgrade_package,
reinstall: top_level_reinstall,
@ -1945,6 +1963,7 @@ impl PipSettings {
let exclude_newer = exclude_newer.combine(top_level_exclude_newer);
let link_mode = link_mode.combine(top_level_link_mode);
let compile_bytecode = compile_bytecode.combine(top_level_compile_bytecode);
let no_sources = no_sources.combine(top_level_no_sources);
let upgrade = upgrade.combine(top_level_upgrade);
let upgrade_package = upgrade_package.combine(top_level_upgrade_package);
let reinstall = reinstall.combine(top_level_reinstall);
@ -2068,6 +2087,9 @@ impl PipSettings {
.compile_bytecode
.combine(compile_bytecode)
.unwrap_or_default(),
sources: SourceStrategy::from_args(
args.no_sources.combine(no_sources).unwrap_or_default(),
),
strict: args.strict.combine(strict).unwrap_or_default(),
upgrade: Upgrade::from_args(
args.upgrade.combine(upgrade),
@ -2133,6 +2155,7 @@ impl<'a> From<ResolverInstallerSettingsRef<'a>> for ResolverSettingsRef<'a> {
link_mode: settings.link_mode,
upgrade: settings.upgrade,
build_options: settings.build_options,
sources: settings.sources,
}
}
}
@ -2149,6 +2172,7 @@ impl<'a> From<ResolverInstallerSettingsRef<'a>> for InstallerSettingsRef<'a> {
compile_bytecode: settings.compile_bytecode,
reinstall: settings.reinstall,
build_options: settings.build_options,
sources: settings.sources,
}
}
}

View file

@ -4492,3 +4492,157 @@ fn lock_redact() -> Result<()> {
Ok(())
}
/// Lock a package that's excluded from the parent workspace, but depends on that parent.
#[test]
fn lock_no_sources() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["anyio"]
[tool.uv.sources]
anyio = { path = "./anyio" }
"#,
)?;
let anyio = context.temp_dir.child("anyio");
fs_err::create_dir_all(&anyio)?;
let pyproject_toml = anyio.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "anyio"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["iniconfig"]
"#,
)?;
// Lock the root package with `tool.uv.sources` enabled.
uv_snapshot!(context.filters(), context.lock().current_dir(&context.temp_dir), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning
warning: `uv.sources` is experimental and may change without warning
Resolved 3 packages in [TIME]
"###);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.12"
exclude-newer = "2024-03-25 00:00:00 UTC"
[[distribution]]
name = "anyio"
version = "0.1.0"
source = { directory = "anyio" }
dependencies = [
{ name = "iniconfig" },
]
[[distribution]]
name = "iniconfig"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
]
[[distribution]]
name = "project"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "anyio" },
]
"###
);
});
// Lock the root package with `tool.uv.sources` disabled.
uv_snapshot!(context.filters(), context.lock().arg("--no-sources").current_dir(&context.temp_dir), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning
Resolved 4 packages in [TIME]
Updated anyio v0.1.0 -> v4.3.0
Added idna v3.6
Removed iniconfig v2.0.0
Added sniffio v1.3.1
"###);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.12"
exclude-newer = "2024-03-25 00:00:00 UTC"
[[distribution]]
name = "anyio"
version = "4.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "idna" },
{ name = "sniffio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6", size = 159642 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", size = 85584 },
]
[[distribution]]
name = "idna"
version = "3.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", size = 175426 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f", size = 61567 },
]
[[distribution]]
name = "project"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "anyio" },
]
[[distribution]]
name = "sniffio"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
]
"###
);
});
Ok(())
}

View file

@ -159,6 +159,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -293,6 +294,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -428,6 +430,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -595,6 +598,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -708,6 +712,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -853,6 +858,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -1035,6 +1041,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -1216,6 +1223,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -1375,6 +1383,7 @@ fn resolve_find_links() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -1510,6 +1519,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -1683,6 +1693,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -1839,6 +1850,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -1974,6 +1986,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -2092,6 +2105,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -2210,6 +2224,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -2330,6 +2345,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -2475,6 +2491,7 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,
@ -2644,6 +2661,7 @@ fn resolve_both() -> anyhow::Result<()> {
annotation_style: Split,
link_mode: Clone,
compile_bytecode: false,
sources: Enabled,
hash_checking: None,
upgrade: None,
reinstall: None,

View file

@ -22,7 +22,7 @@ dependencies = [
]
[tool.uv.sources]
bird-feeder = { path = "/path/to/bird-feeder" }
bird-feeder = { path = "./packages/bird-feeder" }
```
## Project dependencies
@ -73,8 +73,18 @@ additional sources are supported by uv:
Only a single source may be defined for each dependency.
Note that if a non-uv project uses a project with sources as a Git- or path-dependency, only
`project.dependencies` and `project.optional-dependencies` are respected, the information in the
source table will need to be re-specified in a format specific to the other package manager.
`project.dependencies` and `project.optional-dependencies` are respected. Any information provided
in the source table will need to be re-specified in a format specific to the other package manager.
To instruct uv to ignore the `tool.uv.sources` table (e.g., to simulate resolving with the package's
published metadata), use the `--no-sources` flag:
```console
$ uv lock --no-sources
```
The use of `--no-sources` will also prevent uv from discovering any
[workspace members](#workspace-member) that could satisfy a given dependency.
### Git
@ -181,7 +191,7 @@ $ uv add ~/projects/bar/
$ uv add --editable ~/projects/bar/
```
However, it is recommended to use [_workspaces_](#workspaces) instead of manual path
However, it is recommended to use [_workspaces_](./workspaces) instead of manual path
dependencies.
### Workspace member

View file

@ -525,6 +525,33 @@ those provided via `--find-links`.
---
#### [`no-sources`](#no-sources) {: #no-sources }
Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
standards-compliant, publishable package metadata, as opposed to using any local or Git
sources.
**Default value**: `false`
**Type**: `bool`
**Example usage**:
=== "pyproject.toml"
```toml
[tool.uv]
no-sources = true
```
=== "uv.toml"
```toml
no-sources = true
```
---
#### [`offline`](#offline) {: #offline }
Disable network access, relying only on locally cached data and locally available files.
@ -1773,6 +1800,34 @@ those provided via `--find-links`.
---
#### [`no-sources`](#pip_no-sources) {: #pip_no-sources }
<span id="no-sources"></span>
Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
standards-compliant, publishable package metadata, as opposed to using any local or Git
sources.
**Default value**: `false`
**Type**: `bool`
**Example usage**:
=== "pyproject.toml"
```toml
[tool.uv.pip]
no-sources = true
```
=== "uv.toml"
```toml
[pip]
no-sources = true
```
---
#### [`no-strip-extras`](#pip_no-strip-extras) {: #pip_no-strip-extras }
<span id="no-strip-extras"></span>

14
uv.schema.json generated
View file

@ -185,6 +185,13 @@
"null"
]
},
"no-sources": {
"description": "Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the standards-compliant, publishable package metadata, as opposed to using any local or Git sources.",
"type": [
"boolean",
"null"
]
},
"offline": {
"description": "Disable network access, relying only on locally cached data and locally available files.",
"type": [
@ -766,6 +773,13 @@
"null"
]
},
"no-sources": {
"description": "Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the standards-compliant, publishable package metadata, as opposed to using any local or Git sources.",
"type": [
"boolean",
"null"
]
},
"no-strip-extras": {
"description": "Include extras in the output file.\n\nBy default, uv strips extras, as any packages pulled in by the extras are already included as dependencies in the output file directly. Further, output files generated with `--no-strip-extras` cannot be used as constraints files in `install` and `sync` invocations.",
"type": [