From 79a875ba541164dd63316279eed6178bd143c2c9 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 24 Aug 2024 11:46:31 -0400 Subject: [PATCH] Add support for virtual projects --- crates/uv-cli/src/lib.rs | 9 +- crates/uv-settings/src/settings.rs | 4 + crates/uv-workspace/src/pyproject.rs | 34 + crates/uv-workspace/src/workspace.rs | 6 +- crates/uv/src/commands/project/init.rs | 126 ++-- crates/uv/src/commands/project/sync.rs | 35 + crates/uv/tests/common/mod.rs | 5 +- crates/uv/tests/edit.rs | 330 ++++++++- crates/uv/tests/init.rs | 74 +- crates/uv/tests/lock.rs | 904 ++++++++++++++++++++++++- crates/uv/tests/run.rs | 92 ++- crates/uv/tests/sync.rs | 64 +- crates/uv/tests/workspace.rs | 105 ++- docs/reference/cli.md | 6 +- docs/reference/settings.md | 25 + uv.schema.json | 7 + 16 files changed, 1680 insertions(+), 146 deletions(-) diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index b68666f2c04ae..ea67833743f9a 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -2099,11 +2099,12 @@ pub struct InitArgs { #[arg(long)] pub name: Option, - /// Create a virtual workspace instead of a project. + /// Create a virtual project, rather than a package. /// - /// A virtual workspace does not define project dependencies and cannot be - /// published. Instead, workspace members declare project dependencies. - /// Development dependencies may still be declared. + /// A virtual project is a project that is not intended to be built as a Python package, + /// such as a project that only contains scripts or other application code. + /// + /// Virtual projects themselves are not installed into the Python environment. #[arg(long)] pub r#virtual: bool, diff --git a/crates/uv-settings/src/settings.rs b/crates/uv-settings/src/settings.rs index 273a1d8c0d6d2..005ab499680e1 100644 --- a/crates/uv-settings/src/settings.rs +++ b/crates/uv-settings/src/settings.rs @@ -70,6 +70,10 @@ pub struct Options { #[serde(default, skip_serializing)] #[cfg_attr(feature = "schemars", schemars(skip))] managed: serde::de::IgnoredAny, + + #[serde(default, skip_serializing)] + #[cfg_attr(feature = "schemars", schemars(skip))] + r#virtual: serde::de::IgnoredAny, } impl Options { diff --git a/crates/uv-workspace/src/pyproject.rs b/crates/uv-workspace/src/pyproject.rs index c2eaee29652f2..fb093be226cbe 100644 --- a/crates/uv-workspace/src/pyproject.rs +++ b/crates/uv-workspace/src/pyproject.rs @@ -33,6 +33,10 @@ pub struct PyProjectToml { /// The raw unserialized document. #[serde(skip)] pub raw: String, + + /// Used to determine whether a `build-system` is present. + #[serde(default, skip_serializing)] + build_system: Option, } impl PyProjectToml { @@ -41,6 +45,27 @@ impl PyProjectToml { let pyproject = toml::from_str(&raw)?; Ok(PyProjectToml { raw, ..pyproject }) } + + /// Returns `true` if the project should be considered "virtual". + pub fn is_virtual(&self) -> bool { + // A project is virtual if `virtual = true` is set... + if self + .tool + .as_ref() + .and_then(|tool| tool.uv.as_ref()) + .and_then(|uv| uv.r#virtual) + == Some(true) + { + return true; + } + + // Or if `build-system` is not present. + if self.build_system.is_none() { + return true; + } + + false + } } // Ignore raw document in comparison. @@ -100,6 +125,15 @@ pub struct ToolUv { "# )] pub managed: Option, + /// Whether the project should be considered "virtual". + #[option( + default = r#"true"#, + value_type = "bool", + example = r#" + virtual = false + "# + )] + pub r#virtual: Option, /// The project's development dependencies. Development dependencies will be installed by /// default in `uv run` and `uv sync`, but will not appear in the project's published metadata. #[cfg_attr( diff --git a/crates/uv-workspace/src/workspace.rs b/crates/uv-workspace/src/workspace.rs index 4e8f3d34aa097..afeabacf0b8de 100644 --- a/crates/uv-workspace/src/workspace.rs +++ b/crates/uv-workspace/src/workspace.rs @@ -1339,7 +1339,7 @@ impl VirtualProject { } } - /// Return the [`PackageName`] of the project, if it's not a virtual workspace. + /// Return the [`PackageName`] of the project, if it's not a virtual workspace root. pub fn project_name(&self) -> Option<&PackageName> { match self { VirtualProject::Project(project) => Some(project.project_name()), @@ -1347,7 +1347,7 @@ impl VirtualProject { } } - /// Returns `true` if the project is a virtual workspace. + /// Returns `true` if the project is a virtual workspace root. pub fn is_virtual(&self) -> bool { matches!(self, VirtualProject::Virtual(_)) } @@ -1535,6 +1535,7 @@ mod tests { "exclude": null }, "managed": null, + "virtual": null, "dev-dependencies": null, "environments": null, "override-dependencies": null, @@ -1607,6 +1608,7 @@ mod tests { "exclude": null }, "managed": null, + "virtual": null, "dev-dependencies": null, "environments": null, "override-dependencies": null, diff --git a/crates/uv/src/commands/project/init.rs b/crates/uv/src/commands/project/init.rs index 7180d9157b3a6..914abc1ac440b 100644 --- a/crates/uv/src/commands/project/init.rs +++ b/crates/uv/src/commands/project/init.rs @@ -15,7 +15,7 @@ use uv_python::{ }; use uv_resolver::RequiresPython; use uv_workspace::pyproject_mut::{DependencyTarget, PyProjectTomlMut}; -use uv_workspace::{check_nested_workspaces, DiscoveryOptions, Workspace, WorkspaceError}; +use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceError}; use crate::commands::project::find_requires_python; use crate::commands::reporters::PythonDownloadReporter; @@ -69,24 +69,21 @@ pub(crate) async fn init( } }; - if r#virtual { - init_virtual_workspace(&path, no_workspace)?; - } else { - init_project( - &path, - &name, - no_readme, - python, - no_workspace, - python_preference, - python_downloads, - connectivity, - native_tls, - cache, - printer, - ) - .await?; - } + init_project( + &path, + &name, + r#virtual, + no_readme, + python, + no_workspace, + python_preference, + python_downloads, + connectivity, + native_tls, + cache, + printer, + ) + .await?; // Create the `README.md` if it does not already exist. if !no_readme { @@ -126,29 +123,12 @@ pub(crate) async fn init( Ok(ExitStatus::Success) } -/// Initialize a virtual workspace at the given path. -fn init_virtual_workspace(path: &Path, no_workspace: bool) -> Result<()> { - // Ensure that we aren't creating a nested workspace. - if !no_workspace { - check_nested_workspaces(path, &DiscoveryOptions::default()); - } - - // Create the `pyproject.toml`. - let pyproject = indoc::indoc! {r" - [tool.uv.workspace] - members = [] - "}; - - fs_err::create_dir_all(path)?; - fs_err::write(path.join("pyproject.toml"), pyproject)?; - - Ok(()) -} - /// Initialize a project (and, implicitly, a workspace root) at the given path. +#[allow(clippy::fn_params_excessive_bools)] async fn init_project( path: &Path, name: &PackageName, + r#virtual: bool, no_readme: bool, python: Option, no_workspace: bool, @@ -265,38 +245,56 @@ async fn init_project( RequiresPython::greater_than_equal_version(&interpreter.python_minor_version()) }; - // Create the `pyproject.toml`. - let pyproject = indoc::formatdoc! {r#" - [project] - name = "{name}" - version = "0.1.0" - description = "Add your description here"{readme} - requires-python = "{requires_python}" - dependencies = [] + if r#virtual { + // Create the `pyproject.toml`, but omit `[build-system]`. + let pyproject = indoc::formatdoc! {r#" + [project] + name = "{name}" + version = "0.1.0" + description = "Add your description here"{readme} + requires-python = "{requires_python}" + dependencies = [] + "#, + readme = if no_readme { "" } else { "\nreadme = \"README.md\"" }, + requires_python = requires_python.specifiers(), + }; - [build-system] - requires = ["hatchling"] - build-backend = "hatchling.build" - "#, - readme = if no_readme { "" } else { "\nreadme = \"README.md\"" }, - requires_python = requires_python.specifiers(), - }; + fs_err::create_dir_all(path)?; + fs_err::write(path.join("pyproject.toml"), pyproject)?; + } else { + // Create the `pyproject.toml`. + let pyproject = indoc::formatdoc! {r#" + [project] + name = "{name}" + version = "0.1.0" + description = "Add your description here"{readme} + requires-python = "{requires_python}" + dependencies = [] + + [build-system] + requires = ["hatchling"] + build-backend = "hatchling.build" + "#, + readme = if no_readme { "" } else { "\nreadme = \"README.md\"" }, + requires_python = requires_python.specifiers(), + }; - fs_err::create_dir_all(path)?; - fs_err::write(path.join("pyproject.toml"), pyproject)?; + fs_err::create_dir_all(path)?; + fs_err::write(path.join("pyproject.toml"), pyproject)?; - // Create `src/{name}/__init__.py`, if it doesn't exist already. - let src_dir = path.join("src").join(&*name.as_dist_info_name()); - let init_py = src_dir.join("__init__.py"); - if !init_py.try_exists()? { - fs_err::create_dir_all(&src_dir)?; - fs_err::write( - init_py, - indoc::formatdoc! {r#" + // Create `src/{name}/__init__.py`, if it doesn't exist already. + let src_dir = path.join("src").join(&*name.as_dist_info_name()); + let init_py = src_dir.join("__init__.py"); + if !init_py.try_exists()? { + fs_err::create_dir_all(&src_dir)?; + fs_err::write( + init_py, + indoc::formatdoc! {r#" def hello() -> str: return "Hello from {name}!" "#}, - )?; + )?; + } } if let Some(workspace) = workspace { diff --git a/crates/uv/src/commands/project/sync.rs b/crates/uv/src/commands/project/sync.rs index ef97e30fe3029..c42954ec55257 100644 --- a/crates/uv/src/commands/project/sync.rs +++ b/crates/uv/src/commands/project/sync.rs @@ -1,5 +1,8 @@ use anyhow::{Context, Result}; use itertools::Itertools; +use rustc_hash::FxHashSet; + +use distribution_types::Name; use pep508_rs::MarkerTree; use uv_auth::store_credentials_from_url; use uv_cache::Cache; @@ -195,6 +198,9 @@ pub(super) async fn do_sync( // Read the lockfile. let resolution = lock.to_resolution(project, &markers, tags, extras, &dev)?; + // Always skip virtual projects, which shouldn't be built or installed. + let resolution = apply_no_virtual_project(resolution, project); + // Filter resolution based on install-specific options. let resolution = install_options.filter_resolution(resolution, project); @@ -289,3 +295,32 @@ pub(super) async fn do_sync( Ok(()) } + +/// Filter out any virtual workspace members. +fn apply_no_virtual_project( + resolution: distribution_types::Resolution, + project: &VirtualProject, +) -> distribution_types::Resolution { + let VirtualProject::Project(project) = project else { + // If the project is _only_ a virtual workspace root, we don't need to filter it out. + return resolution; + }; + + let virtual_members = project + .workspace() + .packages() + .iter() + .filter_map(|(name, package)| { + // A project is virtual if it's explicitly marked as virtual, _or_ if it's missing a + // build system. + if package.pyproject_toml().is_virtual() { + Some(name) + } else { + None + } + }) + .collect::>(); + + // Remove any virtual members from the resolution. + resolution.filter(|dist| !virtual_members.contains(dist.name())) +} diff --git a/crates/uv/tests/common/mod.rs b/crates/uv/tests/common/mod.rs index d8e4f8daa7d88..ec187573b3189 100644 --- a/crates/uv/tests/common/mod.rs +++ b/crates/uv/tests/common/mod.rs @@ -1110,8 +1110,9 @@ pub fn make_project(dir: &Path, name: &str, body: &str) -> anyhow::Result<()> { {body} [build-system] - requires = ["flit_core>=3.8,<4"] - build-backend = "flit_core.buildapi" + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + "# }; fs_err::create_dir_all(dir)?; diff --git a/crates/uv/tests/edit.rs b/crates/uv/tests/edit.rs index c8425aa140c2a..fd1d411c35a39 100644 --- a/crates/uv/tests/edit.rs +++ b/crates/uv/tests/edit.rs @@ -20,9 +20,12 @@ fn add_registry() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["anyio==3.7.0"]), @r###" @@ -50,11 +53,14 @@ fn add_registry() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [ "anyio==3.7.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -143,6 +149,10 @@ fn add_git() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.lock(), @r###" @@ -212,6 +222,10 @@ fn add_git() -> Result<()> { "uv-public-pypackage", ] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] uv-public-pypackage = { git = "https://github.com/astral-test/uv-public-pypackage", tag = "0.0.1" } "### @@ -313,6 +327,10 @@ fn add_git_private_source() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&[&format!("uv-private-pypackage @ git+https://{token}@github.com/astral-test/uv-private-pypackage")]), @r###" @@ -343,6 +361,10 @@ fn add_git_private_source() -> Result<()> { "uv-private-pypackage", ] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] uv-private-pypackage = { git = "https://github.com/astral-test/uv-private-pypackage" } "### @@ -409,6 +431,10 @@ fn add_git_private_raw() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&[&format!("uv-private-pypackage @ git+https://{token}@github.com/astral-test/uv-private-pypackage")]).arg("--raw-sources"), @r###" @@ -443,6 +469,10 @@ fn add_git_private_raw() -> Result<()> { dependencies = [ "uv-private-pypackage @ git+https://***@github.com/astral-test/uv-private-pypackage", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -504,6 +534,10 @@ fn add_git_error() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.lock(), @r###" @@ -562,6 +596,10 @@ fn add_git_raw() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.lock(), @r###" @@ -617,6 +655,10 @@ fn add_git_raw() -> Result<()> { "anyio==3.7.0", "uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage@0.0.1", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -714,6 +756,10 @@ fn add_git_implicit() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.lock(), @r###" @@ -770,6 +816,10 @@ fn add_raw_error() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Provide a tag without a Git source. @@ -800,9 +850,12 @@ fn add_unnamed() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["git+https://github.com/astral-test/uv-public-pypackage"]).arg("--tag=0.0.1"), @r###" @@ -828,12 +881,15 @@ fn add_unnamed() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [ "uv-public-pypackage", ] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] uv-public-pypackage = { git = "https://github.com/astral-test/uv-public-pypackage", tag = "0.0.1" } "### @@ -897,6 +953,10 @@ fn add_remove_dev() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["anyio==3.7.0"]).arg("--dev"), @r###" @@ -927,6 +987,10 @@ fn add_remove_dev() -> Result<()> { requires-python = ">=3.12" dependencies = [] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] dev-dependencies = [ "anyio==3.7.0", @@ -1049,6 +1113,10 @@ fn add_remove_dev() -> Result<()> { requires-python = ">=3.12" dependencies = [] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] dev-dependencies = [] "### @@ -1101,6 +1169,10 @@ fn add_remove_optional() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["anyio==3.7.0"]).arg("--optional=io"), @r###" @@ -1135,6 +1207,10 @@ fn add_remove_optional() -> Result<()> { io = [ "anyio==3.7.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -1254,6 +1330,10 @@ fn add_remove_optional() -> Result<()> { [project.optional-dependencies] io = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -1310,6 +1390,10 @@ fn add_remove_workspace() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; let pyproject_toml = context.temp_dir.child("child2/pyproject.toml"); @@ -1319,6 +1403,10 @@ fn add_remove_workspace() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Adding a workspace package with a mismatched source should error. @@ -1374,6 +1462,10 @@ fn add_remove_workspace() -> Result<()> { "child2", ] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] child2 = { workspace = true } "### @@ -1457,6 +1549,10 @@ fn add_remove_workspace() -> Result<()> { requires-python = ">=3.12" dependencies = [] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] "### ); @@ -1525,6 +1621,10 @@ fn add_workspace_editable() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; let pyproject_toml = context.temp_dir.child("child2/pyproject.toml"); @@ -1534,6 +1634,10 @@ fn add_workspace_editable() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; let child1 = context.temp_dir.join("child1"); @@ -1568,6 +1672,10 @@ fn add_workspace_editable() -> Result<()> { "child2", ] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] child2 = { workspace = true } "### @@ -1743,9 +1851,11 @@ fn update() -> Result<()> { name = "project" version = "0.1.0" requires-python = ">=3.12" - dependencies = [ - "requests==2.31.0" - ] + dependencies = ["requests==2.31.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.lock(), @r###" @@ -1801,6 +1911,10 @@ fn update() -> Result<()> { dependencies = [ "requests[security]==2.31.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -1836,6 +1950,10 @@ fn update() -> Result<()> { "requests[security]==2.31.0", "requests[socks,use-chardet-on-py3]>=2.31.0 ; python_full_version >= '3.8'", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -1873,6 +1991,10 @@ fn update() -> Result<()> { "requests[socks,use-chardet-on-py3]>=2.31.0 ; python_full_version >= '3.8'", ] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] requests = { git = "https://github.com/psf/requests", tag = "v2.32.3" } "### @@ -2021,9 +2143,11 @@ fn add_update_marker() -> Result<()> { name = "project" version = "0.1.0" requires-python = ">=3.8" - dependencies = [ - "requests>=2.30; python_version >= '3.11'" - ] + dependencies = ["requests>=2.30; python_version >= '3.11'"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.lock(), @r###" success: true @@ -2080,6 +2204,10 @@ fn add_update_marker() -> Result<()> { "requests>=2.30; python_version >= '3.11'", "requests>=2.0,<2.29 ; python_full_version < '3.11'", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2114,6 +2242,10 @@ fn add_update_marker() -> Result<()> { "requests>=2.30; python_version >= '3.11'", "requests>=2.0,<2.20 ; python_full_version < '3.11'", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2153,6 +2285,10 @@ fn add_update_marker() -> Result<()> { "requests>=2.0,<2.20 ; python_full_version < '3.11'", "requests>=2.31 ; python_full_version >= '3.12' and sys_platform == 'win32'", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2190,6 +2326,10 @@ fn add_update_marker() -> Result<()> { "requests>=2.31 ; python_full_version >= '3.12' and sys_platform == 'win32'", "requests>=2.10 ; sys_platform == 'win32'", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2226,6 +2366,10 @@ fn add_update_marker() -> Result<()> { version = "0.1.0" requires-python = ">=3.8" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2247,6 +2391,10 @@ fn update_source_replace_url() -> Result<()> { dependencies = [ "requests[security] @ https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl" ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Change the source. The existing URL should be removed. @@ -2282,6 +2430,10 @@ fn update_source_replace_url() -> Result<()> { "requests[security]", ] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] requests = { git = "https://github.com/psf/requests", tag = "v2.32.3" } "### @@ -2302,9 +2454,11 @@ fn add_inexact() -> Result<()> { name = "project" version = "0.1.0" requires-python = ">=3.12" - dependencies = [ - "anyio == 3.7.0", - ] + dependencies = ["anyio == 3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.lock(), @r###" @@ -2337,6 +2491,10 @@ fn add_inexact() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["iniconfig==2.0.0"]), @r###" @@ -2367,6 +2525,10 @@ fn add_inexact() -> Result<()> { dependencies = [ "iniconfig==2.0.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2445,6 +2607,10 @@ fn remove_registry() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.lock(), @r###" @@ -2498,6 +2664,10 @@ fn remove_registry() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2545,11 +2715,12 @@ fn add_preserves_indentation_in_pyproject_toml() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" - dependencies = [ - "anyio==3.7.0" - ] + dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["requests==2.31.0"]), @r###" @@ -2581,12 +2752,15 @@ fn add_preserves_indentation_in_pyproject_toml() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [ - "anyio==3.7.0", - "requests==2.31.0", + "anyio==3.7.0", + "requests==2.31.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2602,9 +2776,12 @@ fn add_puts_default_indentation_in_pyproject_toml_if_not_observed() -> Result<() [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["requests==2.31.0"]), @r###" @@ -2636,12 +2813,15 @@ fn add_puts_default_indentation_in_pyproject_toml_if_not_observed() -> Result<() [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [ "anyio==3.7.0", "requests==2.31.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2658,9 +2838,12 @@ fn add_frozen() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["anyio==3.7.0"]).arg("--frozen"), @r###" @@ -2681,11 +2864,14 @@ fn add_frozen() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [ "anyio==3.7.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2705,9 +2891,12 @@ fn add_no_sync() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["anyio==3.7.0"]).arg("--no-sync"), @r###" @@ -2729,11 +2918,14 @@ fn add_no_sync() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [ "anyio==3.7.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2821,9 +3013,12 @@ fn add_error() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["xyz"]), @r###" @@ -2863,6 +3058,10 @@ fn add_lower_bound() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Adding `anyio` should include a lower-bound. @@ -2895,6 +3094,10 @@ fn add_lower_bound() -> Result<()> { dependencies = [ "anyio>=4.3.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2914,6 +3117,10 @@ fn add_lower_bound_existing() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Adding `anyio` should _not_ set a lower-bound, since it's already present (even if @@ -2947,6 +3154,10 @@ fn add_lower_bound_existing() -> Result<()> { dependencies = [ "anyio", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -2966,6 +3177,10 @@ fn add_lower_bound_raw() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Adding `anyio` should _not_ set a lower-bound when using `--raw-sources`. @@ -2998,6 +3213,10 @@ fn add_lower_bound_raw() -> Result<()> { dependencies = [ "anyio", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -3017,6 +3236,10 @@ fn add_lower_bound_dev() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Adding `anyio` should include a lower-bound. @@ -3048,6 +3271,10 @@ fn add_lower_bound_dev() -> Result<()> { requires-python = ">=3.12" dependencies = [] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] dev-dependencies = [ "anyio>=4.3.0", @@ -3071,6 +3298,10 @@ fn add_lower_bound_optional() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Adding `anyio` should include a lower-bound. @@ -3106,6 +3337,10 @@ fn add_lower_bound_optional() -> Result<()> { io = [ "anyio>=4.3.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -3185,6 +3420,10 @@ fn add_lower_bound_local() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Adding `torch` should include a lower-bound, but no local segment. @@ -3215,6 +3454,10 @@ fn add_lower_bound_local() -> Result<()> { dependencies = [ "local-simple-a>=1.2.3", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -3359,9 +3602,12 @@ fn add_repeat() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; uv_snapshot!(context.filters(), context.add(&["anyio"]), @r###" @@ -3389,11 +3635,14 @@ fn add_repeat() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [ "anyio>=4.3.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -3418,11 +3667,14 @@ fn add_repeat() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [ "anyio>=4.3.0", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); @@ -3440,9 +3692,12 @@ fn add_requirements_file() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; let requirements_txt = context.temp_dir.child("requirements.txt"); @@ -3481,13 +3736,16 @@ fn add_requirements_file() -> Result<()> { [project] name = "project" version = "0.1.0" - # ... requires-python = ">=3.12" dependencies = [ "flask==2.3.2", "anyio", ] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] anyio = { git = "https://github.com/agronholm/anyio.git", rev = "4.4.0" } "### @@ -3985,6 +4243,10 @@ fn fail_to_add_revert_project() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Adding `pytorch==1.0.2` should produce an error @@ -4032,6 +4294,10 @@ fn fail_to_add_revert_project() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "### ); }); diff --git a/crates/uv/tests/init.rs b/crates/uv/tests/init.rs index e36c417cac4f1..bb5cb58aa8568 100644 --- a/crates/uv/tests/init.rs +++ b/crates/uv/tests/init.rs @@ -882,9 +882,9 @@ fn init_explicit_workspace() -> Result<()> { Ok(()) } -/// Run `uv init` from within a virtual workspace. +/// Run `uv init --virtual` to create a virtual project. #[test] -fn init_virtual_workspace() -> Result<()> { +fn init_virtual_project() -> Result<()> { let context = TestContext::new("3.12"); let child = context.temp_dir.child("foo"); @@ -907,12 +907,67 @@ fn init_virtual_workspace() -> Result<()> { }, { assert_snapshot!( pyproject, @r###" + [project] + name = "foo" + version = "0.1.0" + description = "Add your description here" + readme = "README.md" + requires-python = ">=3.12" + dependencies = [] + "### + ); + }); + + uv_snapshot!(context.filters(), context.init().current_dir(&child).arg("bar"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Adding `bar` as member of workspace `[TEMP_DIR]/foo` + Initialized project `bar` at `[TEMP_DIR]/foo/bar` + "###); + + let pyproject = fs_err::read_to_string(pyproject_toml)?; + insta::with_settings!({ + filters => context.filters(), + }, { + assert_snapshot!( + pyproject, @r###" + [project] + name = "foo" + version = "0.1.0" + description = "Add your description here" + readme = "README.md" + requires-python = ">=3.12" + dependencies = [] + [tool.uv.workspace] - members = [] + members = ["bar"] "### ); }); + Ok(()) +} + +/// Run `uv init` from within a virtual workspace. +#[test] +fn init_virtual_workspace() -> Result<()> { + let context = TestContext::new("3.12"); + + let child = context.temp_dir.child("foo"); + child.create_dir_all()?; + + // Create a virtual workspace. + let pyproject_toml = child.child("pyproject.toml"); + pyproject_toml.write_str(indoc! { + r" + [tool.uv.workspace] + members = [] + ", + })?; + uv_snapshot!(context.filters(), context.init().current_dir(&child).arg("bar"), @r###" success: true exit_code: 0 @@ -957,7 +1012,7 @@ fn init_nested_virtual_workspace() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: Nested workspaces are not supported, but outer workspace (`[TEMP_DIR]/`) includes `[TEMP_DIR]/foo` + Adding `foo` as member of workspace `[TEMP_DIR]/` Initialized workspace `foo` at `[TEMP_DIR]/foo` "###); @@ -967,8 +1022,13 @@ fn init_nested_virtual_workspace() -> Result<()> { }, { assert_snapshot!( pyproject, @r###" - [tool.uv.workspace] - members = [] + [project] + name = "foo" + version = "0.1.0" + description = "Add your description here" + readme = "README.md" + requires-python = ">=3.12" + dependencies = [] "### ); }); @@ -980,7 +1040,7 @@ fn init_nested_virtual_workspace() -> Result<()> { assert_snapshot!( workspace, @r###" [tool.uv.workspace] - members = [] + members = ["foo"] "### ); }); diff --git a/crates/uv/tests/lock.rs b/crates/uv/tests/lock.rs index 38080386a8551..5018cdcce9595 100644 --- a/crates/uv/tests/lock.rs +++ b/crates/uv/tests/lock.rs @@ -28,6 +28,10 @@ fn lock_wheel_registry() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -150,6 +154,10 @@ fn lock_sdist_registry() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["source-distribution==0.0.1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -233,6 +241,10 @@ fn lock_sdist_git() -> Result<()> { requires-python = ">=3.12" dependencies = ["uv-public-pypackage"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] uv-public-pypackage = { git = "https://github.com/astral-test/uv-public-pypackage", tag = "0.0.1" } "#, @@ -323,6 +335,10 @@ fn lock_sdist_git() -> Result<()> { requires-python = ">=3.12" dependencies = ["uv-public-pypackage"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] uv-public-pypackage = { git = "https://github.com/astral-test/uv-public-pypackage", rev = "0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } "#, @@ -379,6 +395,10 @@ fn lock_sdist_git() -> Result<()> { requires-python = ">=3.12" dependencies = ["uv-public-pypackage"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] uv-public-pypackage = { git = "https://github.com/astral-test/uv-public-pypackage", rev = "b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" } "#, @@ -435,6 +455,10 @@ fn lock_sdist_git() -> Result<()> { requires-python = ">=3.12" dependencies = ["uv-public-pypackage"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] uv-public-pypackage = { git = "https://github.com/astral-test/uv-public-pypackage", tag = "0.0.2" } "#, @@ -498,6 +522,10 @@ fn lock_sdist_git_subdirectory() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["example-pkg-a @ git+https://github.com/pypa/sample-namespace-packages.git@df7530eeb8fa0cb7dbb8ecb28363e8e36bfa2f45#subdirectory=pkg_resources/pkg_a"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -582,6 +610,10 @@ fn lock_sdist_git_pep508() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage.git@0.0.1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -645,6 +677,10 @@ fn lock_sdist_git_pep508() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage.git@0dacfd662c64cb4ceb16e6cf65a157a8b715b979"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -698,6 +734,10 @@ fn lock_sdist_git_pep508() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage.git@b270df1a2fb5d012294e9aaf05e7e0bab1e6a389"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -751,6 +791,10 @@ fn lock_sdist_git_pep508() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage.git@0.0.2"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -813,6 +857,10 @@ fn lock_sdist_git_short_rev() -> Result<()> { requires-python = ">=3.12" dependencies = ["uv-public-pypackage"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] uv-public-pypackage = { git = "https://github.com/astral-test/uv-public-pypackage", rev = "0dacfd6" } "#, @@ -909,6 +957,10 @@ fn lock_wheel_url() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio @ https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -1052,6 +1104,10 @@ fn lock_sdist_url() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -1183,6 +1239,10 @@ fn lock_project_extra() -> Result<()> { requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [project.optional-dependencies] test = ["iniconfig"] "#, @@ -1325,6 +1385,10 @@ fn lock_project_with_overrides() -> Result<()> { requires-python = ">=3.12" dependencies = ["flask==3.0.0"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] override-dependencies = ["werkzeug==2.3.8"] "#, @@ -1371,7 +1435,7 @@ fn lock_project_with_overrides() -> Result<()> { Ok(()) } -/// Lock a project with a uv.tool.constraint-dependencies. +/// Lock a project with `uv.tool.constraint-dependencies`. #[test] fn lock_project_with_constraints() -> Result<()> { let context = TestContext::new("3.12"); @@ -1385,6 +1449,10 @@ fn lock_project_with_constraints() -> Result<()> { requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] constraint-dependencies = ["idna<3.4"] "#, @@ -1440,6 +1508,10 @@ fn lock_dependency_extra() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["flask[dotenv]"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -1636,6 +1708,10 @@ fn lock_conditional_dependency_extra() -> Result<()> { version = "0.1.0" requires-python = ">=3.7" dependencies = ["requests", "requests[socks] ; python_version < '3.10'"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -1918,6 +1994,10 @@ fn lock_dependency_non_existent_extra() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["flask[foo]"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2100,6 +2180,10 @@ fn lock_upgrade_log() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["markupsafe<2", "iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2177,6 +2261,10 @@ fn lock_upgrade_log() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["markupsafe", "typing-extensions"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2268,6 +2356,10 @@ fn lock_upgrade_log_multi_version() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["markupsafe<2 ; sys_platform != 'win32'", "markupsafe==2.0.0 ; sys_platform == 'win32'"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2351,6 +2443,10 @@ fn lock_upgrade_log_multi_version() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["markupsafe"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2426,6 +2522,10 @@ fn lock_preference() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig<2"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2482,6 +2582,10 @@ fn lock_preference() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2597,6 +2701,10 @@ fn lock_git_sha() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage@main"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2636,6 +2744,10 @@ fn lock_git_sha() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage@main"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2712,6 +2824,10 @@ fn lock_requires_python() -> Result<()> { version = "0.1.0" requires-python = ">=3.7" dependencies = ["pygls>=1.1.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2748,6 +2864,10 @@ fn lock_requires_python() -> Result<()> { version = "0.1.0" requires-python = ">=3.7" dependencies = ["pygls"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -2899,6 +3019,10 @@ fn lock_requires_python() -> Result<()> { version = "0.1.0" requires-python = ">=3.7.9" dependencies = ["pygls"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -3040,6 +3164,10 @@ fn lock_requires_python() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["pygls"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -3180,6 +3308,10 @@ fn lock_requires_python_wheels() -> Result<()> { version = "0.1.0" requires-python = "==3.12.*" dependencies = ["frozenlist"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -3263,6 +3395,10 @@ fn lock_requires_python_wheels() -> Result<()> { version = "0.1.0" requires-python = "==3.11.*" dependencies = ["frozenlist"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -3372,6 +3508,10 @@ fn lock_requires_python_star() -> Result<()> { version = "0.1.0" requires-python = "==3.11.*" dependencies = ["linehaul"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -3494,6 +3634,10 @@ fn lock_requires_python_pre() -> Result<()> { version = "0.1.0" requires-python = ">=3.11b1" dependencies = ["linehaul"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -3614,6 +3758,10 @@ fn lock_requires_python_unbounded() -> Result<()> { version = "0.1.0" requires-python = "<=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -3815,6 +3963,10 @@ fn lock_dev() -> Result<()> { [tool.uv] dev-dependencies = ["typing-extensions @ https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -3929,6 +4081,10 @@ fn lock_conditional_unconditional() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig", "iniconfig ; python_version < '3.12'"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -4006,6 +4162,10 @@ fn lock_multiple_markers() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig ; implementation_name == 'cpython'", "iniconfig ; python_version < '3.12'"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -4088,8 +4248,8 @@ fn lock_relative_and_absolute_paths() -> Result<()> { c = {{ path = '{}' }} [build-system] - requires = ["hatchling"] - build-backend = "hatchling.build" + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, context.temp_dir.join("c").display() })?; @@ -4106,8 +4266,9 @@ fn lock_relative_and_absolute_paths() -> Result<()> { license = {text = "MIT"} [build-system] - requires = ["hatchling"] - build-backend = "hatchling.build" + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + "#})?; context.temp_dir.child("b/b/__init__.py").touch()?; context @@ -4122,8 +4283,9 @@ fn lock_relative_and_absolute_paths() -> Result<()> { license = {text = "MIT"} [build-system] - requires = ["hatchling"] - build-backend = "hatchling.build" + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + "#})?; context.temp_dir.child("c/c/__init__.py").touch()?; @@ -4203,6 +4365,10 @@ fn lock_cycles() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["testtools==2.3.0", "fixtures==3.0.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -4406,6 +4572,11 @@ fn lock_new_extras() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["requests==2.31.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + "#, )?; @@ -4529,6 +4700,11 @@ fn lock_new_extras() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["requests[socks]==2.31.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + "#, )?; @@ -4677,6 +4853,10 @@ fn lock_invalid_hash() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -4773,6 +4953,10 @@ fn lock_resolution_mode() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio>=3"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -4951,6 +5135,10 @@ fn lock_requires_python_no_wheels() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["dearpygui==1.9.1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -4983,6 +5171,10 @@ fn lock_same_version_multiple_urls() -> Result<()> { version = "0.0.1" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -4996,6 +5188,10 @@ fn lock_same_version_multiple_urls() -> Result<()> { version = "0.0.1" requires-python = ">=3.12" dependencies = ["anyio==3.0.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -5168,6 +5364,10 @@ fn lock_unsafe_lowest() -> Result<()> { [project.optional-dependencies] dev = ["iniconfig"] all = ["project[dev]"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -5207,6 +5407,10 @@ fn lock_exclusion() -> Result<()> { requires-python = ">=3.12" dependencies = [] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = [] exclude = ["child"] @@ -5225,6 +5429,10 @@ fn lock_exclusion() -> Result<()> { requires-python = ">=3.12" dependencies = ["project"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] project = { path = ".." } "#, @@ -5305,6 +5513,10 @@ fn lock_dev_transitive() -> Result<()> { [tool.uv] dev-dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -5320,6 +5532,10 @@ fn lock_dev_transitive() -> Result<()> { requires-python = ">=3.12" dependencies = ["foo", "baz", "iniconfig>1"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] foo = { path = "../foo" } baz = { workspace = true } @@ -5341,6 +5557,10 @@ fn lock_dev_transitive() -> Result<()> { requires-python = ">=3.12" dependencies = [] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] dev-dependencies = ["typing-extensions>4"] "#, @@ -5464,6 +5684,10 @@ fn lock_redact_https() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -5610,6 +5834,10 @@ fn lock_redact_https() -> Result<()> { requires-python = ">=3.12" dependencies = ["iniconfig"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] index-url = "https://public:heron@pypi-proxy.fly.dev/basic-auth/simple" "#, @@ -5652,6 +5880,10 @@ fn lock_redact_git() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["uv-private-pypackage @ git+https://{token}@github.com/astral-test/uv-private-pypackage"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, token = token, })?; @@ -5737,6 +5969,10 @@ fn lock_relative_index() -> Result<()> { requires-python = ">=3.12" dependencies = ["iniconfig"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] index-url = "https://pypi-proxy.fly.dev/relative/simple" "#, @@ -5826,6 +6062,11 @@ fn lock_no_sources() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] anyio = { path = "./anyio" } "#, @@ -5842,6 +6083,10 @@ fn lock_no_sources() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -6010,6 +6255,10 @@ fn lock_migrate() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -6152,6 +6401,10 @@ fn lock_upgrade_package() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio<=2", "idna<=3"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -6246,6 +6499,10 @@ fn lock_upgrade_package() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio", "idna"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -6428,6 +6685,10 @@ fn lock_upgrade_drop_fork_markers() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["fork-upgrade-foo==1"] + + [build-system] + requires = ["flit_core>=3.8,<4"] + build-backend = "flit_core.buildapi" "#; let pyproject_toml = context.temp_dir.child("pyproject.toml"); @@ -6470,6 +6731,10 @@ fn lock_warn_missing_transitive_lower_bounds() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["pytest>8"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -6522,6 +6787,10 @@ fn lock_find_links_local_wheel() -> Result<()> { requires-python = ">=3.12" dependencies = ["tqdm==1000.0.0"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] find-links = ["{}"] "#, @@ -6636,6 +6905,10 @@ fn lock_find_links_local_sdist() -> Result<()> { requires-python = ">=3.12" dependencies = ["tqdm==999.0.0"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] find-links = ["{}"] "#, @@ -6727,6 +7000,10 @@ fn lock_find_links_http_wheel() -> Result<()> { requires-python = ">=3.12" dependencies = ["packaging==23.2"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] find-links = ["{}"] no-build-package = ["packaging"] @@ -6818,6 +7095,10 @@ fn lock_find_links_http_sdist() -> Result<()> { requires-python = ">=3.12" dependencies = ["packaging==23.2"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] find-links = ["{}"] no-binary-package = ["packaging"] @@ -6944,6 +7225,10 @@ fn lock_local_index() -> Result<()> { requires-python = ">=3.12" dependencies = ["tqdm"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] extra-index-url = ["{}"] "#, @@ -7040,6 +7325,10 @@ fn lock_sources_url() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["workspace @ https://github.com/user-attachments/files/16592193/workspace.zip"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -7175,6 +7464,10 @@ fn lock_sources_archive() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["workspace @ {}"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, Url::from_file_path(&workspace_archive).unwrap(), })?; @@ -7425,6 +7718,10 @@ fn lock_editable() -> Result<()> { dependencies = ["library"] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] library = { path = "./library" } @@ -7441,6 +7738,10 @@ fn lock_editable() -> Result<()> { version = "0.1.0" dependencies = ["library"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] library = { path = "../../library" } "#})?; @@ -7532,6 +7833,10 @@ fn lock_editable() -> Result<()> { version = "0.1.0" dependencies = ["library"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] library = { path = "../../library", editable = true } "#})?; @@ -7635,6 +7940,10 @@ fn lock_mixed_extras() -> Result<()> { requires-python = ">=3.12" dependencies = ["leaf1", "workspace2"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [project.optional-dependencies] async = ["typing-extensions>=4"] @@ -7657,6 +7966,10 @@ fn lock_mixed_extras() -> Result<()> { [project.optional-dependencies] async = ["iniconfig>=2"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; leaf1.child("src/__init__.py").touch()?; @@ -7669,6 +7982,10 @@ fn lock_mixed_extras() -> Result<()> { requires-python = ">=3.12" dependencies = ["leaf2"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] leaf2 = { workspace = true } @@ -7687,6 +8004,10 @@ fn lock_mixed_extras() -> Result<()> { [project.optional-dependencies] async = ["packaging>=24"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; leaf2.child("src/__init__.py").touch()?; @@ -7855,6 +8176,10 @@ fn lock_transitive_extra() -> Result<()> { requires-python = ">=3.12" dependencies = ["leaf"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [project.optional-dependencies] async = ["typing-extensions>=4", "leaf[async]"] @@ -7877,6 +8202,10 @@ fn lock_transitive_extra() -> Result<()> { [project.optional-dependencies] async = ["iniconfig>=2"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; leaf.child("src/__init__.py").touch()?; @@ -8060,9 +8389,11 @@ fn lock_mismatched_versions() -> Result<()> { name = "project" version = "0.1.0" requires-python = ">=3.12" - dependencies = [ - "uv-public-pypackage==0.0.2", - ] + dependencies = ["uv-public-pypackage==0.0.2"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" [tool.uv.sources] uv-public-pypackage = { git = "https://github.com/astral-test/uv-public-pypackage", tag = "0.0.1" } @@ -8153,6 +8484,10 @@ fn unconditional_overlapping_marker_disjoint_version_constraints() -> Result<()> "datasets < 2.19", "datasets >= 2.19 ; python_version > '3.10'" ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -8182,6 +8517,10 @@ fn lock_change_index() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -8304,6 +8643,10 @@ fn lock_remove_member() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio>3"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -8316,6 +8659,10 @@ fn lock_remove_member() -> Result<()> { requires-python = ">=3.12" dependencies = ["leaf"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["leaf"] @@ -8497,6 +8844,10 @@ fn lock_add_member() -> Result<()> { requires-python = ">=3.12" dependencies = [] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = [] "#, @@ -8551,6 +8902,10 @@ fn lock_add_member() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio>3"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -8563,6 +8918,10 @@ fn lock_add_member() -> Result<()> { requires-python = ">=3.12" dependencies = [] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["leaf"] "#, @@ -8706,6 +9065,10 @@ fn lock_redundant_add_member() -> Result<()> { requires-python = ">=3.12" dependencies = ["anyio"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = [] "#, @@ -8797,6 +9160,10 @@ fn lock_redundant_add_member() -> Result<()> { requires-python = ">=3.12" dependencies = ["anyio", "idna"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = [] "#, @@ -8903,6 +9270,10 @@ fn lock_new_constraints() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -8992,6 +9363,10 @@ fn lock_new_constraints() -> Result<()> { requires-python = ">=3.12" dependencies = ["anyio"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] constraint-dependencies = [ "anyio < 4.3", @@ -9097,6 +9472,10 @@ fn lock_remove_member_virtual() -> Result<()> { r#" [tool.uv.workspace] members = ["leaf"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -9109,6 +9488,10 @@ fn lock_remove_member_virtual() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio>3"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -9261,6 +9644,10 @@ fn lock_rename_project() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -9327,6 +9714,10 @@ fn lock_rename_project() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -9405,6 +9796,10 @@ fn lock_missing_metadata() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -9543,6 +9938,10 @@ fn lock_reorder() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio", "iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -9644,6 +10043,10 @@ fn lock_reorder() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig", "anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -9672,6 +10075,10 @@ fn lock_narrowed_python_version() -> Result<()> { version = "0.1.0" requires-python = ">=3.7" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -9683,6 +10090,11 @@ fn lock_narrowed_python_version() -> Result<()> { version = "0.1.0" requires-python = ">=3.7" dependencies = ["dependency ; python_version < '3.9'", "dependency ; python_version > '3.10'"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] dependency = { path = "./dependency" } "#, @@ -9787,8 +10199,8 @@ fn lock_exclude_unnecessary_python_forks() -> Result<()> { "anyio ; python_version > '3.10'" ] [build-system] - requires = ["hatchling"] - build-backend = "hatchling.build" + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -9893,6 +10305,10 @@ fn lock_constrained_environment() -> Result<()> { requires-python = ">=3.12" dependencies = ["black"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] environments = "platform_system != 'Windows'" "#, @@ -10037,6 +10453,10 @@ fn lock_constrained_environment() -> Result<()> { requires-python = ">=3.12" dependencies = ["black"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] environments = ["platform_system != 'Windows'"] "#, @@ -10061,6 +10481,10 @@ fn lock_constrained_environment() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["black"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -10209,6 +10633,10 @@ fn lock_overlapping_environment() -> Result<()> { requires-python = ">=3.8" dependencies = ["black"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] environments = ["platform_system != 'Windows'", "python_version > '3.10'"] "#, @@ -10429,9 +10857,7 @@ fn lock_virtual_conditional() -> Result<()> { members = [] [tool.uv] - dev-dependencies = [ - "anyio > 3 ; sys_platform == 'linux'", - ] + dev-dependencies = ["anyio > 3 ; sys_platform == 'linux'"] "#, )?; @@ -10531,10 +10957,12 @@ fn lock_dropped_dev_extra() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] - dev-dependencies = [ - "coverage[toml]" - ] + dev-dependencies = ["coverage[toml]"] "#, )?; @@ -10647,6 +11075,10 @@ fn lock_trailing_slash() -> Result<()> { requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] index-url = "https://pypi.org/simple/" "#, @@ -10757,3 +11189,439 @@ fn lock_trailing_slash() -> Result<()> { Ok(()) } + +/// Lock a project with `virtual = true`. +#[test] +fn lock_explicit_virtual_project() -> 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 = ["black"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] + virtual = true + dev-dependencies = [ + "anyio" + ] + "#, + )?; + + uv_snapshot!(context.filters(), context.lock(), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 11 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" + + [options] + exclude-newer = "2024-03-25T00:00:00Z" + + [[package]] + 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 }, + ] + + [[package]] + name = "black" + version = "24.3.0" + source = { registry = "https://pypi.org/simple" } + dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + ] + sdist = { url = "https://files.pythonhosted.org/packages/8f/5f/bac24a952668c7482cfdb4ebf91ba57a796c9da8829363a772040c1a3312/black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f", size = 634292 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/c6/1d174efa9ff02b22d0124c73fc5f4d4fb006d0d9a081aadc354d05754a13/black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f", size = 1600822 }, + { url = "https://files.pythonhosted.org/packages/d9/ed/704731afffe460b8ff0672623b40fce9fe569f2ee617c15857e4d4440a3a/black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11", size = 1429987 }, + { url = "https://files.pythonhosted.org/packages/a8/05/8dd038e30caadab7120176d4bc109b7ca2f4457f12eef746b0560a583458/black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4", size = 1755319 }, + { url = "https://files.pythonhosted.org/packages/71/9d/e5fa1ff4ef1940be15a64883c0bb8d2fcf626efec996eab4ae5a8c691d2c/black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5", size = 1385180 }, + { url = "https://files.pythonhosted.org/packages/4d/ea/31770a7e49f3eedfd8cd7b35e78b3a3aaad860400f8673994bc988318135/black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93", size = 201493 }, + ] + + [[package]] + name = "click" + version = "8.1.7" + source = { registry = "https://pypi.org/simple" } + dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, + ] + sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, + ] + + [[package]] + name = "colorama" + version = "0.4.6" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + ] + + [[package]] + 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 }, + ] + + [[package]] + name = "mypy-extensions" + version = "1.0.0" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, + ] + + [[package]] + name = "packaging" + version = "24.0" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/ee/b5/b43a27ac7472e1818c4bafd44430e69605baefe1f34440593e0332ec8b4d/packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9", size = 147882 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", size = 53488 }, + ] + + [[package]] + name = "pathspec" + version = "0.12.1" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, + ] + + [[package]] + name = "platformdirs" + version = "4.2.0" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/96/dc/c1d911bf5bb0fdc58cc05010e9f3efe3b67970cef779ba7fbc3183b987a8/platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768", size = 20055 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/55/72/4898c44ee9ea6f43396fbc23d9bfaf3d06e01b83698bdf2e4c919deceb7c/platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", size = 17717 }, + ] + + [[package]] + name = "project" + version = "0.1.0" + source = { editable = "." } + dependencies = [ + { name = "black" }, + ] + + [package.dev-dependencies] + dev = [ + { name = "anyio" }, + ] + + [package.metadata] + requires-dist = [{ name = "black" }] + + [package.metadata.requires-dev] + dev = [{ name = "anyio" }] + + [[package]] + 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 }, + ] + "### + ); + }); + + // Re-run with `--locked`. + uv_snapshot!(context.filters(), context.lock().arg("--locked"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 11 packages in [TIME] + "###); + + // Re-run with `--offline`. We shouldn't need a network connection to validate an + // already-correct lockfile with immutable metadata. + uv_snapshot!(context.filters(), context.lock().arg("--locked").arg("--offline").arg("--no-cache"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 11 packages in [TIME] + "###); + + // Install from the lockfile. The virtual project should _not_ be installed. + uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Prepared 9 packages in [TIME] + Installed 9 packages in [TIME] + + anyio==4.3.0 + + black==24.3.0 + + click==8.1.7 + + idna==3.6 + + mypy-extensions==1.0.0 + + packaging==24.0 + + pathspec==0.12.1 + + platformdirs==4.2.0 + + sniffio==1.3.1 + "###); + + Ok(()) +} + +/// Lock a project that is implicitly virtual (by way of omitting `build-system`0> +#[test] +fn lock_implicit_virtual_project() -> 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 = ["black"] + [tool.uv] + dev-dependencies = [ + "anyio" + ] + "#, + )?; + + uv_snapshot!(context.filters(), context.lock(), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 11 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" + + [options] + exclude-newer = "2024-03-25T00:00:00Z" + + [[package]] + 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 }, + ] + + [[package]] + name = "black" + version = "24.3.0" + source = { registry = "https://pypi.org/simple" } + dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + ] + sdist = { url = "https://files.pythonhosted.org/packages/8f/5f/bac24a952668c7482cfdb4ebf91ba57a796c9da8829363a772040c1a3312/black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f", size = 634292 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/c6/1d174efa9ff02b22d0124c73fc5f4d4fb006d0d9a081aadc354d05754a13/black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f", size = 1600822 }, + { url = "https://files.pythonhosted.org/packages/d9/ed/704731afffe460b8ff0672623b40fce9fe569f2ee617c15857e4d4440a3a/black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11", size = 1429987 }, + { url = "https://files.pythonhosted.org/packages/a8/05/8dd038e30caadab7120176d4bc109b7ca2f4457f12eef746b0560a583458/black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4", size = 1755319 }, + { url = "https://files.pythonhosted.org/packages/71/9d/e5fa1ff4ef1940be15a64883c0bb8d2fcf626efec996eab4ae5a8c691d2c/black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5", size = 1385180 }, + { url = "https://files.pythonhosted.org/packages/4d/ea/31770a7e49f3eedfd8cd7b35e78b3a3aaad860400f8673994bc988318135/black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93", size = 201493 }, + ] + + [[package]] + name = "click" + version = "8.1.7" + source = { registry = "https://pypi.org/simple" } + dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, + ] + sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, + ] + + [[package]] + name = "colorama" + version = "0.4.6" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + ] + + [[package]] + 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 }, + ] + + [[package]] + name = "mypy-extensions" + version = "1.0.0" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, + ] + + [[package]] + name = "packaging" + version = "24.0" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/ee/b5/b43a27ac7472e1818c4bafd44430e69605baefe1f34440593e0332ec8b4d/packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9", size = 147882 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", size = 53488 }, + ] + + [[package]] + name = "pathspec" + version = "0.12.1" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, + ] + + [[package]] + name = "platformdirs" + version = "4.2.0" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/96/dc/c1d911bf5bb0fdc58cc05010e9f3efe3b67970cef779ba7fbc3183b987a8/platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768", size = 20055 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/55/72/4898c44ee9ea6f43396fbc23d9bfaf3d06e01b83698bdf2e4c919deceb7c/platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", size = 17717 }, + ] + + [[package]] + name = "project" + version = "0.1.0" + source = { editable = "." } + dependencies = [ + { name = "black" }, + ] + + [package.dev-dependencies] + dev = [ + { name = "anyio" }, + ] + + [package.metadata] + requires-dist = [{ name = "black" }] + + [package.metadata.requires-dev] + dev = [{ name = "anyio" }] + + [[package]] + 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 }, + ] + "### + ); + }); + + // Re-run with `--locked`. + uv_snapshot!(context.filters(), context.lock().arg("--locked"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 11 packages in [TIME] + "###); + + // Re-run with `--offline`. We shouldn't need a network connection to validate an + // already-correct lockfile with immutable metadata. + uv_snapshot!(context.filters(), context.lock().arg("--locked").arg("--offline").arg("--no-cache"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 11 packages in [TIME] + "###); + + // Install from the lockfile. The virtual project should _not_ be installed. + uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Prepared 9 packages in [TIME] + Installed 9 packages in [TIME] + + anyio==4.3.0 + + black==24.3.0 + + click==8.1.7 + + idna==3.6 + + mypy-extensions==1.0.0 + + packaging==24.0 + + pathspec==0.12.1 + + platformdirs==4.2.0 + + sniffio==1.3.1 + "###); + + Ok(()) +} diff --git a/crates/uv/tests/run.rs b/crates/uv/tests/run.rs index d6e04fa99f016..6e0f59858d691 100644 --- a/crates/uv/tests/run.rs +++ b/crates/uv/tests/run.rs @@ -27,6 +27,10 @@ fn run_with_python_version() -> Result<()> { "anyio==3.6.0 ; python_version == '3.11'", "anyio==3.7.0 ; python_version == '3.12'", ] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; let test_script = context.temp_dir.child("main.py"); @@ -146,6 +150,10 @@ fn run_args() -> Result<()> { version = "1.0.0" requires-python = ">=3.8" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -201,6 +209,10 @@ fn run_pep723_script() -> Result<()> { version = "1.0.0" requires-python = ">=3.8" dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -363,6 +375,10 @@ fn run_pythonw_script() -> Result<()> { version = "1.0.0" requires-python = ">=3.8" dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -473,6 +489,10 @@ fn run_managed_false() -> Result<()> { requires-python = ">=3.8" dependencies = ["anyio"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] managed = false "# @@ -501,6 +521,10 @@ fn run_with() -> Result<()> { version = "1.0.0" requires-python = ">=3.8" dependencies = ["anyio", "sniffio==1.3.1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -597,6 +621,10 @@ fn run_with_editable() -> Result<()> { version = "1.0.0" requires-python = ">=3.8" dependencies = ["anyio", "sniffio==1.3.1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -660,6 +688,10 @@ fn run_with_editable() -> Result<()> { requires-python = ">=3.8" dependencies = ["anyio", "sniffio==1.3.1"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] anyio = { path = "./src/anyio_local", editable = true } "# @@ -719,6 +751,10 @@ fn run_locked() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -745,6 +781,10 @@ fn run_locked() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -797,6 +837,10 @@ fn run_frozen() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -820,6 +864,10 @@ fn run_frozen() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -853,6 +901,10 @@ fn run_empty_requirements_txt() -> Result<()> { version = "1.0.0" requires-python = ">=3.8" dependencies = ["anyio", "sniffio==1.3.1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -909,6 +961,10 @@ fn run_requirements_txt() -> Result<()> { version = "1.0.0" requires-python = ">=3.8" dependencies = ["anyio", "sniffio==1.3.1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -1024,6 +1080,10 @@ fn run_requirements_txt_arguments() -> Result<()> { version = "1.0.0" requires-python = ">=3.8" dependencies = ["typing_extensions"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -1069,15 +1129,15 @@ fn run_editable() -> Result<()> { let pyproject_toml = context.temp_dir.child("pyproject.toml"); pyproject_toml.write_str(indoc! { r#" - [build-system] - requires = ["hatchling"] - build-backend = "hatchling.build" - [project] name = "foo" version = "1.0.0" requires-python = ">=3.8" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -1136,6 +1196,10 @@ fn run_from_directory() -> Result<()> { [project.scripts] main = "main:main" + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; let main_script = project_dir.child("main.py"); @@ -1180,6 +1244,10 @@ fn run_without_output() -> Result<()> { version = "1.0.0" requires-python = ">=3.8" dependencies = ["anyio", "sniffio==1.3.1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -1219,15 +1287,15 @@ fn run_isolated_python_version() -> Result<()> { let pyproject_toml = context.temp_dir.child("pyproject.toml"); pyproject_toml.write_str(indoc! { r#" - [build-system] - requires = ["hatchling"] - build-backend = "hatchling.build" - [project] name = "foo" version = "1.0.0" requires-python = ">=3.8" dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; @@ -1318,15 +1386,15 @@ fn run_no_project() -> Result<()> { let pyproject_toml = context.temp_dir.child("pyproject.toml"); pyproject_toml.write_str(indoc! { r#" - [build-system] - requires = ["hatchling"] - build-backend = "hatchling.build" - [project] name = "foo" version = "1.0.0" requires-python = ">=3.8" dependencies = ["anyio"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "# })?; diff --git a/crates/uv/tests/sync.rs b/crates/uv/tests/sync.rs index 28752eead06b9..ffc8e114a5a5c 100644 --- a/crates/uv/tests/sync.rs +++ b/crates/uv/tests/sync.rs @@ -21,6 +21,10 @@ fn sync() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -55,6 +59,10 @@ fn locked() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -81,6 +89,10 @@ fn locked() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -115,6 +127,10 @@ fn frozen() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -138,6 +154,10 @@ fn frozen() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -212,6 +232,10 @@ fn package() -> Result<()> { requires-python = ">=3.12" dependencies = ["child", "anyio>3"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] child = { workspace = true } @@ -237,6 +261,10 @@ fn package() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig>1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -312,6 +340,10 @@ fn mixed_requires_python() -> Result<()> { name = "bird-feeder" version = "0.1.0" requires-python = ">=3.8" + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -381,6 +413,10 @@ fn virtual_workspace_dev_dependencies() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["iniconfig>1"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -441,6 +477,10 @@ fn sync_build_isolation() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["source-distribution @ https://files.pythonhosted.org/packages/10/1f/57aa4cce1b1abf6b433106676e15f9fa2c92ed2bd4cf77c3b50a9e9ac773/source_distribution-0.0.1.tar.gz"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -877,6 +917,10 @@ fn sync_environment() -> Result<()> { requires-python = ">=3.10" dependencies = ["iniconfig"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] environments = ["python_version < '3.11'"] "#, @@ -916,6 +960,10 @@ fn read_metadata_statically_over_the_cache() -> Result<()> { requires-python = ">=3.12" # Python string sorting is the other way round. dependencies = ["anyio>=4,<5"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -945,6 +993,10 @@ fn no_install_project() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; @@ -996,6 +1048,10 @@ fn no_install_workspace() -> Result<()> { requires-python = ">=3.12" dependencies = ["anyio==3.7.0", "child"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["child"] @@ -1015,8 +1071,8 @@ fn no_install_workspace() -> Result<()> { dependencies = ["iniconfig>1"] [build-system] - requires = ["hatchling"] - build-backend = "hatchling.build" + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; child @@ -1073,6 +1129,10 @@ fn no_install_package() -> Result<()> { version = "0.1.0" requires-python = ">=3.12" dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#, )?; diff --git a/crates/uv/tests/workspace.rs b/crates/uv/tests/workspace.rs index b3607331d2795..7f452ba05a6f8 100644 --- a/crates/uv/tests/workspace.rs +++ b/crates/uv/tests/workspace.rs @@ -965,6 +965,10 @@ fn workspace_inherit_sources() -> Result<()> { dependencies = [] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["packages/*"] "#})?; @@ -977,6 +981,10 @@ fn workspace_inherit_sources() -> Result<()> { name = "leaf" version = "0.1.0" dependencies = ["library"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; leaf.child("src/__init__.py").touch()?; @@ -987,6 +995,10 @@ fn workspace_inherit_sources() -> Result<()> { name = "library" version = "0.1.0" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; library.child("src/__init__.py").touch()?; @@ -1013,6 +1025,10 @@ fn workspace_inherit_sources() -> Result<()> { version = "0.1.0" dependencies = ["library"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] library = { path = "../../../library", editable = true } "#})?; @@ -1036,6 +1052,10 @@ fn workspace_inherit_sources() -> Result<()> { name = "leaf" version = "0.1.0" dependencies = ["library"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; // Update the root to include the source. @@ -1046,6 +1066,10 @@ fn workspace_inherit_sources() -> Result<()> { dependencies = [] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] library = { path = "../library", editable = true } @@ -1117,6 +1141,10 @@ fn workspace_inherit_sources() -> Result<()> { dependencies = [] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] library = { path = "../library", editable = true } @@ -1131,9 +1159,12 @@ fn workspace_inherit_sources() -> Result<()> { version = "0.1.0" dependencies = ["library"] + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.sources] application = { path = "../application", editable = true } - "#})?; // Resolving should succeed; the member should still use the root's source, despite defining @@ -1167,6 +1198,10 @@ fn workspace_unsatisfiable_member_dependencies() -> Result<()> { dependencies = [] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["packages/*"] "#})?; @@ -1179,6 +1214,10 @@ fn workspace_unsatisfiable_member_dependencies() -> Result<()> { name = "leaf" version = "0.1.0" dependencies = ["httpx>9999"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; leaf.child("src/__init__.py").touch()?; @@ -1215,6 +1254,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting() -> Result<()> { dependencies = [] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["packages/*"] "#})?; @@ -1227,6 +1270,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting() -> Result<()> { name = "foo" version = "0.1.0" dependencies = ["anyio==4.1.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; foo.child("src/__init__.py").touch()?; let bar = workspace.child("packages").child("bar"); @@ -1235,6 +1282,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting() -> Result<()> { name = "bar" version = "0.1.0" dependencies = ["anyio==4.2.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; bar.child("src/__init__.py").touch()?; @@ -1271,6 +1322,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_threeway() -> Result< dependencies = [] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["packages/*"] "#})?; @@ -1283,6 +1338,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_threeway() -> Result< name = "red" version = "0.1.0" dependencies = ["anyio==4.1.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; red.child("src/__init__.py").touch()?; let knot = workspace.child("packages").child("knot"); @@ -1291,6 +1350,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_threeway() -> Result< name = "knot" version = "0.1.0" dependencies = ["anyio==4.2.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; knot.child("src/__init__.py").touch()?; @@ -1302,6 +1365,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_threeway() -> Result< name = "bird" version = "0.1.0" dependencies = ["anyio==4.3.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; bird.child("src/__init__.py").touch()?; @@ -1338,6 +1405,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_extra() -> Result<()> dependencies = [] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["packages/*"] "#})?; @@ -1350,6 +1421,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_extra() -> Result<()> name = "foo" version = "0.1.0" dependencies = ["anyio==4.1.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; foo.child("src/__init__.py").touch()?; let bar = workspace.child("packages").child("bar"); @@ -1360,6 +1435,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_extra() -> Result<()> [project.optional-dependencies] some_extra = ["anyio==4.2.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; bar.child("src/__init__.py").touch()?; @@ -1396,6 +1475,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_dev() -> Result<()> { dependencies = [] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["packages/*"] "#})?; @@ -1408,6 +1491,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_dev() -> Result<()> { name = "foo" version = "0.1.0" dependencies = ["anyio==4.1.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; foo.child("src/__init__.py").touch()?; let bar = workspace.child("packages").child("bar"); @@ -1416,6 +1503,10 @@ fn workspace_unsatisfiable_member_dependencies_conflicting_dev() -> Result<()> { name = "bar" version = "0.1.0" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv] dev-dependencies = ["anyio==4.2.0"] "#})?; @@ -1455,6 +1546,10 @@ fn workspace_member_name_shadows_dependencies() -> Result<()> { dependencies = [] requires-python = ">=3.12" + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" + [tool.uv.workspace] members = ["packages/*"] "#})?; @@ -1467,6 +1562,10 @@ fn workspace_member_name_shadows_dependencies() -> Result<()> { name = "foo" version = "0.1.0" dependencies = ["anyio==4.1.0"] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; foo.child("src/__init__.py").touch()?; @@ -1477,6 +1576,10 @@ fn workspace_member_name_shadows_dependencies() -> Result<()> { name = "anyio" version = "0.1.0" dependencies = [] + + [build-system] + requires = ["setuptools>=42", "wheel"] + build-backend = "setuptools.build_meta" "#})?; anyio.child("src/__init__.py").touch()?; diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 7d9644f6fc652..f05390cbe24e5 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -455,9 +455,11 @@ uv init [OPTIONS] [PATH]
--version, -V

Display the uv version

-
--virtual

Create a virtual workspace instead of a project.

+
--virtual

Create a virtual project, rather than a package.

-

A virtual workspace does not define project dependencies and cannot be published. Instead, workspace members declare project dependencies. Development dependencies may still be declared.

+

A virtual project is a project that is not intended to be built as a Python package, such as a project that only contains scripts or other application code.

+ +

Virtual projects themselves are not installed into the Python environment.

diff --git a/docs/reference/settings.md b/docs/reference/settings.md index fc9b11a629f55..9b8e599d9149b 100644 --- a/docs/reference/settings.md +++ b/docs/reference/settings.md @@ -1010,6 +1010,31 @@ those that are downloaded and installed by uv. --- +#### [`r#virtual`](#r#virtual) {: #r#virtual } + +Whether the project should be considered "virtual". + +**Default value**: `true` + +**Type**: `bool` + +**Example usage**: + +=== "pyproject.toml" + + ```toml + [tool.uv] + virtual = false + ``` +=== "uv.toml" + + ```toml + + virtual = false + ``` + +--- + #### [`reinstall`](#reinstall) {: #reinstall } Reinstall all packages, regardless of whether they're already installed. Implies `refresh`. diff --git a/uv.schema.json b/uv.schema.json index 2ba30d6e9d5ff..6518136176dc1 100644 --- a/uv.schema.json +++ b/uv.schema.json @@ -379,6 +379,13 @@ "$ref": "#/definitions/Requirement" } }, + "virtual": { + "description": "Whether the project should be considered \"virtual\".", + "type": [ + "boolean", + "null" + ] + }, "workspace": { "description": "The workspace definition for the project, if any.", "anyOf": [