From 9d4470a1a0b2fc955b17abcd09a2ebf2bca12d91 Mon Sep 17 00:00:00 2001 From: Jon Grace-Cox Date: Tue, 18 Jul 2023 09:31:59 -0700 Subject: [PATCH] Allow badges with no value or no label (#89) This commit allows badges to be generated with only a label or only a value. Badges must provide at least a label or a value, so it is not valid to create a badge with no label and no value. This will result in a `ValueError` being raised. --- README.md | 10 ++++++++ anybadge/badge.py | 14 +++++++++++ anybadge/cli.py | 9 ++----- build_examples.py | 6 +++-- docker/test/shell_tests.sh | 10 ++++++++ examples/label_only.svg | 23 ++++++++++++++++++ examples/value_only.svg | 23 ++++++++++++++++++ tests/test_anybadge.py | 48 +++++++++++++++++++++++++++++++++----- 8 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 examples/label_only.svg create mode 100644 examples/value_only.svg diff --git a/README.md b/README.md index 21218ae..fcf9e18 100644 --- a/README.md +++ b/README.md @@ -317,6 +317,16 @@ Here are some examples to show how to use padding to fix layout: | ![](https://cdn.rawgit.com/jongracecox/anybadge/master/examples/pipeline_smile.svg) | `anybadge.Badge("Pipeline status", "😄")` | | ![](https://cdn.rawgit.com/jongracecox/anybadge/master/examples/pipeline_smile_padding.svg) | `anybadge.Badge("Pipeline status", "😄", num_value_padding_chars=1)` | +### Value or label only + +It is possible to create badges with only a label or only a value. This can be done by passing +an empty string to the appropriate field. Note that either a label or value must be provided. + +| Badge | Code | +|---------------------------------------------------------------------------------|--------------------------------------| +| ![](https://cdn.rawgit.com/jongracecox/anybadge/master/examples/label_only.svg) | `anybadge.Badge(label="Label only")` | +| ![](https://cdn.rawgit.com/jongracecox/anybadge/master/examples/value_only.svg) | `anybadge.Badge(value="Value only")` | + ### Semantic version support Anybadge supports semantic versions for value and threshold keys. This supports color-coded diff --git a/anybadge/badge.py b/anybadge/badge.py index a8b6b54..d21e1df 100644 --- a/anybadge/badge.py +++ b/anybadge/badge.py @@ -153,6 +153,14 @@ class Badge: self.label = label self.value = value + if self.label is None: + self.label = "" + if self.value is None: + self.value = "" + + if len(str(self.label)) == 0 and len(str(self.value)) == 0: + raise ValueError("Either a label or a value must be provided for a badge.") + self.value_is_version = semver self.value_format = value_format @@ -414,6 +422,9 @@ class Badge: Returns: int """ + if len(str(self.label)) == 0: + return 0 + return int( self.get_text_width(str(self.label)) + (2.0 * self.num_label_padding_chars * self.font_width) @@ -433,6 +444,9 @@ class Badge: Returns: int """ + if len(str(self.value_text)) == 0: + return 0 + return int( self.get_text_width(str(self.value_text)) + (2.0 * self.num_value_padding_chars * self.font_width) diff --git a/anybadge/cli.py b/anybadge/cli.py index b46e925..1f76bd2 100644 --- a/anybadge/cli.py +++ b/anybadge/cli.py @@ -52,10 +52,8 @@ examples: """ ), ) - parser.add_argument("-l", "--label", type=str, help="The badge label.") - parser.add_argument( - "-v", "--value", type=str, help="The badge value.", required=True - ) + parser.add_argument("-l", "--label", type=str, help="The badge label.", default="") + parser.add_argument("-v", "--value", type=str, help="The badge value.", default="") parser.add_argument( "-m", "--value-format", @@ -196,9 +194,6 @@ def main(args=None): if not args.suffix and style.suffix: suffix = style.suffix - if not label: - raise ValueError("Label has not been set. Please use --label argument.") - # Create threshold list from args threshold_list = [x.split("=") for x in threshold_text] threshold_dict = {x[0]: x[1] for x in threshold_list} diff --git a/build_examples.py b/build_examples.py index e39b531..1eb5259 100644 --- a/build_examples.py +++ b/build_examples.py @@ -24,7 +24,7 @@ def color_examples_table(): ) -def emoji_examples(): +def other_examples(): """Generate emoji example badges used in documentation.""" examples_dir = Path(__file__).parent / Path("examples") for label, value, file, kwargs in [ @@ -38,6 +38,8 @@ def emoji_examples(): ("Pipeline status", "😟", "pipeline_frown.svg", {"default_color": "Red"}), ("🔗", "Documentation", "documentation_link.svg", {}), ("🔗", "PyPi", "pypi_link.svg", {}), + ("", "Value only", "value_only.svg", {}), + ("Label only", "", "label_only.svg", {}), ]: anybadge.Badge(label=label, value=value, **kwargs).write_badge( examples_dir / Path(file), overwrite=True @@ -46,7 +48,7 @@ def emoji_examples(): def main(): color_examples_table() - emoji_examples() + other_examples() if __name__ == "__main__": diff --git a/docker/test/shell_tests.sh b/docker/test/shell_tests.sh index aa2e736..ed055f6 100755 --- a/docker/test/shell_tests.sh +++ b/docker/test/shell_tests.sh @@ -34,6 +34,16 @@ anybadge --label="Label" --value="Value" --file "${TEST_FILES}/test_command_line check_rc echo "OK" +echo -n "Testing with no label..." +anybadge --value="Value" --file "${TEST_FILES}/test_command_line_no_label.svg" +check_rc +echo "OK" + +echo -n "Testing with no value..." +anybadge --label="Label" --file "${TEST_FILES}/test_command_line_no_value.svg" +check_rc +echo "OK" + echo -n "Testing python -m call... " python -m anybadge --label="Label" --value="Value" --file "${TEST_FILES}/test_m_command_line.svg" check_rc diff --git a/examples/label_only.svg b/examples/label_only.svg new file mode 100644 index 0000000..27372bb --- /dev/null +++ b/examples/label_only.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + Label only + Label only + + + + + + diff --git a/examples/value_only.svg b/examples/value_only.svg new file mode 100644 index 0000000..7e79946 --- /dev/null +++ b/examples/value_only.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + Value only + Value only + + diff --git a/tests/test_anybadge.py b/tests/test_anybadge.py index c5c369a..47ad8f9 100644 --- a/tests/test_anybadge.py +++ b/tests/test_anybadge.py @@ -328,12 +328,6 @@ class TestAnybadge(TestCase): ] ) - def test_main_missing_value(self): - with self.assertRaisesRegex( - ValueError, r"Label has not been set\. Please use --label argument\." - ): - main(["--value", "123", "--file", "test_badge_main.svg", "--overwrite"]) - def test_version_comparison(self): # Define thresholds: <3.0.0=red, <3.2.0=orange <999.0.0=green badge = Badge( @@ -410,3 +404,45 @@ class TestAnybadge(TestCase): output_module = subprocess.check_output(["python", "-m", "anybadge", "--help"]) output_script = subprocess.check_output(["anybadge", "--help"]) self.assertEqual(output_module, output_script) + + def test_badge_with_no_label(self): + """Test the dimensions for a badge with no label.""" + badge = Badge( + label="", + value="Value", + ) + self.assertEqual( + badge.label_width, + 0, + "Expected label width to be 0 for badge with no label.", + ) + + def test_badge_with_no_value(self): + """Test the dimensions for a badge with no value.""" + badge = Badge( + label="Label", + value="", + ) + self.assertEqual( + badge.value_width, + 0, + "Expected value width to be 0 for badge with no value.", + ) + + def test_badge_with_no_label_and_no_value(self): + """Test that an exception is raised when trying to create a badge with no label or value.""" + with self.assertRaisesRegex( + ValueError, r"Either a label or a value must be provided for a badge\." + ): + _ = Badge( + label="", + value="", + ) + + with self.assertRaisesRegex( + ValueError, r"Either a label or a value must be provided for a badge\." + ): + _ = Badge( + label=None, + value=None, + )