diff --git a/src/poetry/console/commands/check.py b/src/poetry/console/commands/check.py index ae90004d318..86a7f5a02c2 100644 --- a/src/poetry/console/commands/check.py +++ b/src/poetry/console/commands/check.py @@ -7,6 +7,7 @@ from cleo.helpers import option from poetry.console.commands.command import Command +from poetry.utils.helpers import lock_command_hint_for if TYPE_CHECKING: @@ -161,9 +162,10 @@ def handle(self) -> int: if self.option("lock") and not self.poetry.locker.is_locked(): check_result["errors"] += ["poetry.lock was not found."] if self.poetry.locker.is_locked() and not self.poetry.locker.is_fresh(): + hint = lock_command_hint_for(self.poetry.locker.lock) check_result["errors"] += [ "pyproject.toml changed significantly since poetry.lock was last generated. " - "Run `poetry lock` to fix the lock file." + f"Run {hint} to fix the lock file." ] return_code = 0 diff --git a/src/poetry/console/commands/show.py b/src/poetry/console/commands/show.py index 779f423bf49..66df0ad65d7 100644 --- a/src/poetry/console/commands/show.py +++ b/src/poetry/console/commands/show.py @@ -13,6 +13,7 @@ from poetry.console.commands.env_command import EnvCommand from poetry.console.commands.group_command import GroupCommand +from poetry.utils.helpers import lock_command_hint_for if TYPE_CHECKING: @@ -146,9 +147,9 @@ def handle(self) -> int: self.io.input.set_option("latest", True) if not self.poetry.locker.is_locked(): + hint = lock_command_hint_for(self.poetry.locker.lock) self.line_error( - "Error: poetry.lock not found. Run `poetry lock` to create" - " it." + f"Error: poetry.lock not found. Run {hint} to create it." ) return 1 diff --git a/src/poetry/installation/installer.py b/src/poetry/installation/installer.py index b4e9eaaaafd..ec4b9b498d2 100644 --- a/src/poetry/installation/installer.py +++ b/src/poetry/installation/installer.py @@ -12,6 +12,7 @@ from poetry.repositories import RepositoryPool from poetry.repositories.installed_repository import InstalledRepository from poetry.repositories.lockfile_repository import LockfileRepository +from poetry.utils.helpers import lock_command_hint_for if TYPE_CHECKING: @@ -255,9 +256,10 @@ def _do_install(self) -> int: self._io.write_line("Installing dependencies from lock file") if not self._locker.is_fresh(): + hint = lock_command_hint_for(self._locker.lock) raise ValueError( "pyproject.toml changed significantly since poetry.lock was last" - " generated. Run `poetry lock` to fix the lock file." + f" generated. Run {hint} to fix the lock file." ) if not (reresolve or self._locker.is_locked_groups_and_markers()): if self._io.is_verbose(): diff --git a/src/poetry/utils/helpers.py b/src/poetry/utils/helpers.py index c5facf140f6..1d84bb3ef09 100644 --- a/src/poetry/utils/helpers.py +++ b/src/poetry/utils/helpers.py @@ -64,6 +64,25 @@ ) +def lock_command_hint_for(lock_path: Path) -> str: + """Return the appropriate lock command hint for a given lock file path. + + If the lock file resides in Poetry's configuration directory, this suggests + using the self-locking command. Otherwise, it suggests the regular project + lock command. + """ + try: + from poetry.locations import CONFIG_DIR + except Exception: + return "`poetry lock`" + + return ( + "`poetry self lock`" + if lock_path.parent == Path(CONFIG_DIR) + else "`poetry lock`" + ) + + @contextmanager def directory(path: Path) -> Iterator[Path]: cwd = Path.cwd() diff --git a/tests/console/commands/self/test_show.py b/tests/console/commands/self/test_show.py index d1b553a2af0..d924eecf8de 100644 --- a/tests/console/commands/self/test_show.py +++ b/tests/console/commands/self/test_show.py @@ -70,3 +70,30 @@ def test_show_format(tester: CommandTester, options: str) -> None: ) assert tester.execute(options) == 0 assert tester.io.fetch_output().strip() == expected + + +def test_self_show_errors_without_lock_file(tester: CommandTester) -> None: + from poetry.console.commands.self.self_command import SelfCommand + + pyproject_content = { + "tool": { + "poetry": { + "name": "poetry-instance", + "version": __version__, + "dependencies": {"python": "^3.9", "poetry": __version__}, + } + } + } + + system_pyproject_file = SelfCommand.get_default_system_pyproject_file() + system_pyproject_file.write_text(tomlkit.dumps(pyproject_content), encoding="utf-8") + + lock_path = system_pyproject_file.parent.joinpath("poetry.lock") + if lock_path.exists(): + lock_path.unlink() + + tester.execute("") + + expected = "Error: poetry.lock not found. Run `poetry self lock` to create it.\n" + assert tester.io.fetch_error() == expected + assert tester.status_code == 1 diff --git a/tests/installation/test_installer.py b/tests/installation/test_installer.py index 851c9594b80..ef39a2adae9 100644 --- a/tests/installation/test_installer.py +++ b/tests/installation/test_installer.py @@ -228,6 +228,25 @@ def test_not_fresh_lock(installer: Installer, locker: Locker) -> None: installer.run() +def test_not_fresh_lock_in_self_context_suggests_self_lock( + installer: Installer, locker: Locker +) -> None: + from pathlib import Path + + from poetry.locations import CONFIG_DIR + + locker.locked().fresh(False).set_lock_path(Path(CONFIG_DIR)) + + with pytest.raises( + ValueError, + match=re.escape( + "pyproject.toml changed significantly since poetry.lock was last generated. " + "Run `poetry self lock` to fix the lock file." + ), + ): + installer.run() + + def test_run_with_dependencies( installer: Installer, locker: Locker, repo: Repository, package: ProjectPackage ) -> None: