Skip to content

Commit

Permalink
locker: enable poetry lock if an incompatible lock file exists
Browse files Browse the repository at this point in the history
  • Loading branch information
radoering committed Oct 10, 2022
1 parent 94a5ce4 commit a83b5e8
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 10 deletions.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ repos:
- id: check-case-conflict
- id: check-json
- id: check-toml
exclude: tests/fixtures/invalid_lock/poetry\.lock
- id: check-yaml
- id: pretty-format-json
args: [--autofix, --no-ensure-ascii, --no-sort-keys]
Expand Down
2 changes: 1 addition & 1 deletion src/poetry/installation/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def _do_install(self) -> int:

locked_repository = Repository("poetry-locked")
if self._update:
if self._locker.is_locked() and not self._lock:
if not self._lock and self._locker.is_locked():
locked_repository = self._locker.locked_repository()

# If no packages have been whitelisted (The ones we want to update),
Expand Down
21 changes: 12 additions & 9 deletions src/poetry/packages/locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ def is_locked(self) -> bool:
"""
Checks whether the locker has been locked (lockfile found).
"""
if not self._lock.exists():
return False

return "package" in self.lock_data
return self._lock.exists()

def is_fresh(self) -> bool:
"""
Expand Down Expand Up @@ -256,12 +253,18 @@ def set_lock_data(self, root: Package, packages: list[Package]) -> bool:
"content-hash": self._content_hash,
}

if not self.is_locked() or lock != self.lock_data:
do_write = True
if self.is_locked():
try:
lock_data = self.lock_data
except RuntimeError:
# incompatible, invalid or no lock file
pass
else:
do_write = lock != lock_data
if do_write:
self._write_lock_data(lock)

return True

return False
return do_write

def _write_lock_data(self, data: TOMLDocument) -> None:
self.lock.write(data)
Expand Down
71 changes: 71 additions & 0 deletions tests/console/commands/test_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ def poetry_with_old_lockfile(
return _project_factory("old_lock", project_factory, fixture_dir)


@pytest.fixture
def poetry_with_incompatible_lockfile(
project_factory: ProjectFactory, fixture_dir: FixtureDirGetter
) -> Poetry:
return _project_factory("incompatible_lock", project_factory, fixture_dir)


@pytest.fixture
def poetry_with_invalid_lockfile(
project_factory: ProjectFactory, fixture_dir: FixtureDirGetter
) -> Poetry:
return _project_factory("invalid_lock", project_factory, fixture_dir)


def test_lock_check_outdated(
command_tester_factory: CommandTesterFactory,
poetry_with_outdated_lockfile: Poetry,
Expand Down Expand Up @@ -150,3 +164,60 @@ def test_lock_no_update(

for package in packages:
assert locked_repository.find_packages(package.to_dependency())


@pytest.mark.parametrize("is_no_update", [False, True])
def test_lock_with_incompatible_lockfile(
command_tester_factory: CommandTesterFactory,
poetry_with_incompatible_lockfile: Poetry,
repo: TestRepository,
is_no_update: bool,
) -> None:
repo.add_package(get_package("sampleproject", "1.3.1"))

locker = Locker(
lock=poetry_with_incompatible_lockfile.pyproject.file.path.parent
/ "poetry.lock",
local_config=poetry_with_incompatible_lockfile.locker._local_config,
)
poetry_with_incompatible_lockfile.set_locker(locker)

tester = command_tester_factory("lock", poetry=poetry_with_incompatible_lockfile)
if is_no_update:
# not possible because of incompatible lock file
expected = (
"(?s)lock file is not compatible .*"
" regenerate the lock file with the `poetry lock` command"
)
with pytest.raises(RuntimeError, match=expected):
tester.execute("--no-update")
else:
# still possible because lock file is not required
status_code = tester.execute()
assert status_code == 0


@pytest.mark.parametrize("is_no_update", [False, True])
def test_lock_with_invalid_lockfile(
command_tester_factory: CommandTesterFactory,
poetry_with_invalid_lockfile: Poetry,
repo: TestRepository,
is_no_update: bool,
) -> None:
repo.add_package(get_package("sampleproject", "1.3.1"))

locker = Locker(
lock=poetry_with_invalid_lockfile.pyproject.file.path.parent / "poetry.lock",
local_config=poetry_with_invalid_lockfile.locker._local_config,
)
poetry_with_invalid_lockfile.set_locker(locker)

tester = command_tester_factory("lock", poetry=poetry_with_invalid_lockfile)
if is_no_update:
# not possible because of broken lock file
with pytest.raises(RuntimeError, match="Unable to read the lock file"):
tester.execute("--no-update")
else:
# still possible because lock file is not required
status_code = tester.execute()
assert status_code == 0
2 changes: 2 additions & 0 deletions tests/fixtures/incompatible_lock/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions tests/fixtures/incompatible_lock/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[tool.poetry]
name = "foobar"
version = "0.1.0"
description = ""
authors = ["Poetry Developer <developer@python-poetry.org>"]

[tool.poetry.dependencies]
python = "^3.8"
sampleproject = ">=1.3.1"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
1 change: 1 addition & 0 deletions tests/fixtures/invalid_lock/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions tests/fixtures/invalid_lock/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[tool.poetry]
name = "foobar"
version = "0.1.0"
description = ""
authors = ["Poetry Developer <developer@python-poetry.org>"]

[tool.poetry.dependencies]
python = "^3.8"
sampleproject = ">=1.3.1"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

0 comments on commit a83b5e8

Please sign in to comment.