Skip to content

Commit 2812a1a

Browse files
committed
deprecate install --sync and introduce self sync command for symmetry
1 parent e9673f0 commit 2812a1a

File tree

8 files changed

+251
-33
lines changed

8 files changed

+251
-33
lines changed

docs/cli.md

Lines changed: 142 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ poetry init
142142
The `install` command reads the `pyproject.toml` file from the current project,
143143
resolves the dependencies, and installs them.
144144

145+
{{% note %}}
146+
Normally, you should prefer `poetry sync` to `poetry install` to avoid untracked outdated packages.
147+
However, if you have set `virtualenvs.create = false` to install dependencies into your system environment,
148+
which is discouraged, or `virtualenvs.options.system-site-packages = true` to make
149+
system site-packages available in your virtual environment, you should use `poetry install`
150+
because `poetry sync` will normally not work well in these cases.
151+
{{% /note %}}
152+
145153
```bash
146154
poetry install
147155
```
@@ -186,21 +194,6 @@ poetry install --only-root
186194
See [Dependency groups]({{< relref "managing-dependencies#dependency-groups" >}}) for more information
187195
about dependency groups.
188196

189-
If you want to synchronize your environment – and ensure it matches the lock file – use the
190-
`--sync` option.
191-
192-
```bash
193-
poetry install --sync
194-
```
195-
196-
The `--sync` can be combined with group-related options:
197-
198-
```bash
199-
poetry install --without dev --sync
200-
poetry install --with docs --sync
201-
poetry install --only dev --sync
202-
```
203-
204197
You can also specify the extras you want installed
205198
by passing the `-E|--extras` option (See [Extras]({{< relref "pyproject#extras" >}}) for more info).
206199
Pass `--all-extras` to install all defined extras for a project.
@@ -211,7 +204,7 @@ poetry install -E mysql -E pgsql
211204
poetry install --all-extras
212205
```
213206

214-
Extras are not sensitive to `--sync`. Any extras not specified will always be removed.
207+
Any extras not specified will always be removed.
215208

216209
```bash
217210
poetry install --extras "A B" # C is removed
@@ -258,7 +251,7 @@ poetry install --compile
258251
* `--with`: The optional dependency groups to include.
259252
* `--only`: The only dependency groups to include.
260253
* `--only-root`: Install only the root project, exclude all dependencies.
261-
* `--sync`: Synchronize the environment with the locked packages and the specified groups.
254+
* `--sync`: Synchronize the environment with the locked packages and the specified groups. (**Deprecated**, use `poetry sync` instead)
262255
* `--no-root`: Do not install the root package (your project).
263256
* `--no-directory`: Skip all directory path dependencies (including transitive ones).
264257
* `--dry-run`: Output the operations but do not execute anything (implicitly enables `--verbose`).
@@ -275,15 +268,119 @@ When `--only` is specified, `--with` and `--without` options are ignored.
275268
## sync
276269

277270
The `sync` command makes sure that the project's environment is in sync with the `poetry.lock` file.
278-
It is equivalent to running `poetry install --sync` and provides the same options
279-
(except for `--sync`) as [install]({{< relref "#install" >}}).
271+
It is similar to `poetry install` but it additionally removes packages that are not tracked in the lock file.
272+
273+
```bash
274+
poetry sync
275+
```
276+
277+
If there is a `poetry.lock` file in the current directory,
278+
it will use the exact versions from there instead of resolving them.
279+
This ensures that everyone using the library will get the same versions of the dependencies.
280+
281+
If there is no `poetry.lock` file, Poetry will create one after dependency resolution.
282+
283+
If you want to exclude one or more dependency groups for the installation, you can use
284+
the `--without` option.
285+
286+
```bash
287+
poetry sync --without test,docs
288+
```
289+
290+
You can also select optional dependency groups with the `--with` option.
291+
292+
```bash
293+
poetry sync --with test,docs
294+
```
295+
296+
To install all dependency groups including the optional groups, use the ``--all-groups`` flag.
297+
298+
```bash
299+
poetry sync --all-groups
300+
```
301+
302+
It's also possible to only install specific dependency groups by using the `only` option.
303+
304+
```bash
305+
poetry sync --only test,docs
306+
```
307+
308+
To only install the project itself with no dependencies, use the `--only-root` flag.
309+
310+
```bash
311+
poetry sync --only-root
312+
```
313+
314+
See [Dependency groups]({{< relref "managing-dependencies#dependency-groups" >}}) for more information
315+
about dependency groups.
316+
317+
You can also specify the extras you want installed
318+
by passing the `-E|--extras` option (See [Extras]({{< relref "pyproject#extras" >}}) for more info).
319+
Pass `--all-extras` to install all defined extras for a project.
320+
321+
```bash
322+
poetry sync --extras "mysql pgsql"
323+
poetry sync -E mysql -E pgsql
324+
poetry sync --all-extras
325+
```
326+
327+
Any extras not specified will always be removed.
328+
329+
```bash
330+
poetry sync --extras "A B" # C is removed
331+
```
332+
333+
By default `poetry` will install your project's package every time you run `sync`:
334+
335+
```bash
336+
$ poetry sync
337+
Installing dependencies from lock file
338+
339+
No dependencies to install or update
340+
341+
- Installing <your-package-name> (x.x.x)
342+
```
343+
344+
If you want to skip this installation, use the `--no-root` option.
345+
346+
```bash
347+
poetry sync --no-root
348+
```
349+
350+
Similar to `--no-root` you can use `--no-directory` to skip directory path dependencies:
351+
352+
```bash
353+
poetry sync --no-directory
354+
```
355+
356+
This is mainly useful for caching in CI or when building Docker images. See the [FAQ entry]({{< relref "faq#poetry-busts-my-docker-cache-because-it-requires-me-to-copy-my-source-files-in-before-installing-3rd-party-dependencies" >}}) for more information on this option.
357+
358+
By default `poetry` does not compile Python source files to bytecode during installation.
359+
This speeds up the installation process, but the first execution may take a little more
360+
time because Python then compiles source files to bytecode automatically.
361+
If you want to compile source files to bytecode during installation,
362+
you can use the `--compile` option:
363+
364+
```bash
365+
poetry sync --compile
366+
```
367+
368+
### Options
369+
370+
* `--without`: The dependency groups to ignore.
371+
* `--with`: The optional dependency groups to include.
372+
* `--only`: The only dependency groups to include.
373+
* `--only-root`: Install only the root project, exclude all dependencies.
374+
* `--no-root`: Do not install the root package (your project).
375+
* `--no-directory`: Skip all directory path dependencies (including transitive ones).
376+
* `--dry-run`: Output the operations but do not execute anything (implicitly enables `--verbose`).
377+
* `--extras (-E)`: Features to install (multiple values allowed).
378+
* `--all-extras`: Install all extra features (conflicts with `--extras`).
379+
* `--all-groups`: Install dependencies from all groups (conflicts with `--only`, `--with`, and `--without`).
380+
* `--compile`: Compile Python source files to bytecode.
280381

