diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 921f6d082..decd2b107 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -609,18 +609,22 @@ pub enum ProjectCommand { Remove(RemoveArgs), /// Update the project's environment. /// - /// Syncing ensures that all project dependencies are installed and - /// up-to-date with the lockfile. Syncing also removes packages that are not - /// declared as dependencies of the project. + /// Syncing ensures that all project dependencies are installed and up-to-date with the + /// lockfile. /// - /// If the project virtual environment (`.venv`) does not exist, it will be - /// created. + /// By default, an exact sync is performed: uv removes packages that are not declared as + /// dependencies of the project. Use the `--inexact` flag to keep extraneous packages. Note that + /// if an extraneous package conflicts with a project dependency, it will still be removed. + /// Additionally, if `--no-build-isolation` is used, uv will not remove extraneous packages to + /// avoid removing possible build dependencies. /// - /// The project is re-locked before syncing unless the `--locked` or - /// `--frozen` flag is provided. + /// If the project virtual environment (`.venv`) does not exist, it will be created. /// - /// uv will search for a project in the current directory or any parent - /// directory. If a project cannot be found, uv will exit with an error. + /// The project is re-locked before syncing unless the `--locked` or `--frozen` flag is + /// provided. + /// + /// uv will search for a project in the current directory or any parent directory. If a project + /// cannot be found, uv will exit with an error. /// /// Note that, when installing from a lockfile, uv will not provide warnings for yanked package /// versions. @@ -2247,16 +2251,19 @@ pub struct SyncArgs { #[arg(long, overrides_with("dev"))] pub no_dev: bool, - /// Do not remove extraneous packages. + /// Do not remove extraneous packages present in the environment. /// - /// When enabled, uv will make the minimum necessary changes to satisfy the - /// requirements. + /// When enabled, uv will make the minimum necessary changes to satisfy the requirements. /// - /// By default, syncing will remove any extraneous packages from the - /// environment, unless `--no-build-isolation` is enabled, in which case - /// extra packages are considered necessary for builds. - #[arg(long)] - pub no_clean: bool, + /// By default, syncing will remove any extraneous packages from the environment, unless + /// `--no-build-isolation` is enabled, in which case extra packages are considered necessary for + /// builds. + #[arg(long, overrides_with("exact"), alias = "no-exact")] + pub inexact: bool, + + /// Perform an exact sync, removing extraneous packages. + #[arg(long, overrides_with("inexact"), hide = true)] + pub exact: bool, /// Assert that the `uv.lock` will remain unchanged. /// diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 5e052c37e..e472c3887 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -627,7 +627,8 @@ impl SyncSettings { no_all_extras, dev, no_dev, - no_clean, + inexact, + exact, installer, build, refresh, @@ -640,9 +641,11 @@ impl SyncSettings { filesystem, ); + let exact = flag(exact, inexact).unwrap_or(true); + // By default, sync with exact semantics, unless the user set `--no-build-isolation`; // otherwise, we'll end up removing build dependencies. - let modifications = if no_clean || settings.no_build_isolation { + let modifications = if !exact || settings.no_build_isolation { Modifications::Sufficient } else { Modifications::Exact diff --git a/crates/uv/tests/edit.rs b/crates/uv/tests/edit.rs index 01ca83f83..df34abc3c 100644 --- a/crates/uv/tests/edit.rs +++ b/crates/uv/tests/edit.rs @@ -2187,9 +2187,9 @@ fn update_source_replace_url() -> Result<()> { Ok(()) } -/// Adding a dependency does not clean the environment. +/// Adding a dependency does not remove untracked dependencies from the environment. #[test] -fn add_no_clean() -> Result<()> { +fn add_inexact() -> Result<()> { let context = TestContext::new("3.12"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); @@ -2303,8 +2303,8 @@ fn add_no_clean() -> Result<()> { ); }); - // Install from the lockfile without cleaning the environment. - uv_snapshot!(context.filters(), context.sync().arg("--frozen").arg("--no-clean"), @r###" + // Install from the lockfile without removing extraneous packages from the environment. + uv_snapshot!(context.filters(), context.sync().arg("--frozen").arg("--inexact"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -2313,7 +2313,7 @@ fn add_no_clean() -> Result<()> { Audited 2 packages in [TIME] "###); - // Install from the lockfile, cleaning the environment. + // Install from the lockfile, performing an exact sync. uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###" success: true exit_code: 0 diff --git a/crates/uv/tests/lock.rs b/crates/uv/tests/lock.rs index 167682667..4d2ebe05b 100644 --- a/crates/uv/tests/lock.rs +++ b/crates/uv/tests/lock.rs @@ -9704,7 +9704,6 @@ fn lock_constrained_environment() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: `uv lock` is experimental and may change without warning Resolved 7 packages in [TIME] "###); @@ -9726,7 +9725,7 @@ fn lock_constrained_environment() -> Result<()> { ] [options] - exclude-newer = "2024-03-25 00:00:00 UTC" + exclude-newer = "2024-03-25T00:00:00Z" [[package]] name = "black" @@ -9814,7 +9813,6 @@ fn lock_constrained_environment() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: `uv lock` is experimental and may change without warning Resolved 7 packages in [TIME] "###); @@ -9826,7 +9824,6 @@ fn lock_constrained_environment() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: `uv lock` is experimental and may change without warning Resolved 7 packages in [TIME] "###); @@ -9852,7 +9849,6 @@ fn lock_constrained_environment() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: `uv lock` is experimental and may change without warning Resolved 7 packages in [TIME] "###); @@ -9875,7 +9871,6 @@ fn lock_constrained_environment() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: `uv lock` is experimental and may change without warning Ignoring existing lockfile due to change in supported environments Resolved 8 packages in [TIME] error: The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`. @@ -9887,7 +9882,6 @@ fn lock_constrained_environment() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: `uv lock` is experimental and may change without warning Ignoring existing lockfile due to change in supported environments Resolved 8 packages in [TIME] Added colorama v0.4.6 @@ -9905,7 +9899,7 @@ fn lock_constrained_environment() -> Result<()> { requires-python = ">=3.12" [options] - exclude-newer = "2024-03-25 00:00:00 UTC" + exclude-newer = "2024-03-25T00:00:00Z" [[package]] name = "black" @@ -10026,7 +10020,6 @@ fn lock_overlapping_environment() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: `uv lock` is experimental and may change without warning error: Supported environments must be disjoint, but the following markers overlap: `platform_system != 'Windows'` and `python_full_version >= '3.11'`. hint: replace `python_full_version >= '3.11'` with `python_full_version >= '3.11' and platform_system == 'Windows'`. diff --git a/crates/uv/tests/sync.rs b/crates/uv/tests/sync.rs index 8511bab67..54c76c224 100644 --- a/crates/uv/tests/sync.rs +++ b/crates/uv/tests/sync.rs @@ -783,7 +783,6 @@ fn sync_environment() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: `uv sync` is experimental and may change without warning Resolved 2 packages in [TIME] error: The current Python platform is not compatible with the lockfile's supported environments: `python_full_version < '3.11'` "###); diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 11e27ff0a..a97877ae1 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -999,7 +999,9 @@ uv remove [OPTIONS] ... Update the project's environment. -Syncing ensures that all project dependencies are installed and up-to-date with the lockfile. Syncing also removes packages that are not declared as dependencies of the project. +Syncing ensures that all project dependencies are installed and up-to-date with the lockfile. + +By default, an exact sync is performed: uv removes packages that are not declared as dependencies of the project. Use the `--inexact` flag to keep extraneous packages. Note that if an extraneous package conflicts with a project dependency, it will still be removed. Additionally, if `--no-build-isolation` is used, uv will not remove extraneous packages to avoid removing possible build dependencies. If the project virtual environment (`.venv`) does not exist, it will be created. @@ -1092,6 +1094,12 @@ uv sync [OPTIONS]

The index given by this flag is given lower priority than all other indexes specified via the --extra-index-url flag.

+
--inexact

Do not remove extraneous packages present in the environment.

+ +

When enabled, uv will make the minimum necessary changes to satisfy the requirements.

+ +

By default, syncing will remove any extraneous packages from the environment, unless --no-build-isolation is enabled, in which case extra packages are considered necessary for builds.

+
--keyring-provider keyring-provider

Attempt to use keyring for authentication for index URLs.

At present, only --keyring-provider subprocess is supported, which configures uv to use the keyring CLI to handle authentication.

@@ -1152,12 +1160,6 @@ uv sync [OPTIONS]
--no-cache, -n

Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation

-
--no-clean

Do not remove extraneous packages.

- -

When enabled, uv will make the minimum necessary changes to satisfy the requirements.

- -

By default, syncing will remove any extraneous packages from the environment, unless --no-build-isolation is enabled, in which case extra packages are considered necessary for builds.

-
--no-config

Avoid discovering configuration files (pyproject.toml, uv.toml).

Normally, configuration files are discovered in the current directory, parent directories, or user configuration directories.