diff --git a/news/33.feature b/news/33.feature new file mode 100644 index 0000000000000000000000000000000000000000..46480bd5be3fe2527783ca5fd268f8f07cbbdf2c --- /dev/null +++ b/news/33.feature @@ -0,0 +1 @@ +Pinned candidates in lock file are reused when relocking during `pdm install`. diff --git a/pdm/cli/commands.py b/pdm/cli/commands.py index 56fd5188534bf4d3e41d93f37eda53cdbee1eb32..1fe824615b735da5c3210b749b50a7d7a57ef931 100644 --- a/pdm/cli/commands.py +++ b/pdm/cli/commands.py @@ -103,10 +103,15 @@ def lock(project): ) @pass_project def install(project, sections, dev, default, lock): - if lock and not ( - project.lockfile_file.is_file() and project.is_lockfile_hash_match() - ): - actions.do_lock(project) + if lock: + if not project.lockfile_file.exists(): + context.io.echo("Lock file does not exist, trying to generate one...") + actions.do_lock(project, strategy="all") + elif not project.is_lockfile_hash_match(): + context.io.echo( + "Lock file hash doesn't match pyproject.toml, regenerating..." + ) + actions.do_lock(project, strategy="reuse") actions.do_sync(project, sections, dev, default, False, False) diff --git a/pdm/project/core.py b/pdm/project/core.py index 9629bcb075d14552c8a54f71224d36e50ae8743c..a46e2fbb034e698e289ca595469078a8ac28184b 100644 --- a/pdm/project/core.py +++ b/pdm/project/core.py @@ -177,7 +177,7 @@ class Project: return {} section = section or "default" result = {} - for package in [dict(p) for p in self.lockfile["package"]]: + for package in [dict(p) for p in self.lockfile.get("package", [])]: if section != "__all__" and section not in package["sections"]: continue version = package.get("version") diff --git a/tests/cli/test_cli.py b/tests/cli/test_cli.py index 92e73148fa87e23cf2f9a056f18dcc7a00e51e68..cb970a0b83489d7e9a529f339e1dfc8607a24070 100644 --- a/tests/cli/test_cli.py +++ b/tests/cli/test_cli.py @@ -6,6 +6,7 @@ from pathlib import Path import pytest from click.testing import CliRunner from pdm.cli import actions, commands +from pdm.models.requirements import parse_requirement @pytest.fixture() @@ -124,3 +125,16 @@ def test_use_command(project, invoke): project.write_pyproject() result = invoke(["use", "2.7"], obj=project) assert result.exit_code == 1 + + +def test_install_with_lockfile(project, invoke, working_set, repository): + result = invoke(["lock"], obj=project) + assert result.exit_code == 0 + result = invoke(["install"], obj=project) + assert "Lock file" not in result.output + + project.add_dependencies({"pytz": parse_requirement("pytz")}) + result = invoke(["install"], obj=project) + assert "Lock file hash doesn't match" in result.output + assert "pytz" in project.get_locked_candidates() + assert project.is_lockfile_hash_match()