281382
{{% note %}}
282-
Normally, you should prefer `poetry sync` to `poetry install` to avoid untracked outdated packages.
283-
However, if you have set `virtualenvs.create = false` to install dependencies into your system environment,
284-
which is discouraged, or `virtualenvs.options.system-site-packages = true` to make
285-
system site-packages available in your virtual environment, you should use `poetry install`
286-
because `poetry sync` will normally not work well in these cases.
383+
When `--only` is specified, `--with` and `--without` options are ignored.
287384
{{% /note %}}
288385

289386

@@ -1039,16 +1136,34 @@ runtime environment.
10391136

10401137
{{% note %}}
10411138
The `self install` command works similar to the [`install` command](#install). However,
1042-
is different in that the packages managed are for Poetry's runtime environment.
1139+
it is different in that the packages managed are for Poetry's runtime environment.
10431140
{{% /note %}}
10441141

10451142
```bash
1046-
poetry self install --sync
1143+
poetry self install
1144+
```
1145+
1146+
#### Options
1147+
1148+
* `--sync`: Synchronize the environment with the locked packages and the specified groups. (**Deprecated**, use `poetry self sync` instead)
1149+
* `--dry-run`: Output the operations but do not execute anything (implicitly enables `--verbose`).
1150+
1151+
### self sync
1152+
1153+
The `self sync` command ensures all additional (and no other) packages specified
1154+
are installed in the current runtime environment.
1155+
1156+
{{% note %}}
1157+
The `self sync` command works similar to the [`sync` command](#sync). However,
1158+
it is different in that the packages managed are for Poetry's runtime environment.
1159+
{{% /note %}}
1160+
1161+
```bash
1162+
poetry self sync
10471163
```
10481164

10491165
#### Options
10501166

1051-
* `--sync`: Synchronize the environment with the locked packages and the specified groups.
10521167
* `--dry-run`: Output the operations but do not execute anything (implicitly enables `--verbose`).
10531168

10541169
## export

src/poetry/console/application.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def _load() -> Command:
8686
"self update",
8787
"self show",
8888
"self show plugins",
89+
"self sync",
8990
# Source commands
9091
"source add",
9192
"source remove",

src/poetry/console/commands/install.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class InstallCommand(InstallerCommand):
2323
"sync",
2424
None,
2525
"Synchronize the environment with the locked packages and the specified"
26-
" groups.",
26+
" groups. (<warning>Deprecated</warning>)",
2727
),
2828
option(
2929
"no-root", None, "Do not install the root package (the current project)."
@@ -89,6 +89,10 @@ def activated_groups(self) -> set[str]:
8989
else:
9090
return super().activated_groups
9191

92+
@property
93+
def _alternative_sync_command(self) -> str:
94+
return "poetry sync"
95+
9296
def handle(self) -> int:
9397
from poetry.core.masonry.utils.module import ModuleOrPackageNotFoundError
9498

@@ -147,6 +151,14 @@ def handle(self) -> int:
147151
self.installer.extras(extras)
148152

149153
with_synchronization = self.option("sync")
154+
if with_synchronization:
155+
self.line_error(
156+
"<warning>The `<fg=yellow;options=bold>--sync</>` option is"
157+
" deprecated and slated for removal in the next minor release"
158+
" after June 2025, use the"
159+
f" `<fg=yellow;options=bold>{self._alternative_sync_command}</>`"
160+
" command instead.</warning>"
161+
)
150162

151163
self.installer.only_groups(self.activated_groups)
152164
self.installer.skip_directory(self.option("no-directory"))

src/poetry/console/commands/self/install.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,7 @@ class SelfInstallCommand(SelfCommand, InstallCommand):
3535
@property
3636
def activated_groups(self) -> set[str]:
3737
return {MAIN_GROUP, self.default_group}
38+
39+
@property
40+
def _alternative_sync_command(self) -> str:
41+
return "poetry self sync"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING
4+
from typing import ClassVar
5+
6+
from poetry.console.commands.self.install import SelfInstallCommand
7+
8+
9+
if TYPE_CHECKING:
10+
from cleo.io.inputs.option import Option
11+
12+
13+
class SelfSyncCommand(SelfInstallCommand):
14+
name = "self sync"
15+
description = (
16+
"Sync Poetry's own environment according to the locked packages (incl. addons)"
17+
" required by this Poetry installation."
18+
)
19+
options: ClassVar[list[Option]] = [
20+
opt for opt in SelfInstallCommand.options if opt.name != "sync"
21+
]
22+
help = f"""\
23+
The <c1>self sync</c1> command ensures all additional (and no other) packages \
24+
specified are installed in the current runtime environment.
25+
26+
This is managed in the \
27+
<comment>{SelfInstallCommand.get_default_system_pyproject_file()}</> file.
28+
29+
You can add more packages using the <c1>self add</c1> command and remove them using \
30+
the <c1>self remove</c1> command.
31+
"""

tests/console/commands/self/test_install.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@
1414

1515

1616
@pytest.fixture
17-
def tester(command_tester_factory: CommandTesterFactory) -> CommandTester:
18-
return command_tester_factory("self install")
17+
def command() -> str:
18+
return "self install"
19+
20+
21+
@pytest.fixture
22+
def tester(command_tester_factory: CommandTesterFactory, command: str) -> CommandTester:
23+
return command_tester_factory(command)
1924

2025

2126
@pytest.mark.parametrize(
@@ -60,3 +65,15 @@ def test_self_install(
6065

6166
assert tester.io.fetch_output() == expected_output
6267
assert tester.io.fetch_error() == ""
68+
69+
70+
@pytest.mark.parametrize("sync", [True, False])
71+
def test_sync_deprecation(tester: CommandTester, sync: bool) -> None:
72+
tester.execute("--sync" if sync else "")
73+
74+
error = tester.io.fetch_error()
75+
if sync:
76+
assert "deprecated" in error
77+
assert "poetry self sync" in error
78+
else:
79+
assert error == ""
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING
4+
5+
import pytest
6+
7+
from cleo.exceptions import CleoNoSuchOptionError
8+
9+
# import all tests from the self install command
10+
# and run them for sync by overriding the command fixture
11+
from tests.console.commands.self.test_install import * # noqa: F403
12+
13+
14+
if TYPE_CHECKING:
15+
from cleo.testers.command_tester import CommandTester
16+
17+
18+
@pytest.fixture # type: ignore[no-redef]
19+
def command() -> str:
20+
return "self sync"
21+
22+
23+
@pytest.mark.skip("Only relevant for `poetry self install`") # type: ignore[no-redef]
24+
def test_sync_deprecation() -> None:
25+
"""The only test from the self install command that does not work for self sync."""
26+
27+
28+
def test_sync_option_not_available(tester: CommandTester) -> None:
29+
with pytest.raises(CleoNoSuchOptionError):
30+
tester.execute("--sync")

tests/console/commands/test_install.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,18 +159,26 @@ def test_group_options_are_passed_to_the_installer(
159159
assert editable_builder_mock.call_count == 0
160160

161161

162+
@pytest.mark.parametrize("sync", [True, False])
162163
def test_sync_option_is_passed_to_the_installer(
163-
tester: CommandTester, mocker: MockerFixture
164+
tester: CommandTester, mocker: MockerFixture, sync: bool
164165
) -> None:
165166
"""
166167
The --sync option is passed properly to the installer.
167168
"""
168169
assert isinstance(tester.command, InstallerCommand)
169170
mocker.patch.object(tester.command.installer, "run", return_value=1)
170171

171-
tester.execute("--sync")
172+
tester.execute("--sync" if sync else "")
173+
174+
assert tester.command.installer._requires_synchronization is sync
172175

173-
assert tester.command.installer._requires_synchronization
176+
error = tester.io.fetch_error()
177+
if sync:
178+
assert "deprecated" in error
179+
assert "poetry sync" in error
180+
else:
181+
assert error == ""
174182

175183

176184
@pytest.mark.parametrize("compile", [False, True])

0 commit comments

Comments
 (0)