Skip to content

Commit 6d57e84

Browse files
authored
Moving "poetry lock --check" to "poetry check --lock" (#8015)
1 parent 1fc9482 commit 6d57e84

File tree

5 files changed

+172
-9
lines changed

5 files changed

+172
-9
lines changed

docs/cli.md

+9-4
Original file line numberDiff line numberDiff line change
@@ -625,8 +625,9 @@ As such, `exit` should be used to properly exit the shell and the virtual enviro
625625

626626
## check
627627

628-
The `check` command validates the structure of the `pyproject.toml` file
629-
and returns a detailed report if there are any errors.
628+
The `check` command validates the content of the `pyproject.toml` file
629+
and its consistency with the `poetry.lock` file.
630+
It returns a detailed report if there are any errors.
630631

631632
{{% note %}}
632633
This command is also available as a pre-commit hook. See [pre-commit hooks]({{< relref "pre-commit-hooks#poetry-check">}}) for more information.
@@ -636,6 +637,10 @@ This command is also available as a pre-commit hook. See [pre-commit hooks]({{<
636637
poetry check
637638
```
638639

640+
### Options
641+
642+
* `--lock`: Verifies that `poetry.lock` exists for the current `pyproject.toml`.
643+
639644
## search
640645

641646
This command searches for packages on a remote index.
@@ -659,7 +664,7 @@ poetry lock
659664

660665
### Options
661666

662-
* `--check`: Verify that `poetry.lock` is consistent with `pyproject.toml`
667+
* `--check`: Verify that `poetry.lock` is consistent with `pyproject.toml`. (**Deprecated**) Use `poetry check --lock` instead.
663668
* `--no-update`: Do not update locked versions, only refresh lock file.
664669

665670
## version
@@ -944,7 +949,7 @@ poetry self lock
944949

945950
#### Options
946951

947-
* `--check`: Verify that `poetry.lock` is consistent with `pyproject.toml`
952+
* `--check`: Verify that `poetry.lock` is consistent with `pyproject.toml`. (**Deprecated**)
948953
* `--no-update`: Do not update locked versions, only refresh lock file.
949954

950955
### self show

src/poetry/console/commands/check.py

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
11
from __future__ import annotations
22

3+
from cleo.helpers import option
4+
35
from poetry.console.commands.command import Command
46

57

68
class CheckCommand(Command):
79
name = "check"
8-
description = "Checks the validity of the <comment>pyproject.toml</comment> file."
10+
description = (
11+
"Validates the content of the <comment>pyproject.toml</> file and its"
12+
" consistency with the poetry.lock file."
13+
)
14+
15+
options = [
16+
option(
17+
"lock",
18+
None,
19+
(
20+
"Checks that <comment>poetry.lock</> exists for the current"
21+
" version of <comment>pyproject.toml</>."
22+
),
23+
),
24+
]
925

1026
def validate_classifiers(
1127
self, project_classifiers: set[str]
@@ -72,6 +88,15 @@ def handle(self) -> int:
7288
check_result["errors"].extend(errors)
7389
check_result["warnings"].extend(warnings)
7490

91+
# Verify that lock file is consistent
92+
if self.option("lock") and not self.poetry.locker.is_locked():
93+
check_result["errors"] += ["poetry.lock was not found."]
94+
if self.poetry.locker.is_locked() and not self.poetry.locker.is_fresh():
95+
check_result["errors"] += [
96+
"poetry.lock is not consistent with pyproject.toml. Run `poetry"
97+
" lock [--no-update]` to fix it."
98+
]
99+
75100
if not check_result["errors"] and not check_result["warnings"]:
76101
self.info("All set!")
77102

src/poetry/console/commands/lock.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ class LockCommand(InstallerCommand):
1818
None,
1919
(
2020
"Check that the <comment>poetry.lock</> file corresponds to the current"
21-
" version of <comment>pyproject.toml</>."
21+
" version of <comment>pyproject.toml</>. (<warning>Deprecated</>) Use"
22+
" <comment>poetry check --lock</> instead."
2223
),
2324
),
2425
]
@@ -36,6 +37,10 @@ class LockCommand(InstallerCommand):
3637

3738
def handle(self) -> int:
3839
if self.option("check"):
40+
self.line_error(
41+
"<warning>poetry lock --check is deprecated, use `poetry"
42+
" check --lock` instead.</warning>"
43+
)
3944
if self.poetry.locker.is_locked() and self.poetry.locker.is_fresh():
4045
self.line("poetry.lock is consistent with pyproject.toml.")
4146
return 0

tests/console/commands/test_check.py

+123-1
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,56 @@
44

55
import pytest
66

7+
from poetry.packages import Locker
8+
79

810
if TYPE_CHECKING:
11+
import httpretty
12+
913
from cleo.testers.command_tester import CommandTester
1014
from pytest_mock import MockerFixture
1115

16+
from poetry.poetry import Poetry
1217
from tests.types import CommandTesterFactory
1318
from tests.types import FixtureDirGetter
19+
from tests.types import ProjectFactory
1420

1521

1622
@pytest.fixture()
1723
def tester(command_tester_factory: CommandTesterFactory) -> CommandTester:
1824
return command_tester_factory("check")
1925

2026

27+
def _project_factory(
28+
fixture_name: str,
29+
project_factory: ProjectFactory,
30+
fixture_dir: FixtureDirGetter,
31+
) -> Poetry:
32+
source = fixture_dir(fixture_name)
33+
pyproject_content = (source / "pyproject.toml").read_text(encoding="utf-8")
34+
poetry_lock_content = (source / "poetry.lock").read_text(encoding="utf-8")
35+
return project_factory(
36+
name="foobar",
37+
pyproject_content=pyproject_content,
38+
poetry_lock_content=poetry_lock_content,
39+
source=source,
40+
)
41+
42+
43+
@pytest.fixture
44+
def poetry_with_outdated_lockfile(
45+
project_factory: ProjectFactory, fixture_dir: FixtureDirGetter
46+
) -> Poetry:
47+
return _project_factory("outdated_lock", project_factory, fixture_dir)
48+
49+
50+
@pytest.fixture
51+
def poetry_with_up_to_date_lockfile(
52+
project_factory: ProjectFactory, fixture_dir: FixtureDirGetter
53+
) -> Poetry:
54+
return _project_factory("up_to_date_lock", project_factory, fixture_dir)
55+
56+
2157
def test_check_valid(tester: CommandTester) -> None:
2258
tester.execute()
2359

@@ -39,12 +75,13 @@ def test_check_invalid(
3975
new_callable=mocker.PropertyMock,
4076
)
4177

42-
tester.execute()
78+
tester.execute("--lock")
4379

4480
expected = """\
4581
Error: 'description' is a required property
4682
Error: Project name (invalid) is same as one of its dependencies
4783
Error: Unrecognized classifiers: ['Intended Audience :: Clowns'].
84+
Error: poetry.lock was not found.
4885
Warning: A wildcard Python dependency is ambiguous.\
4986
Consider specifying a more explicit one.
5087
Warning: The "pendulum" dependency specifies the "allows-prereleases" property,\
@@ -74,3 +111,88 @@ def test_check_private(
74111
"""
75112

76113
assert tester.io.fetch_output() == expected
114+
115+
116+
@pytest.mark.parametrize(
117+
("options", "expected", "expected_status"),
118+
[
119+
("", "All set!\n", 0),
120+
("--lock", "Error: poetry.lock was not found.\n", 1),
121+
],
122+
)
123+
def test_check_lock_missing(
124+
mocker: MockerFixture,
125+
tester: CommandTester,
126+
fixture_dir: FixtureDirGetter,
127+
options: str,
128+
expected: str,
129+
expected_status: int,
130+
) -> None:
131+
from poetry.toml import TOMLFile
132+
133+
mocker.patch(
134+
"poetry.poetry.Poetry.file",
135+
return_value=TOMLFile(fixture_dir("private_pyproject") / "pyproject.toml"),
136+
new_callable=mocker.PropertyMock,
137+
)
138+
139+
status_code = tester.execute(options)
140+
141+
assert status_code == expected_status
142+
143+
if status_code == 0:
144+
assert tester.io.fetch_output() == expected
145+
else:
146+
assert tester.io.fetch_error() == expected
147+
148+
149+
@pytest.mark.parametrize("options", ["", "--lock"])
150+
def test_check_lock_outdated(
151+
command_tester_factory: CommandTesterFactory,
152+
poetry_with_outdated_lockfile: Poetry,
153+
http: type[httpretty.httpretty],
154+
options: str,
155+
) -> None:
156+
http.disable()
157+
158+
locker = Locker(
159+
lock=poetry_with_outdated_lockfile.pyproject.file.path.parent / "poetry.lock",
160+
local_config=poetry_with_outdated_lockfile.locker._local_config,
161+
)
162+
poetry_with_outdated_lockfile.set_locker(locker)
163+
164+
tester = command_tester_factory("check", poetry=poetry_with_outdated_lockfile)
165+
status_code = tester.execute(options)
166+
expected = (
167+
"Error: poetry.lock is not consistent with pyproject.toml. "
168+
"Run `poetry lock [--no-update]` to fix it.\n"
169+
)
170+
171+
assert tester.io.fetch_error() == expected
172+
173+
# exit with an error
174+
assert status_code == 1
175+
176+
177+
@pytest.mark.parametrize("options", ["", "--lock"])
178+
def test_check_lock_up_to_date(
179+
command_tester_factory: CommandTesterFactory,
180+
poetry_with_up_to_date_lockfile: Poetry,
181+
http: type[httpretty.httpretty],
182+
options: str,
183+
) -> None:
184+
http.disable()
185+
186+
locker = Locker(
187+
lock=poetry_with_up_to_date_lockfile.pyproject.file.path.parent / "poetry.lock",
188+
local_config=poetry_with_up_to_date_lockfile.locker._local_config,
189+
)
190+
poetry_with_up_to_date_lockfile.set_locker(locker)
191+
192+
tester = command_tester_factory("check", poetry=poetry_with_up_to_date_lockfile)
193+
status_code = tester.execute(options)
194+
expected = "All set!\n"
195+
assert tester.io.fetch_output() == expected
196+
197+
# exit with an error
198+
assert status_code == 0

tests/console/commands/test_lock.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def poetry_with_invalid_lockfile(
8989
return _project_factory("invalid_lock", project_factory, fixture_dir)
9090

9191

92-
def test_lock_check_outdated(
92+
def test_lock_check_outdated_legacy(
9393
command_tester_factory: CommandTesterFactory,
9494
poetry_with_outdated_lockfile: Poetry,
9595
http: type[httpretty.httpretty],
@@ -105,6 +105,7 @@ def test_lock_check_outdated(
105105
tester = command_tester_factory("lock", poetry=poetry_with_outdated_lockfile)
106106
status_code = tester.execute("--check")
107107
expected = (
108+
"poetry lock --check is deprecated, use `poetry check --lock` instead.\n"
108109
"Error: poetry.lock is not consistent with pyproject.toml. "
109110
"Run `poetry lock [--no-update]` to fix it.\n"
110111
)
@@ -115,7 +116,7 @@ def test_lock_check_outdated(
115116
assert status_code == 1
116117

117118

118-
def test_lock_check_up_to_date(
119+
def test_lock_check_up_to_date_legacy(
119120
command_tester_factory: CommandTesterFactory,
120121
poetry_with_up_to_date_lockfile: Poetry,
121122
http: type[httpretty.httpretty],
@@ -133,6 +134,11 @@ def test_lock_check_up_to_date(
133134
expected = "poetry.lock is consistent with pyproject.toml.\n"
134135
assert tester.io.fetch_output() == expected
135136

137+
expected_error = (
138+
"poetry lock --check is deprecated, use `poetry check --lock` instead.\n"
139+
)
140+
assert tester.io.fetch_error() == expected_error
141+
136142
# exit with an error
137143
assert status_code == 0
138144

0 commit comments

Comments
 (0)