From 48eedcec0b18341e7cc89e4a448d5f34f126b53c Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Tue, 24 Mar 2020 12:29:33 -0500 Subject: [PATCH 1/7] Add InvalidClassifier exception, better tests --- _internal/exceptions.py | 2 ++ _internal/models.py | 5 ++++- tests/test_classifiers.py | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 _internal/exceptions.py diff --git a/_internal/exceptions.py b/_internal/exceptions.py new file mode 100644 index 0000000..f1d15ef --- /dev/null +++ b/_internal/exceptions.py @@ -0,0 +1,2 @@ +class InvalidClassifier(Exception): + pass diff --git a/_internal/models.py b/_internal/models.py index bafbb18..bc32b84 100644 --- a/_internal/models.py +++ b/_internal/models.py @@ -1,3 +1,6 @@ +from _internal.exceptions import InvalidClassifier + + class ClassifierRoot: def __init__(self, children): self.children = children @@ -23,7 +26,7 @@ def __init__( skip=False, ): if deprecated_by and not deprecated: - raise Exception( + raise InvalidClassifier( "Using deprecated_by, but not marking the classifier as deprecated" ) diff --git a/tests/test_classifiers.py b/tests/test_classifiers.py index d2a7ff0..2ea3bd6 100644 --- a/tests/test_classifiers.py +++ b/tests/test_classifiers.py @@ -1,6 +1,7 @@ import pytest from _internal.models import ClassifierRoot, ClassifierNode +from _internal.exceptions import InvalidClassifier def test_nested_prefixes(): @@ -38,5 +39,9 @@ def test_skip(): def test_bad_deprecation_failure(): - with pytest.raises(Exception): + with pytest.raises(InvalidClassifier) as excinfo: ClassifierNode("blah", deprecated_by=["spam"]) + + assert excinfo.value.args == ( + "Using deprecated_by, but not marking the classifier as deprecated", + ) From d0e120b28716f70dfc6d6675f883025d5072c4e7 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Tue, 24 Mar 2020 12:56:46 -0500 Subject: [PATCH 2/7] Make tests more clear --- tests/test_classifiers.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_classifiers.py b/tests/test_classifiers.py index 2ea3bd6..670c053 100644 --- a/tests/test_classifiers.py +++ b/tests/test_classifiers.py @@ -14,10 +14,10 @@ def test_nested_prefixes(): ] ) - assert root.generate() == [ - ClassifierNode("Foo"), - ClassifierNode("Foo :: Bar"), - ClassifierNode("Foo :: Bar :: Baz"), + assert [node.full_name for node in root.generate()] == [ + "Foo", + "Foo :: Bar", + "Foo :: Bar :: Baz", ] @@ -32,9 +32,9 @@ def test_skip(): ] ) - assert root.generate() == [ - ClassifierNode("Foo :: Bar"), - ClassifierNode("Foo :: Bar :: Baz"), + assert [node.full_name for node in root.generate()] == [ + "Foo :: Bar", + "Foo :: Bar :: Baz", ] From 0a7a990d21ea0787103fd624f4bf228374b002f0 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Tue, 24 Mar 2020 13:27:58 -0500 Subject: [PATCH 3/7] Don't allow private classifiers --- _internal/models.py | 3 +++ tests/test_classifiers.py | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/_internal/models.py b/_internal/models.py index bc32b84..fcab383 100644 --- a/_internal/models.py +++ b/_internal/models.py @@ -30,6 +30,9 @@ def __init__( "Using deprecated_by, but not marking the classifier as deprecated" ) + if short_name.lower().startswith("private"): + raise InvalidClassifier("Classifiers starting with 'Private' are invalid") + self.short_name = short_name self.prefix_list = [] self.deprecated = deprecated diff --git a/tests/test_classifiers.py b/tests/test_classifiers.py index 670c053..9c7d6b9 100644 --- a/tests/test_classifiers.py +++ b/tests/test_classifiers.py @@ -45,3 +45,16 @@ def test_bad_deprecation_failure(): assert excinfo.value.args == ( "Using deprecated_by, but not marking the classifier as deprecated", ) + + +@pytest.mark.parametrize( + "parent, child", + [("Private", "Foo"), ("private", "Foo"), ("Foo", "Private"), ("Foo", "private"),], +) +def test_private_classifier_failure(parent, child): + with pytest.raises(InvalidClassifier) as excinfo: + ClassifierNode( + parent, children=[ClassifierNode(child)], + ) + + assert excinfo.value.args == ("Classifiers starting with 'Private' are invalid",) From fb45ed25ef0165bac489e6f8ef9d44bd218ab514 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Tue, 24 Mar 2020 13:28:21 -0500 Subject: [PATCH 4/7] Don't allow classifiers that start/end with whitespace --- _internal/models.py | 5 +++++ tests/test_classifiers.py | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/_internal/models.py b/_internal/models.py index fcab383..59b7acd 100644 --- a/_internal/models.py +++ b/_internal/models.py @@ -33,6 +33,11 @@ def __init__( if short_name.lower().startswith("private"): raise InvalidClassifier("Classifiers starting with 'Private' are invalid") + if short_name.strip().rstrip() != short_name: + raise InvalidClassifier( + "Classifiers starting or ending with whitespace are invalid" + ) + self.short_name = short_name self.prefix_list = [] self.deprecated = deprecated diff --git a/tests/test_classifiers.py b/tests/test_classifiers.py index 9c7d6b9..7a69fe6 100644 --- a/tests/test_classifiers.py +++ b/tests/test_classifiers.py @@ -58,3 +58,13 @@ def test_private_classifier_failure(parent, child): ) assert excinfo.value.args == ("Classifiers starting with 'Private' are invalid",) + + +@pytest.mark.parametrize("classifier", [" Foo", "Foo "]) +def test_whitespace_classifier_failure(classifier): + with pytest.raises(InvalidClassifier) as excinfo: + ClassifierNode(classifier) + + assert excinfo.value.args == ( + "Classifiers starting or ending with whitespace are invalid", + ) From 8f1e587fba03f2763716bfef7bdb0732233f504a Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Tue, 24 Mar 2020 13:57:36 -0500 Subject: [PATCH 5/7] Don't allow classifiers that contain colons --- _internal/models.py | 3 +++ tests/test_classifiers.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/_internal/models.py b/_internal/models.py index 59b7acd..12617be 100644 --- a/_internal/models.py +++ b/_internal/models.py @@ -38,6 +38,9 @@ def __init__( "Classifiers starting or ending with whitespace are invalid" ) + if ":" in short_name: + raise InvalidClassifier("Classifiers containing ':' are invalid") + self.short_name = short_name self.prefix_list = [] self.deprecated = deprecated diff --git a/tests/test_classifiers.py b/tests/test_classifiers.py index 7a69fe6..c11cb6b 100644 --- a/tests/test_classifiers.py +++ b/tests/test_classifiers.py @@ -68,3 +68,11 @@ def test_whitespace_classifier_failure(classifier): assert excinfo.value.args == ( "Classifiers starting or ending with whitespace are invalid", ) + + +@pytest.mark.parametrize("classifier", ["Foo:", "Foo :: Bar"]) +def test_colon_classifier_failure(classifier): + with pytest.raises(InvalidClassifier) as excinfo: + ClassifierNode(classifier) + + assert excinfo.value.args == ("Classifiers containing ':' are invalid",) From b35bfe5bff92d36f80b441d64476fa583bafe5d1 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Tue, 24 Mar 2020 15:09:49 -0500 Subject: [PATCH 6/7] Remove unnecessary import --- setup.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup.py b/setup.py index 5a6d2fa..deb5a01 100644 --- a/setup.py +++ b/setup.py @@ -3,8 +3,6 @@ from setuptools import setup, find_packages -from trove_classifiers import classifiers - here = path.abspath(path.dirname(__file__)) # Get the long description from the README file From f64d86abb71cb0ea65a964e61587b51699afaf7a Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Tue, 24 Mar 2020 15:10:32 -0500 Subject: [PATCH 7/7] Fix imports --- Makefile | 4 ++-- _internal/classifiers.py | 2 +- _internal/generator.py | 2 +- _internal/models.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 907ba08..465b8e9 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,12 @@ BINDIR = $(PWD)/.state/env/bin $(BINDIR)/python -m pip install -r requirements/dev.txt build: .state/env/pyvenv.cfg - $(BINDIR)/python _internal/generator.py + $(BINDIR)/python -m _internal.generator test: .state/env/pyvenv.cfg $(BINDIR)/pytest $(eval TMPDIR := $(shell mktemp -d)) - $(BINDIR)/python _internal/generator.py --output $(TMPDIR)/test.py + $(BINDIR)/python -m _internal.generator --output $(TMPDIR)/test.py diff trove_classifiers/__init__.py $(TMPDIR)/test.py lint: .state/env/pyvenv.cfg diff --git a/_internal/classifiers.py b/_internal/classifiers.py index 5687f6b..84ed928 100644 --- a/_internal/classifiers.py +++ b/_internal/classifiers.py @@ -1,4 +1,4 @@ -from models import ClassifierRoot, ClassifierNode +from .models import ClassifierRoot, ClassifierNode classifiers = ClassifierRoot( children=[ diff --git a/_internal/generator.py b/_internal/generator.py index 910a085..1a904bd 100644 --- a/_internal/generator.py +++ b/_internal/generator.py @@ -4,7 +4,7 @@ from jinja2 import Template -from classifiers import classifiers +from .classifiers import classifiers parser = argparse.ArgumentParser() parser.add_argument( diff --git a/_internal/models.py b/_internal/models.py index 12617be..9d3b8fa 100644 --- a/_internal/models.py +++ b/_internal/models.py @@ -1,4 +1,4 @@ -from _internal.exceptions import InvalidClassifier +from .exceptions import InvalidClassifier class ClassifierRoot: