Skip to content

Commit

Permalink
Support disabling trove classifier verification (#1620)
Browse files Browse the repository at this point in the history
Co-authored-by: Ofek Lev <[email protected]>
  • Loading branch information
mgorny and ofek authored Nov 10, 2024
1 parent 4a97018 commit e1ade75
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 8 deletions.
31 changes: 24 additions & 7 deletions backend/src/hatchling/metadata/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -947,8 +947,6 @@ def classifiers(self) -> list[str]:
if self._classifiers is None:
import bisect

import trove_classifiers

if 'classifiers' in self.config:
classifiers = self.config['classifiers']
if 'classifiers' in self.dynamic:
Expand All @@ -964,23 +962,42 @@ def classifiers(self) -> list[str]:
message = 'Field `project.classifiers` must be an array'
raise TypeError(message)

known_classifiers = trove_classifiers.classifiers | self._extra_classifiers
verify_classifiers = not os.environ.get('HATCH_METADATA_CLASSIFIERS_NO_VERIFY')
if verify_classifiers:
import trove_classifiers

known_classifiers = trove_classifiers.classifiers | self._extra_classifiers
sorted_classifiers = list(trove_classifiers.sorted_classifiers)

for classifier in sorted(self._extra_classifiers - trove_classifiers.classifiers):
bisect.insort(sorted_classifiers, classifier)

unique_classifiers = set()

for i, classifier in enumerate(classifiers, 1):
if not isinstance(classifier, str):
message = f'Classifier #{i} of field `project.classifiers` must be a string'
raise TypeError(message)

if not self.__classifier_is_private(classifier) and classifier not in known_classifiers:
if (
not self.__classifier_is_private(classifier)
and verify_classifiers
and classifier not in known_classifiers
):
message = f'Unknown classifier in field `project.classifiers`: {classifier}'
raise ValueError(message)

unique_classifiers.add(classifier)

sorted_classifiers = list(trove_classifiers.sorted_classifiers)
for classifier in sorted(self._extra_classifiers - trove_classifiers.classifiers):
bisect.insort(sorted_classifiers, classifier)
if not verify_classifiers:
import re

# combined text-numeric sort that ensures that Python versions sort correctly
split_re = re.compile(r'(\D*)(\d*)')
sorted_classifiers = sorted(
classifiers,
key=lambda value: ([(a, int(b) if b else None) for a, b in split_re.findall(value)]),
)

self._classifiers = sorted(
unique_classifiers, key=lambda c: -1 if self.__classifier_is_private(c) else sorted_classifiers.index(c)
Expand Down
27 changes: 26 additions & 1 deletion tests/backend/metadata/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -898,12 +898,37 @@ def test_entry_not_string(self, isolation):
with pytest.raises(TypeError, match='Classifier #1 of field `project.classifiers` must be a string'):
_ = metadata.core.classifiers

def test_entry_unknown(self, isolation):
def test_entry_unknown(self, isolation, monkeypatch):
monkeypatch.delenv('HATCH_METADATA_CLASSIFIERS_NO_VERIFY', False)
metadata = ProjectMetadata(str(isolation), None, {'project': {'classifiers': ['foo']}})

with pytest.raises(ValueError, match='Unknown classifier in field `project.classifiers`: foo'):
_ = metadata.core.classifiers

def test_entry_unknown_no_verify(self, isolation, monkeypatch):
monkeypatch.setenv('HATCH_METADATA_CLASSIFIERS_NO_VERIFY', '1')
classifiers = [
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.9',
'Development Status :: 4 - Beta',
'Private :: Do Not Upload',
'Foo',
]
metadata = ProjectMetadata(str(isolation), None, {'project': {'classifiers': classifiers}})

assert (
metadata.core.classifiers
== metadata.core.classifiers
== [
'Private :: Do Not Upload',
'Development Status :: 4 - Beta',
'Foo',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.11',
]
)

def test_correct(self, isolation):
classifiers = [
'Programming Language :: Python :: 3.11',
Expand Down

0 comments on commit e1ade75

Please sign in to comment.