From 8b8e367e466b1d7d21dcb03305feca7ce8c3edff Mon Sep 17 00:00:00 2001 From: Jan Chren ~rindeal Date: Fri, 30 Aug 2024 17:43:27 +0000 Subject: [PATCH 1/5] Ignore empty readme strings in configs --- src/poetry/core/factory.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/poetry/core/factory.py b/src/poetry/core/factory.py index 5e74991e3..aae44fdfa 100644 --- a/src/poetry/core/factory.py +++ b/src/poetry/core/factory.py @@ -152,10 +152,9 @@ def configure_package( package.classifiers = config.get("classifiers", []) if "readme" in config: - if isinstance(config["readme"], str): - package.readmes = (root / config["readme"],) - else: - package.readmes = tuple(root / readme for readme in config["readme"]) + readme_strs = (config["readme"],) if isinstance(config["readme"], str) else config["readme"] + package.readmes = tuple(root / readme for readme in readme_strs if readme.strip()) + if "dependencies" in config: cls._add_package_group_dependencies( From 1ede8e2d8257e78d916b2917452ef874c337f5dd Mon Sep 17 00:00:00 2001 From: Jan Chren ~rindeal Date: Fri, 30 Aug 2024 17:42:01 +0000 Subject: [PATCH 2/5] Raise user-friendly exceptions on readme open errors --- src/poetry/core/masonry/metadata.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/poetry/core/masonry/metadata.py b/src/poetry/core/masonry/metadata.py index 0c18c1051..1f97b37a8 100644 --- a/src/poetry/core/masonry/metadata.py +++ b/src/poetry/core/masonry/metadata.py @@ -57,8 +57,15 @@ def from_package(cls, package: Package) -> Metadata: if package.readmes: descriptions = [] for readme in package.readmes: - with readme.open(encoding="utf-8") as f: - descriptions.append(f.read()) + try: + with readme.open(encoding="utf-8") as f: + descriptions.append(f.read()) + except FileNotFoundError as e: + raise FileNotFoundError(f"Readme path `{readme}` does not exist.") from e + except IsADirectoryError as e: + raise IsADirectoryError(f"Readme path `{readme}` is a directory.") from e + except PermissionError as e: + raise PermissionError(f"Readme path `{readme}` is not readable.") from e meta.description = "\n".join(descriptions) meta.keywords = ",".join(package.keywords) From fc6f3bb4ee78c815121e3de993df5e9526382618 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 18:07:51 +0000 Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/poetry/core/factory.py | 11 ++++++++--- src/poetry/core/masonry/metadata.py | 12 +++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/poetry/core/factory.py b/src/poetry/core/factory.py index aae44fdfa..a0394f1b0 100644 --- a/src/poetry/core/factory.py +++ b/src/poetry/core/factory.py @@ -152,9 +152,14 @@ def configure_package( package.classifiers = config.get("classifiers", []) if "readme" in config: - readme_strs = (config["readme"],) if isinstance(config["readme"], str) else config["readme"] - package.readmes = tuple(root / readme for readme in readme_strs if readme.strip()) - + readme_strs = ( + (config["readme"],) + if isinstance(config["readme"], str) + else config["readme"] + ) + package.readmes = tuple( + root / readme for readme in readme_strs if readme.strip() + ) if "dependencies" in config: cls._add_package_group_dependencies( diff --git a/src/poetry/core/masonry/metadata.py b/src/poetry/core/masonry/metadata.py index 1f97b37a8..ce04ce83d 100644 --- a/src/poetry/core/masonry/metadata.py +++ b/src/poetry/core/masonry/metadata.py @@ -61,11 +61,17 @@ def from_package(cls, package: Package) -> Metadata: with readme.open(encoding="utf-8") as f: descriptions.append(f.read()) except FileNotFoundError as e: - raise FileNotFoundError(f"Readme path `{readme}` does not exist.") from e + raise FileNotFoundError( + f"Readme path `{readme}` does not exist." + ) from e except IsADirectoryError as e: - raise IsADirectoryError(f"Readme path `{readme}` is a directory.") from e + raise IsADirectoryError( + f"Readme path `{readme}` is a directory." + ) from e except PermissionError as e: - raise PermissionError(f"Readme path `{readme}` is not readable.") from e + raise PermissionError( + f"Readme path `{readme}` is not readable." + ) from e meta.description = "\n".join(descriptions) meta.keywords = ",".join(package.keywords) From 8f6fcad2605cd68a657883e41bb8348fd51351c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:58:07 +0200 Subject: [PATCH 4/5] add tests, simplify code --- src/poetry/core/factory.py | 12 ++---- src/poetry/core/masonry/metadata.py | 3 +- tests/masonry/test_metadata.py | 62 +++++++++++++++++++++++++++++ tests/test_factory.py | 23 +++++++++++ 4 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 tests/masonry/test_metadata.py diff --git a/src/poetry/core/factory.py b/src/poetry/core/factory.py index a0394f1b0..5aaa595e0 100644 --- a/src/poetry/core/factory.py +++ b/src/poetry/core/factory.py @@ -151,15 +151,9 @@ def configure_package( package.keywords = config.get("keywords", []) package.classifiers = config.get("classifiers", []) - if "readme" in config: - readme_strs = ( - (config["readme"],) - if isinstance(config["readme"], str) - else config["readme"] - ) - package.readmes = tuple( - root / readme for readme in readme_strs if readme.strip() - ) + if readme := config.get("readme"): + readmes = (readme,) if isinstance(readme, str) else readme + package.readmes = tuple(root / readme for readme in readmes if readme) if "dependencies" in config: cls._add_package_group_dependencies( diff --git a/src/poetry/core/masonry/metadata.py b/src/poetry/core/masonry/metadata.py index ce04ce83d..10f2440db 100644 --- a/src/poetry/core/masonry/metadata.py +++ b/src/poetry/core/masonry/metadata.py @@ -58,8 +58,7 @@ def from_package(cls, package: Package) -> Metadata: descriptions = [] for readme in package.readmes: try: - with readme.open(encoding="utf-8") as f: - descriptions.append(f.read()) + descriptions.append(readme.read_text(encoding="utf-8")) except FileNotFoundError as e: raise FileNotFoundError( f"Readme path `{readme}` does not exist." diff --git a/tests/masonry/test_metadata.py b/tests/masonry/test_metadata.py new file mode 100644 index 000000000..aecd5758c --- /dev/null +++ b/tests/masonry/test_metadata.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING + +import pytest + +from poetry.core.masonry.metadata import Metadata +from poetry.core.packages.package import Package + + +if TYPE_CHECKING: + from pytest_mock import MockerFixture + + +def test_from_package_readme(tmp_path: Path) -> None: + readme_path = tmp_path / "README.md" + readme_path.write_text("This is a description\néöß", encoding="utf-8") + + package = Package("foo", "1.0") + package.readmes = (readme_path,) + + metadata = Metadata.from_package(package) + + assert metadata.description == "This is a description\néöß" + + +def test_from_package_multiple_readmes(tmp_path: Path) -> None: + readme_path1 = tmp_path / "README1.md" + readme_path1.write_text("Description 1", encoding="utf-8") + + readme_path2 = tmp_path / "README2.md" + readme_path2.write_text("Description 2", encoding="utf-8") + + package = Package("foo", "1.0") + package.readmes = (readme_path1, readme_path2) + + metadata = Metadata.from_package(package) + + assert metadata.description == "Description 1\nDescription 2" + + +@pytest.mark.parametrize( + ("exception", "message"), + [ + (FileNotFoundError, "Readme path `MyReadme.md` does not exist."), + (IsADirectoryError, "Readme path `MyReadme.md` is a directory."), + (PermissionError, "Readme path `MyReadme.md` is not readable."), + ], +) +def test_from_package_readme_issues( + mocker: MockerFixture, exception: type[OSError], message: str +) -> None: + package = Package("foo", "1.0") + package.readmes = (Path("MyReadme.md"),) + + mocker.patch("pathlib.Path.read_text", side_effect=exception) + + with pytest.raises(exception) as e: + Metadata.from_package(package) + + assert str(e.value) == message diff --git a/tests/test_factory.py b/tests/test_factory.py index 3d34787e2..defe838bc 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -246,6 +246,29 @@ def test_create_poetry_non_package_mode() -> None: assert not poetry.is_package_mode +def test_create_poetry_no_readme(tmp_path: Path) -> None: + pyproject = tmp_path / "pyproject.toml" + pyproject.write_text( + '[tool.poetry]\nname="foo"\nversion="1"\nauthors = []\ndescription = ""\n', + encoding="utf-8", + ) + poetry = Factory().create_poetry(tmp_path) + + assert not poetry.package.readmes + + +def test_create_poetry_empty_readme(tmp_path: Path) -> None: + pyproject = tmp_path / "pyproject.toml" + pyproject.write_text( + '[tool.poetry]\nname="foo"\nversion="1"\nauthors = []\ndescription = ""\n' + 'readme = ""\n', + encoding="utf-8", + ) + poetry = Factory().create_poetry(tmp_path) + + assert not poetry.package.readmes + + def test_validate() -> None: complete = fixtures_dir / "complete.toml" with complete.open("rb") as f: From c1e12b4bce1ba90b0cc5dbf9786260fdda78a119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 7 Sep 2024 11:12:53 +0200 Subject: [PATCH 5/5] fix tests --- tests/masonry/test_metadata.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/masonry/test_metadata.py b/tests/masonry/test_metadata.py index aecd5758c..d7515faa4 100644 --- a/tests/masonry/test_metadata.py +++ b/tests/masonry/test_metadata.py @@ -6,7 +6,7 @@ import pytest from poetry.core.masonry.metadata import Metadata -from poetry.core.packages.package import Package +from poetry.core.packages.project_package import ProjectPackage if TYPE_CHECKING: @@ -17,7 +17,7 @@ def test_from_package_readme(tmp_path: Path) -> None: readme_path = tmp_path / "README.md" readme_path.write_text("This is a description\néöß", encoding="utf-8") - package = Package("foo", "1.0") + package = ProjectPackage("foo", "1.0") package.readmes = (readme_path,) metadata = Metadata.from_package(package) @@ -32,7 +32,7 @@ def test_from_package_multiple_readmes(tmp_path: Path) -> None: readme_path2 = tmp_path / "README2.md" readme_path2.write_text("Description 2", encoding="utf-8") - package = Package("foo", "1.0") + package = ProjectPackage("foo", "1.0") package.readmes = (readme_path1, readme_path2) metadata = Metadata.from_package(package) @@ -51,7 +51,7 @@ def test_from_package_multiple_readmes(tmp_path: Path) -> None: def test_from_package_readme_issues( mocker: MockerFixture, exception: type[OSError], message: str ) -> None: - package = Package("foo", "1.0") + package = ProjectPackage("foo", "1.0") package.readmes = (Path("MyReadme.md"),) mocker.patch("pathlib.Path.read_text", side_effect=exception)