Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check project against valid and deprecated trove classifiers. #2881

Merged
merged 1 commit into from Sep 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
81 changes: 28 additions & 53 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Expand Up @@ -67,6 +67,7 @@ requests-toolbelt = "^0.9.1"
shellingham = "^1.5"
# exclude 0.11.2 and 0.11.3 due to https://github.com/sdispater/tomlkit/issues/225
tomlkit = ">=0.11.1,<1.0.0,!=0.11.2,!=0.11.3"
trove-classifiers = "^2022.5.19"
# exclude 20.4.5 - 20.4.6 due to https://github.com/pypa/pip/issues/9953
virtualenv = "^20.4.3,!=20.4.5,!=20.4.6"
xattr = { version = "^0.9.7", markers = "sys_platform == 'darwin'" }
Expand Down
53 changes: 53 additions & 0 deletions src/poetry/console/commands/check.py
Expand Up @@ -9,6 +9,52 @@ class CheckCommand(Command):
name = "check"
description = "Checks the validity of the <comment>pyproject.toml</comment> file."

def validate_classifiers(
self, project_classifiers: set[str]
) -> tuple[list[str], list[str]]:
"""Identify unrecognized and deprecated trove classifiers.

A fully-qualified classifier is a string delimited by `` :: `` separators. To
make the error message more readable we need to have visual clues to
materialize the start and end of a classifier string. That way the user can
easily copy and paste it from the messages while reducing mistakes because of
extra spaces.

We use ``!r`` (``repr()``) for classifiers and list of classifiers for
consistency. That way all strings will be rendered with the same kind of quotes
(i.e. simple tick: ``'``).
"""
from trove_classifiers import classifiers
from trove_classifiers import deprecated_classifiers

errors = []
warnings = []

unrecognized = sorted(
project_classifiers - set(classifiers) - set(deprecated_classifiers)
)
if unrecognized:
errors.append(f"Unrecognized classifiers: {unrecognized!r}.")

deprecated = sorted(
project_classifiers.intersection(set(deprecated_classifiers))
)
if deprecated:
for old_classifier in deprecated:
new_classifiers = deprecated_classifiers[old_classifier]
if new_classifiers:
message = (
f"Deprecated classifier {old_classifier!r}. "
f"Must be replaced by {new_classifiers!r}."
)
else:
message = (
f"Deprecated classifier {old_classifier!r}. Must be removed."
)
warnings.append(message)

return errors, warnings

def handle(self) -> int:
from poetry.core.pyproject.toml import PyProjectTOML

Expand All @@ -18,6 +64,13 @@ def handle(self) -> int:
poetry_file = Factory.locate(Path.cwd())
config = PyProjectTOML(poetry_file).poetry_config
check_result = Factory.validate(config, strict=True)

# Validate trove classifiers
project_classifiers = set(config.get("classifiers", []))
errors, warnings = self.validate_classifiers(project_classifiers)
check_result["errors"].extend(errors)
check_result["warnings"].extend(warnings)

if not check_result["errors"] and not check_result["warnings"]:
self.info("All set!")

Expand Down
6 changes: 6 additions & 0 deletions tests/console/commands/test_check.py
Expand Up @@ -41,10 +41,16 @@ def test_check_invalid(mocker: MockerFixture, tester: CommandTester):

expected = """\
Error: 'description' is a required property
Error: Unrecognized classifiers: ['Intended Audience :: Clowns'].
Warning: A wildcard Python dependency is ambiguous.\
Consider specifying a more explicit one.
Warning: The "pendulum" dependency specifies the "allows-prereleases" property,\
which is deprecated. Use "allow-prereleases" instead.
Warning: Deprecated classifier 'Natural Language :: Ukranian'.\
Must be replaced by ['Natural Language :: Ukrainian'].
Warning: Deprecated classifier\
'Topic :: Communications :: Chat :: AOL Instant Messenger'.\
Must be removed.
"""

assert tester.io.fetch_error() == expected
6 changes: 6 additions & 0 deletions tests/fixtures/invalid_pyproject/pyproject.toml
Expand Up @@ -5,6 +5,12 @@ authors = [
"Foo <foo@bar.com>"
]
license = "INVALID"
classifiers = [
"Environment :: Console",
"Intended Audience :: Clowns",
"Natural Language :: Ukranian",
"Topic :: Communications :: Chat :: AOL Instant Messenger",
]

[tool.poetry.dependencies]
python = "*"
Expand Down