From 2f39e51faea515cc7af9cf7eb7770bd85af28648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 11 Nov 2023 19:32:27 +0100 Subject: [PATCH] non-package-mode: - metadata like `name` and `version` is not required - the root package is never installed (same as `--no-root`) - building and publishing is not possible --- src/poetry/console/commands/build.py | 4 +++ src/poetry/console/commands/install.py | 7 +++-- src/poetry/console/commands/publish.py | 4 +++ src/poetry/factory.py | 4 +-- tests/console/commands/test_build.py | 16 +++++++++++ tests/console/commands/test_check.py | 28 +++++++++++++++---- tests/console/commands/test_install.py | 19 ++++++++++++- tests/console/commands/test_publish.py | 19 +++++++++++++ .../fixtures/non_package_mode/pyproject.toml | 7 +++++ tests/test_factory.py | 6 ++++ 10 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 tests/fixtures/non_package_mode/pyproject.toml diff --git a/src/poetry/console/commands/build.py b/src/poetry/console/commands/build.py index 5339a865200..ab0db1ffafd 100644 --- a/src/poetry/console/commands/build.py +++ b/src/poetry/console/commands/build.py @@ -23,6 +23,10 @@ class BuildCommand(EnvCommand): def handle(self) -> int: from poetry.core.masonry.builder import Builder + if not self.poetry.is_package_mode: + self.line_error("Building a package is not possible in non-package mode.") + return 1 + with build_environment(poetry=self.poetry, env=self.env, io=self.io) as env: fmt = self.option("format") or "all" package = self.poetry.package diff --git a/src/poetry/console/commands/install.py b/src/poetry/console/commands/install.py index 8e716caa2b0..869ad09d341 100644 --- a/src/poetry/console/commands/install.py +++ b/src/poetry/console/commands/install.py @@ -152,7 +152,7 @@ def handle(self) -> int: if return_code != 0: return return_code - if self.option("no-root"): + if self.option("no-root") or not self.poetry.is_package_mode: return 0 log_install = ( @@ -186,7 +186,10 @@ def handle(self) -> int: self.line_error( f"The current project could not be installed: {e}\n" "If you do not want to install the current project" - " use --no-root", + " use --no-root.\n" + "If you want to use Poetry only for dependency management" + " and not for packaging, you may also try the non-package mode.\n" + "In a future version of Poetry this warning will become an error!", style="warning", ) return 0 diff --git a/src/poetry/console/commands/publish.py b/src/poetry/console/commands/publish.py index a53df8208dd..54306fb4b1e 100644 --- a/src/poetry/console/commands/publish.py +++ b/src/poetry/console/commands/publish.py @@ -49,6 +49,10 @@ class PublishCommand(Command): def handle(self) -> int: from poetry.publishing.publisher import Publisher + if not self.poetry.is_package_mode: + self.line_error("Publishing a package is not possible in non-package mode.") + return 1 + publisher = Publisher(self.poetry, self.io) # Building package first, if told diff --git a/src/poetry/factory.py b/src/poetry/factory.py index 15bd004e747..7235ab1d6d1 100644 --- a/src/poetry/factory.py +++ b/src/poetry/factory.py @@ -370,9 +370,9 @@ def validate( dependencies = {canonicalize_name(d) for d in dependencies} - if canonicalize_name(config["name"]) in dependencies: + if (name := config.get("name")) and canonicalize_name(name) in dependencies: results["errors"].append( - f"Project name ({config['name']}) is same as one of its dependencies" + f"Project name ({name}) is same as one of its dependencies" ) return results diff --git a/tests/console/commands/test_build.py b/tests/console/commands/test_build.py index ed9f3a3c5fa..135db0f064d 100644 --- a/tests/console/commands/test_build.py +++ b/tests/console/commands/test_build.py @@ -16,6 +16,22 @@ from tests.types import FixtureDirGetter +def test_build_not_possible_in_non_package_mode( + fixture_dir: FixtureDirGetter, + command_tester_factory: CommandTesterFactory, +) -> None: + source_dir = fixture_dir("non_package_mode") + + poetry = Factory().create_poetry(source_dir) + tester = command_tester_factory("build", poetry) + + assert tester.execute() == 1 + assert ( + tester.io.fetch_error() + == "Building a package is not possible in non-package mode.\n" + ) + + def test_build_with_multiple_readme_files( fixture_dir: FixtureDirGetter, tmp_path: Path, diff --git a/tests/console/commands/test_check.py b/tests/console/commands/test_check.py index e0d7ece440e..06d044fb785 100644 --- a/tests/console/commands/test_check.py +++ b/tests/console/commands/test_check.py @@ -5,6 +5,7 @@ import pytest from poetry.packages import Locker +from poetry.toml import TOMLFile if TYPE_CHECKING: @@ -67,8 +68,6 @@ def test_check_valid(tester: CommandTester) -> None: def test_check_invalid( mocker: MockerFixture, tester: CommandTester, fixture_dir: FixtureDirGetter ) -> None: - from poetry.toml import TOMLFile - mocker.patch( "poetry.poetry.Poetry.file", return_value=TOMLFile(fixture_dir("invalid_pyproject") / "pyproject.toml"), @@ -108,8 +107,27 @@ def test_check_private( mocker: MockerFixture, tester: CommandTester, fixture_dir: FixtureDirGetter ) -> None: mocker.patch( - "poetry.factory.Factory.locate", - return_value=fixture_dir("private_pyproject") / "pyproject.toml", + "poetry.poetry.Poetry.file", + return_value=TOMLFile(fixture_dir("private_pyproject") / "pyproject.toml"), + new_callable=mocker.PropertyMock, + ) + + tester.execute() + + expected = """\ +All set! +""" + + assert tester.io.fetch_output() == expected + + +def test_check_non_package_mode( + mocker: MockerFixture, tester: CommandTester, fixture_dir: FixtureDirGetter +) -> None: + mocker.patch( + "poetry.poetry.Poetry.file", + return_value=TOMLFile(fixture_dir("non_package_mode") / "pyproject.toml"), + new_callable=mocker.PropertyMock, ) tester.execute() @@ -136,8 +154,6 @@ def test_check_lock_missing( expected: str, expected_status: int, ) -> None: - from poetry.toml import TOMLFile - mocker.patch( "poetry.poetry.Poetry.file", return_value=TOMLFile(fixture_dir("private_pyproject") / "pyproject.toml"), diff --git a/tests/console/commands/test_install.py b/tests/console/commands/test_install.py index bf0789c8616..b1a1e1dca68 100644 --- a/tests/console/commands/test_install.py +++ b/tests/console/commands/test_install.py @@ -416,7 +416,7 @@ def test_install_logs_output_decorated( assert tester.io.fetch_output() == expected -@pytest.mark.parametrize("with_root", [True]) +@pytest.mark.parametrize("with_root", [True, False]) @pytest.mark.parametrize("error", ["module", "readme", ""]) def test_install_warning_corrupt_root( command_tester_factory: CommandTesterFactory, @@ -488,3 +488,20 @@ def test_install_missing_directory_dependency_with_no_directory( else: with pytest.raises(ValueError, match="does not exist"): tester.execute(options) + + +def test_non_package_mode_does_not_try_to_install_root( + command_tester_factory: CommandTesterFactory, + project_factory: ProjectFactory, +) -> None: + content = """\ +[tool.poetry] +mode = "non-package" +""" + poetry = project_factory(name="non-package-mode", pyproject_content=content) + + tester = command_tester_factory("install", poetry=poetry) + tester.execute() + + assert tester.status_code == 0 + assert tester.io.fetch_error() == "" diff --git a/tests/console/commands/test_publish.py b/tests/console/commands/test_publish.py index 5f230c01ff3..bdfea939609 100644 --- a/tests/console/commands/test_publish.py +++ b/tests/console/commands/test_publish.py @@ -7,6 +7,7 @@ import pytest import requests +from poetry.factory import Factory from poetry.publishing.uploader import UploadError @@ -17,6 +18,24 @@ from pytest_mock import MockerFixture from tests.helpers import PoetryTestApplication + from tests.types import CommandTesterFactory + from tests.types import FixtureDirGetter + + +def test_publish_not_possible_in_non_package_mode( + fixture_dir: FixtureDirGetter, + command_tester_factory: CommandTesterFactory, +) -> None: + source_dir = fixture_dir("non_package_mode") + + poetry = Factory().create_poetry(source_dir) + tester = command_tester_factory("publish", poetry) + + assert tester.execute() == 1 + assert ( + tester.io.fetch_error() + == "Publishing a package is not possible in non-package mode.\n" + ) def test_publish_returns_non_zero_code_for_upload_errors( diff --git a/tests/fixtures/non_package_mode/pyproject.toml b/tests/fixtures/non_package_mode/pyproject.toml new file mode 100644 index 00000000000..5a5fbee0a1a --- /dev/null +++ b/tests/fixtures/non_package_mode/pyproject.toml @@ -0,0 +1,7 @@ +[tool.poetry] +mode = "non-package" + +[tool.poetry.dependencies] +python = "^3.8" +cleo = "^0.6" +pendulum = { git = "https://github.com/sdispater/pendulum.git", branch = "2.0" } diff --git a/tests/test_factory.py b/tests/test_factory.py index 00f563082a4..dcb1e3d4733 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -224,6 +224,12 @@ def test_create_poetry_with_multi_constraints_dependency( assert len(package.requires) == 2 +def test_create_poetry_non_package_mode(fixture_dir: FixtureDirGetter) -> None: + poetry = Factory().create_poetry(fixture_dir("non_package_mode")) + + assert not poetry.is_package_mode + + def test_poetry_with_default_source_legacy( fixture_dir: FixtureDirGetter, with_simple_keyring: None ) -> None: