diff --git a/poetry/core/factory.py b/poetry/core/factory.py index 003a197ba..749d5e44e 100644 --- a/poetry/core/factory.py +++ b/poetry/core/factory.py @@ -94,7 +94,12 @@ def configure_package( package.classifiers = config.get("classifiers", []) if "readme" in config: - package.readme = root / config["readme"] + if isinstance(config["readme"], list): + package.readmes = tuple(root / readme for readme in config["readme"]) + else: + package.readmes = (root / config["readme"],) + + package.description_type = cls._readme_content_type(package.readmes[0]) if "platform" in config: package.platform = config["platform"] @@ -419,6 +424,14 @@ def validate(cls, config: dict, strict: bool = False) -> Dict[str, List[str]]: ) ) + # Checking readme file types (must match) + if "readme" in config and isinstance(config["readme"], list): + readme_types = [cls._readme_content_type(r) for r in config["readme"]] + if len(set(readme_types)) > 1: + result["errors"].append( + f"Declared README files must be of same type: found {', '.join(readme_types)}" + ) + return result @classmethod @@ -438,3 +451,13 @@ def locate(cls, cwd: Path) -> Path: cwd ) ) + + @staticmethod + def _readme_content_type(path: Union[str, Path]) -> str: + suffix = Path(path).suffix + if suffix == ".rst": + return "text/x-rst" + elif suffix in [".md", ".markdown"]: + return "text/markdown" + else: + return "text/plain" diff --git a/poetry/core/masonry/metadata.py b/poetry/core/masonry/metadata.py index ebdf93f43..e7a643218 100644 --- a/poetry/core/masonry/metadata.py +++ b/poetry/core/masonry/metadata.py @@ -51,9 +51,12 @@ def from_package(cls, package: "Package") -> "Metadata": meta.name = canonicalize_name(package.name) meta.version = normalize_version(package.version.text) meta.summary = package.description - if package.readme: - with package.readme.open(encoding="utf-8") as f: - meta.description = f.read() + if package.readmes: + descriptions = [] + for readme in package.readmes: + with readme.open(encoding="utf-8") as f: + descriptions.append(f.read()) + meta.description = "\n".join(descriptions) meta.keywords = ",".join(package.keywords) meta.home_page = package.homepage or package.repository_url @@ -76,13 +79,8 @@ def from_package(cls, package: "Package") -> "Metadata": meta.requires_dist = [d.to_pep_508() for d in package.requires] # Version 2.1 - if package.readme: - if package.readme.suffix == ".rst": - meta.description_content_type = "text/x-rst" - elif package.readme.suffix in [".md", ".markdown"]: - meta.description_content_type = "text/markdown" - else: - meta.description_content_type = "text/plain" + if package.description_type: + meta.description_content_type = package.description_type meta.provides_extra = [e for e in package.extras] diff --git a/poetry/core/packages/package.py b/poetry/core/packages/package.py index 2c8e8a031..0c008f2e4 100644 --- a/poetry/core/packages/package.py +++ b/poetry/core/packages/package.py @@ -88,7 +88,8 @@ def __init__( self.documentation_url = None self.keywords = [] self._license = None - self.readme = None + self.readmes = () + self.description_type = None self.extras = {} self.requires_extras = [] diff --git a/tests/fixtures/with_readme_files/README-1.rst b/tests/fixtures/with_readme_files/README-1.rst new file mode 100644 index 000000000..265d70d6a --- /dev/null +++ b/tests/fixtures/with_readme_files/README-1.rst @@ -0,0 +1,2 @@ +Single Python +============= diff --git a/tests/fixtures/with_readme_files/README-2.rst b/tests/fixtures/with_readme_files/README-2.rst new file mode 100644 index 000000000..a5693d973 --- /dev/null +++ b/tests/fixtures/with_readme_files/README-2.rst @@ -0,0 +1,2 @@ +Changelog +========= diff --git a/tests/fixtures/with_readme_files/pyproject.toml b/tests/fixtures/with_readme_files/pyproject.toml new file mode 100644 index 000000000..850e51174 --- /dev/null +++ b/tests/fixtures/with_readme_files/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "single-python" +version = "0.1" +description = "Some description." +authors = [ + "Wagner Macedo " +] +license = "MIT" + +readme = [ + "README-1.rst", + "README-2.rst" +] + +homepage = "https://python-poetry.org/" + + +[tool.poetry.dependencies] +python = "2.7.15" diff --git a/tests/fixtures/with_readme_files/single_python.py b/tests/fixtures/with_readme_files/single_python.py new file mode 100644 index 000000000..7ef41c5d4 --- /dev/null +++ b/tests/fixtures/with_readme_files/single_python.py @@ -0,0 +1,3 @@ +"""Example module""" + +__version__ = "0.1" diff --git a/tests/masonry/builders/test_builder.py b/tests/masonry/builders/test_builder.py index 590266421..bee8e8980 100644 --- a/tests/masonry/builders/test_builder.py +++ b/tests/masonry/builders/test_builder.py @@ -260,3 +260,16 @@ def test_builder_convert_script_files(fixture, result): project_root = Path(__file__).parent / "fixtures" / fixture script_files = Builder(Factory().create_poetry(project_root)).convert_script_files() assert [p.relative_to(project_root) for p in script_files] == result + + +def test_metadata_with_readme_files(): + test_path = Path(__file__).parent.parent.parent / "fixtures" / "with_readme_files" + builder = Builder(Factory().create_poetry(test_path)) + + metadata = Parser().parsestr(builder.get_metadata_content()) + + readme1 = test_path / "README-1.rst" + readme2 = test_path / "README-2.rst" + description = "\n".join([readme1.read_text(), readme2.read_text(), ""]) + + assert metadata.get_payload() == description diff --git a/tests/test_factory.py b/tests/test_factory.py index 76836b60f..5f7211b0e 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -23,7 +23,7 @@ def test_create_poetry(): assert package.authors == ["Sébastien Eustace "] assert package.license.id == "MIT" assert ( - package.readme.relative_to(fixtures_dir).as_posix() + package.readmes[0].relative_to(fixtures_dir).as_posix() == "sample_project/README.rst" ) assert package.homepage == "https://python-poetry.org" @@ -185,6 +185,26 @@ def test_validate_fails(): assert Factory.validate(content) == {"errors": [expected], "warnings": []} +def test_validate_multiple_readme_files(): + with_readme_files = TOMLFile(fixtures_dir / "with_readme_files" / "pyproject.toml") + content = with_readme_files.read()["tool"]["poetry"] + + assert Factory.validate(content, strict=True) == {"errors": [], "warnings": []} + + +def test_validate_fails_on_readme_files_with_unmatching_types(): + with_readme_files = TOMLFile(fixtures_dir / "with_readme_files" / "pyproject.toml") + content = with_readme_files.read()["tool"]["poetry"] + content["readme"][0] = "README.md" + + assert Factory.validate(content, strict=True) == { + "errors": [ + "Declared README files must be of same type: found text/markdown, text/x-rst" + ], + "warnings": [], + } + + def test_create_poetry_fails_on_invalid_configuration(): with pytest.raises(RuntimeError) as e: Factory().create_poetry(