From f691320294cf076349d8a915687716b43b087bf7 Mon Sep 17 00:00:00 2001 From: "Y.D.X" <73375426+YDX-2147483647@users.noreply.github.com> Date: Sat, 17 Jun 2023 15:40:39 +0800 Subject: [PATCH] `poetry check` command validates readme (files must exist) (#7444) --- docs/pyproject.md | 6 +++++ src/poetry/console/commands/check.py | 26 +++++++++++++++++-- tests/console/commands/test_check.py | 1 + .../fixtures/invalid_pyproject/pyproject.toml | 1 + tests/fixtures/private_pyproject/README.md | 0 5 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/private_pyproject/README.md diff --git a/docs/pyproject.md b/docs/pyproject.md index a344ffc0db5..f123313d883 100644 --- a/docs/pyproject.md +++ b/docs/pyproject.md @@ -114,6 +114,12 @@ The file(s) can be of any format, but if you intend to publish to PyPI keep the https://packaging.python.org/en/latest/guides/making-a-pypi-friendly-readme/) in mind. README paths are implicitly relative to `pyproject.toml`. +{{% note %}} +Whether paths are case-sensitive follows platform defaults, but it is recommended to keep cases. + +To be specific, you can set `readme = "rEaDmE.mD"` for `README.md` on macOS and Windows, but Linux users can't `poetry install` after cloning your repo. This is because macOS and Windows are case-insensitive and case-preserving. +{{% /note %}} + The contents of the README file(s) are used to populate the [Description field](https://packaging.python.org/en/latest/specifications/core-metadata/#description-optional) of your distribution's metadata (similar to `long_description` in setuptools). diff --git a/src/poetry/console/commands/check.py b/src/poetry/console/commands/check.py index 733f0a7c5d5..95bd9912195 100644 --- a/src/poetry/console/commands/check.py +++ b/src/poetry/console/commands/check.py @@ -1,10 +1,16 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from cleo.helpers import option from poetry.console.commands.command import Command +if TYPE_CHECKING: + from pathlib import Path + + class CheckCommand(Command): name = "check" description = ( @@ -23,7 +29,7 @@ class CheckCommand(Command): ), ] - def validate_classifiers( + def _validate_classifiers( self, project_classifiers: set[str] ) -> tuple[list[str], list[str]]: """Identify unrecognized and deprecated trove classifiers. @@ -73,6 +79,17 @@ def validate_classifiers( return errors, warnings + def _validate_readme(self, readme: str | list[str], poetry_file: Path) -> list[str]: + """Check existence of referenced readme files""" + + readmes = [readme] if isinstance(readme, str) else readme + + errors = [] + for name in readmes: + if not (poetry_file.parent / name).exists(): + errors.append(f"Declared README file does not exist: {name}") + return errors + def handle(self) -> int: from poetry.factory import Factory from poetry.pyproject.toml import PyProjectTOML @@ -84,10 +101,15 @@ def handle(self) -> int: # Validate trove classifiers project_classifiers = set(config.get("classifiers", [])) - errors, warnings = self.validate_classifiers(project_classifiers) + errors, warnings = self._validate_classifiers(project_classifiers) check_result["errors"].extend(errors) check_result["warnings"].extend(warnings) + # Validate readme (files must exist) + if "readme" in config: + errors = self._validate_readme(config["readme"], poetry_file) + check_result["errors"].extend(errors) + # Verify that lock file is consistent if self.option("lock") and not self.poetry.locker.is_locked(): check_result["errors"] += ["poetry.lock was not found."] diff --git a/tests/console/commands/test_check.py b/tests/console/commands/test_check.py index 6347d4585fb..aeed833002a 100644 --- a/tests/console/commands/test_check.py +++ b/tests/console/commands/test_check.py @@ -81,6 +81,7 @@ def test_check_invalid( Error: 'description' is a required property Error: Project name (invalid) is same as one of its dependencies Error: Unrecognized classifiers: ['Intended Audience :: Clowns']. +Error: Declared README file does not exist: never/exists.md Error: poetry.lock was not found. Warning: A wildcard Python dependency is ambiguous.\ Consider specifying a more explicit one. diff --git a/tests/fixtures/invalid_pyproject/pyproject.toml b/tests/fixtures/invalid_pyproject/pyproject.toml index 55b0b6282af..bafa0936489 100644 --- a/tests/fixtures/invalid_pyproject/pyproject.toml +++ b/tests/fixtures/invalid_pyproject/pyproject.toml @@ -4,6 +4,7 @@ version = "1.0.0" authors = [ "Foo " ] +readme = "never/exists.md" license = "INVALID" classifiers = [ "Environment :: Console", diff --git a/tests/fixtures/private_pyproject/README.md b/tests/fixtures/private_pyproject/README.md new file mode 100644 index 00000000000..e69de29bb2d