Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

install: make --sync the default and introduce --keep-untracked #9855

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ poetry init
## install

The `install` command reads the `pyproject.toml` file from the current project,
resolves the dependencies, and installs them.
resolves the dependencies, and installs them. It also uninstalls packages
that are not required per default.

```bash
poetry install
Expand Down Expand Up @@ -185,19 +186,18 @@ poetry install --only-root
See [Dependency groups]({{< relref "managing-dependencies#dependency-groups" >}}) for more information
about dependency groups.

If you want to synchronize your environment – and ensure it matches the lock file – use the
`--sync` option.
If you want to keep untracked packages use the `--keep-untracked` option.

```bash
poetry install --sync
poetry install --keep-untracked
```

The `--sync` can be combined with group-related options:
The `--keep-untracked` can be combined with group-related options:

```bash
poetry install --without dev --sync
poetry install --with docs --sync
poetry install --only dev --sync
poetry install --without dev --keep-untracked
poetry install --with docs --keep-untracked
poetry install --only dev --keep-untracked
```

You can also specify the extras you want installed
Expand All @@ -210,7 +210,7 @@ poetry install -E mysql -E pgsql
poetry install --all-extras
```

Extras are not sensitive to `--sync`. Any extras not specified will always be removed.
Extras are not sensitive to `--keep-untracked`. Any extras not specified will always be removed.

```bash
poetry install --extras "A B" # C is removed
Expand Down Expand Up @@ -257,15 +257,14 @@ poetry install --compile
* `--with`: The optional dependency groups to include.
* `--only`: The only dependency groups to include.
* `--only-root`: Install only the root project, exclude all dependencies.
* `--sync`: Synchronize the environment with the locked packages and the specified groups.
* `--keep-untracked`: Do not uninstall the untracked packages.
* `--no-root`: Do not install the root package (your project).
* `--no-directory`: Skip all directory path dependencies (including transitive ones).
* `--dry-run`: Output the operations but do not execute anything (implicitly enables `--verbose`).
* `--extras (-E)`: Features to install (multiple values allowed).
* `--all-extras`: Install all extra features (conflicts with `--extras`).
* `--all-groups`: Install dependencies from all groups (conflicts with `--only`, `--with`, and `--without`).
* `--compile`: Compile Python source files to bytecode.
* `--remove-untracked`: Remove dependencies not presented in the lock file. (**Deprecated**, use `--sync` instead)

{{% note %}}
When `--only` is specified, `--with` and `--without` options are ignored.
Expand Down Expand Up @@ -304,7 +303,7 @@ You can do this using the `add` command.
* `--only`: The only dependency groups to include.
* `--dry-run` : Outputs the operations but will not execute anything (implicitly enables `--verbose`).
* `--lock` : Do not perform install (only update the lockfile).
* `--sync`: Synchronize the environment with the locked packages and the specified groups.
* `--keep-untracked`: Do not uninstall the untracked packages.

{{% note %}}
When `--only` is specified, `--with` and `--without` options are ignored.
Expand Down Expand Up @@ -1066,10 +1065,10 @@ is different in that the packages managed are for Poetry's runtime environment.
{{% /note %}}

```bash
poetry self install --sync
poetry self install
```

#### Options

* `--sync`: Synchronize the environment with the locked packages and the specified groups.
* `--keep-untracked`: Do not uninstall the untracked packages.
* `--dry-run`: Output the operations but do not execute anything (implicitly enables `--verbose`).
2 changes: 1 addition & 1 deletion docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Thus, dependencies are resolved by `pip`.
[testenv]
allowlist_externals = poetry
commands_pre =
poetry install --no-root --sync
poetry install --no-root
commands =
poetry run pytest tests/ --import-mode importlib
```
Expand Down
26 changes: 6 additions & 20 deletions docs/managing-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,32 +213,18 @@ poetry remove mkdocs --group docs

## Synchronizing dependencies

Poetry supports what's called dependency synchronization. Dependency synchronization ensures
Poetry promotes what is called dependency synchronization. Dependency synchronization ensures
that the locked dependencies in the `poetry.lock` file are the only ones present
in the environment, removing anything that's not necessary.
in the environment, removing anything that is not necessary.

This is done by using the `--sync` option of the `install` command:
Alternatively, you can keep untracked packages by using the `--keep-untracked` option of the `install` command:

```bash
poetry install --sync
poetry install --keep-untracked
```

The `--sync` option can be combined with any [dependency groups]({{< relref "#dependency-groups" >}}) related options
to synchronize the environment with specific groups. Note that extras are separate. Any
extras not selected for install are always removed, regardless of `--sync`.

```bash
poetry install --without dev --sync
poetry install --with docs --sync
poetry install --only dev
```

{{% note %}}
The `--sync` option replaces the `--remove-untracked` option which is now deprecated.
{{% /note %}}

## Layering optional groups

When you omit the `--sync` option, you can install any subset of optional groups without removing
those that are already installed. This is very useful, for example, in multi-stage
When you use the `--keep-untracked` option, you can install any subset of optional groups without removing
those that are already installed. This is very useful, for example, in multi-stage
Docker builds, where you run `poetry install` multiple times in different build stages.
7 changes: 3 additions & 4 deletions src/poetry/console/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ class InstallCommand(InstallerCommand):
options: ClassVar[list[Option]] = [
*InstallerCommand._group_dependency_options(),
option(
"sync",
"keep-untracked",
None,
"Synchronize the environment with the locked packages and the specified"
" groups.",
"Do not uninstall the untracked packages.",
),
option(
"no-root", None, "Do not install the root package (the current project)."
Expand Down Expand Up @@ -146,7 +145,7 @@ def handle(self) -> int:

self.installer.extras(extras)

with_synchronization = self.option("sync")
with_synchronization = not self.option("keep-untracked")

self.installer.only_groups(self.activated_groups)
self.installer.skip_directory(self.option("no-directory"))
Expand Down
2 changes: 1 addition & 1 deletion src/poetry/console/commands/self/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class SelfInstallCommand(SelfCommand, InstallCommand):
"Install locked packages (incl. addons) required by this Poetry installation."
)
options: ClassVar[list[Option]] = [
o for o in InstallCommand.options if o.name in {"sync", "dry-run"}
o for o in InstallCommand.options if o.name in {"keep-untracked", "dry-run"}
]
help = f"""\
The <c1>self install</c1> command ensures all additional packages specified are \
Expand Down
7 changes: 3 additions & 4 deletions src/poetry/console/commands/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ class UpdateCommand(InstallerCommand):
options: ClassVar[list[Option]] = [
*InstallerCommand._group_dependency_options(),
option(
"sync",
"keep-untracked",
None,
"Synchronize the environment with the locked packages and the specified"
" groups.",
"Do not uninstall the untracked packages.",
),
option(
"dry-run",
Expand All @@ -49,7 +48,7 @@ def handle(self) -> int:

self.installer.only_groups(self.activated_groups)
self.installer.dry_run(self.option("dry-run"))
self.installer.requires_synchronization(self.option("sync"))
self.installer.requires_synchronization(not self.option("keep-untracked"))
self.installer.execute_operations(not self.option("lock"))

# Force update
Expand Down
9 changes: 1 addition & 8 deletions tests/console/commands/self/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,5 @@ def test_self_install(

tester.execute()

expected_output = """\
Updating dependencies
Resolving dependencies...

Writing lock file
"""

assert tester.io.fetch_output() == expected_output
assert tester.io.fetch_output().endswith("Writing lock file\n")
assert tester.io.fetch_error() == ""
14 changes: 9 additions & 5 deletions tests/console/commands/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,22 @@ def test_group_options_are_passed_to_the_installer(
assert editable_builder_mock.call_count == 0


def test_sync_option_is_passed_to_the_installer(
tester: CommandTester, mocker: MockerFixture
@pytest.mark.parametrize("options", ["", "--keep-untracked"])
def test_keep_untracked_option_is_passed_to_the_installer(
tester: CommandTester, mocker: MockerFixture, options: str
) -> None:
"""
The --sync option is passed properly to the installer.
The --keep-untracked option is passed properly to the installer.
"""
assert isinstance(tester.command, InstallerCommand)
mocker.patch.object(tester.command.installer, "run", return_value=1)

tester.execute("--sync")
tester.execute(options)

assert tester.command.installer._requires_synchronization
if options:
assert not tester.command.installer._requires_synchronization
else:
assert tester.command.installer._requires_synchronization


@pytest.mark.parametrize("compile", [False, True])
Expand Down
13 changes: 9 additions & 4 deletions tests/console/commands/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,23 @@ def test_update_prints_operations(
assert ("Installing docker (4.3.1)" in output) is expected


def test_update_sync_option_is_passed_to_the_installer(
@pytest.mark.parametrize("options", ["", "--keep-untracked"])
def test_update_keep_untracked_option_is_passed_to_the_installer(
poetry_with_outdated_lockfile: Poetry,
command_tester_factory: CommandTesterFactory,
mocker: MockerFixture,
options: str,
) -> None:
"""
The --sync option is passed properly to the installer from update.
The --keep-untracked option is passed properly to the installer from update.
"""
tester = command_tester_factory("update", poetry=poetry_with_outdated_lockfile)
assert isinstance(tester.command, UpdateCommand)
mocker.patch.object(tester.command.installer, "run", return_value=1)

tester.execute("--sync")
tester.execute(options)

assert tester.command.installer._requires_synchronization
if options:
assert not tester.command.installer._requires_synchronization
else:
assert tester.command.installer._requires_synchronization
Loading