From 2925295a0ad729912b22071a6bd523c7ead51c2a Mon Sep 17 00:00:00 2001 From: Jon Grace-Cox Date: Wed, 27 Sep 2017 21:12:41 -0400 Subject: [PATCH] Add ability to choose text color (#6) --- CHANGELOG.md | 1 + README.rst | 429 ++++++++++++++++++++++++++------------------------- anybadge.py | 25 ++- test.py | 2 +- 4 files changed, 240 insertions(+), 217 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7309e33..735be59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # 0.2.0 - Removed bright green color (including pylint and coverage defaults) (#7) +- Add ability to choose text color (#6) # 0.1.0 - Initial release. diff --git a/README.rst b/README.rst index 7fcd95b..d1fad73 100644 --- a/README.rst +++ b/README.rst @@ -49,10 +49,10 @@ Here is the same example implemented in Python code:: import anybadge # Define thresholds: <2=red, <4=orange <8=yellow <10=green - thresholds = {thresholds={2: 'red', - 4: 'orange', - 6: 'yellow', - 10: 'green',}) + thresholds = {2: 'red', + 4: 'orange', + 6: 'yellow', + 10: 'green'} badge = anybadge.Badge('pylint', 2.22, thresholds=thresholds) @@ -91,39 +91,43 @@ Options ------- These are the command line options:: - positional arguments: - args Pairs of =. For example 2=red 4=orange - 8=yellow 10=green. Read this as "Less - than 2 = red, less than 4 = orange...". + positional arguments: + args Pairs of =. For example 2=red 4=orange + 6=yellow 8=good. Read this as "Less than 2 = red, less + than 4 = orange...". - optional arguments: - -h, --help show this help message and exit - -l LABEL, --label LABEL - The badge label. - -v VALUE, --value VALUE - The badge value. - -m VALUE_FORMAT, --value-format VALUE_FORMAT - Formatting string for value (e.g. "%.2f" for 2dp - floats) - -c COLOR, --color COLOR - For fixed color badges use --colorto specify the badge - color. - -p PREFIX, --prefix PREFIX - Optional prefix for value. - -s SUFFIX, --suffix SUFFIX - Optional suffix for value. - -d PADDING, --padding PADDING - Number of characters to pad on either side of the - badge text. - -n FONT, --font FONT "DejaVu Sans,Verdana,Geneva,sans-serif" - -z FONT_SIZE, --font-size FONT_SIZE - Font size. - -t TEMPLATE, --template TEMPLATE - Location of alternative template .svg file. - -u, --use-max Use the maximum threshold color when the value exceeds - the maximum threshold. - -f FILE, --file FILE Output file location. - -o, --overwrite Overwrite output file if it already exists. + optional arguments: + -h, --help show this help message and exit + -l LABEL, --label LABEL + The badge label. + -v VALUE, --value VALUE + The badge value. + -m VALUE_FORMAT, --value-format VALUE_FORMAT + Formatting string for value (e.g. "%.2f" for 2dp + floats) + -c COLOR, --color COLOR + For fixed color badges use --colorto specify the badge + color. + -p PREFIX, --prefix PREFIX + Optional prefix for value. + -s SUFFIX, --suffix SUFFIX + Optional suffix for value. + -d PADDING, --padding PADDING + Number of characters to pad on either side of the + badge text. + -n FONT, --font FONT "DejaVu Sans,Verdana,Geneva,sans-serif" + -z FONT_SIZE, --font-size FONT_SIZE + Font size. + -t TEMPLATE, --template TEMPLATE + Location of alternative template .svg file. + -u, --use-max Use the maximum threshold color when the value exceeds + the maximum threshold. + -f FILE, --file FILE Output file location. + -o, --overwrite Overwrite output file if it already exists. + -r TEXT_COLOR, --text-color TEXT_COLOR + Text color. Single value affects both labeland value + colors. A comma separated pair affects label and value + text respectively. Examples -------- @@ -149,186 +153,187 @@ Python usage ============ Here is the output of ``help(anybadge)``:: - Help on module anybadge: + Help on module anybadge: - NAME - anybadge - anybadge + NAME + anybadge - anybadge - FILE - anybadge.py + FILE + /home/jon/Git/anybadge/anybadge.py - DESCRIPTION - A Python module for generating badges for your projects, with a focus on - simplicity and flexibility. + DESCRIPTION + A Python module for generating badges for your projects, with a focus on + simplicity and flexibility. - CLASSES - __builtin__.object - Badge - - class Badge(__builtin__.object) - | Badge class used to generate badges. - | - | Examples: - | - | Create a simple green badge: - | - | >>> badge = Badge('label', 123, default_color='green') - | - | Write a badge to file, overwriting any existing file: - | - | >>> badge = Badge('label', 123, default_color='green') - | >>> badge.write_badge('demo.svg', overwrite=True) - | - | Here are a number of examples showing thresholds, since there - | are certain situations that may not be obvious: - | - | >>> badge = Badge('pipeline', 'passing', thresholds={'passing': 'green', 'failing': 'red'}) - | >>> badge.badge_color - | 'green' - | - | 2.32 is not <2 - | 2.32 is < 4, so 2.32 yields orange - | >>> badge = Badge('pylint', 2.32, thresholds={2: 'red', - | ... 4: 'orange', - | ... 8: 'yellow', - | ... 10: 'green'}) - | >>> badge.badge_color - | 'orange' - | - | 6 is not <6 - | 6 is < 8, so 6 yields green - | >>> badge = Badge('pylint', 6, thresholds={2: 'red', - | ... 4: 'orange', - | ... 8: 'yellow', - | ... 10: 'green'}) - | >>> badge.badge_color - | 'green' - | - | 11 is not <10, but use_max_when_value_exceeds defaults to - | True, so 11 yields green - | >>> badge = Badge('pylint', 11, thresholds={2: 'red', - | ... 4: 'orange', - | ... 8: 'yellow', - | ... 10: 'green'}) - | >>> badge.badge_color - | 'green' - | - | 11 is not <10, and use_max_when_value_exceeds is set to - | False, so 11 yields the default color '#a4a61d' - | >>> badge = Badge('pylint', 11, use_max_when_value_exceeds=False, - | ... thresholds={2: 'red', 4: 'orange', 8: 'yellow', - | ... 10: 'green'}) - | >>> badge.badge_color - | '#a4a61d' - | - | Methods defined here: - | - | __init__(self, label, value, font_name='DejaVu Sans,Verdana,Geneva,sans-serif', font_size=11, num_padding_chars=0.5, template='\n{{ value }}\n \n', value_prefix='', value_suffix='', thresholds=None, default_color='#a4a61d', use_max_when_value_exceeds=True, value_format=None) - | Constructor for Badge class. - | - | get_text_width(self, text) - | Return the width of text. - | - | This implementation assumes a fixed font of: - | - | font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11" - | >>> badge = Badge('x', 1, font_name='DejaVu Sans,Verdana,Geneva,sans-serif', font_size=11) - | >>> badge.get_text_width('pylint') - | 42 - | - | write_badge(self, file_path, overwrite=False) - | Write badge to file. - | - | ---------------------------------------------------------------------- - | Static methods defined here: - | - | get_font_width(font_name, font_size) - | Return the width multiplier for a font. - | - | >>> Badge.get_font_width('DejaVu Sans,Verdana,Geneva,sans-serif', 11) - | 7 - | - | ---------------------------------------------------------------------- - | Data descriptors defined here: - | - | __dict__ - | dictionary for instance variables (if defined) - | - | __weakref__ - | list of weak references to the object (if defined) - | - | badge_color - | Find the badge color based on the thresholds. - | - | badge_color_code - | Return the color code for the badge. - | - | badge_svg_text - | The badge SVG text. - | - | badge_width - | The total width of badge. - | - | >>> badge = Badge('pylint', '5', font_name='DejaVu Sans,Verdana,Geneva,sans-serif', - | ... font_size=11) - | >>> badge.badge_width - | 91 - | - | color_split_position - | The SVG x position where the color split should occur. - | - | font_width - | Return the badge font width. - | - | label_anchor - | The SVG x position of the middle anchor for the label text. - | - | label_anchor_shadow - | The SVG x position of the label shadow anchor. - | - | label_width - | The SVG width of the label text. - | - | value_anchor - | The SVG x position of the middle anchor for the value text. - | - | value_anchor_shadow - | The SVG x position of the value shadow anchor. - | - | value_is_float - | Identify whether the value text is a float. - | - | value_is_int - | Identify whether the value text is an int. - | - | value_type - | The Python type associated with the value. - | - | value_width - | The SVG width of the value text. + CLASSES + __builtin__.object + Badge - FUNCTIONS - main() - Generate a badge based on command line arguments. - - parse_args() - Parse the command line arguments. + class Badge(__builtin__.object) + | Badge class used to generate badges. + | + | Examples: + | + | Create a simple green badge: + | + | >>> badge = Badge('label', 123, default_color='green') + | + | Write a badge to file, overwriting any existing file: + | + | >>> badge = Badge('label', 123, default_color='green') + | >>> badge.write_badge('demo.svg', overwrite=True) + | + | Here are a number of examples showing thresholds, since there + | are certain situations that may not be obvious: + | + | >>> badge = Badge('pipeline', 'passing', thresholds={'passing': 'green', 'failing': 'red'}) + | >>> badge.badge_color + | 'green' + | + | 2.32 is not <2 + | 2.32 is < 4, so 2.32 yields orange + | >>> badge = Badge('pylint', 2.32, thresholds={2: 'red', + | ... 4: 'orange', + | ... 8: 'yellow', + | ... 10: 'green'}) + | >>> badge.badge_color + | 'orange' + | + | 8 is not <8 + | 8 is <4, so 8 yields orange + | >>> badge = Badge('pylint', 6, thresholds={2: 'red', + | ... 4: 'orange', + | ... 8: 'yellow', + | ... 10: 'green'}) + | >>> badge.badge_color + | 'green' + | + | 10 is not <8, but use_max_when_value_exceeds defaults to + | True, so 10 yields green + | >>> badge = Badge('pylint', 11, thresholds={2: 'red', + | ... 4: 'orange', + | ... 8: 'yellow', + | ... 10: 'green'}) + | >>> badge.badge_color + | 'green' + | + | 11 is not <10, and use_max_when_value_exceeds is set to + | False, so 11 yields the default color '#a4a61d' + | >>> badge = Badge('pylint', 11, use_max_when_value_exceeds=False, + | ... thresholds={2: 'red', 4: 'orange', 8: 'yellow', + | ... 10: 'green'}) + | >>> badge.badge_color + | '#a4a61d' + | + | Methods defined here: + | + | __init__(self, label, value, font_name='DejaVu Sans,Verdana,Geneva,sans-serif', font_size=11, num_padding_chars=0.5, template='\n{{ value }}\n \n', value_prefix='', value_suffix='', thresholds=None, default_color='#a4a61d', use_max_when_value_exceeds=True, value_format=None, text_color='#fff') + | Constructor for Badge class. + | + | get_text_width(self, text) + | Return the width of text. + | + | This implementation assumes a fixed font of: + | + | font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11" + | >>> badge = Badge('x', 1, font_name='DejaVu Sans,Verdana,Geneva,sans-serif', font_size=11) + | >>> badge.get_text_width('pylint') + | 42 + | + | write_badge(self, file_path, overwrite=False) + | Write badge to file. + | + | ---------------------------------------------------------------------- + | Static methods defined here: + | + | get_font_width(font_name, font_size) + | Return the width multiplier for a font. + | + | >>> Badge.get_font_width('DejaVu Sans,Verdana,Geneva,sans-serif', 11) + | 7 + | + | ---------------------------------------------------------------------- + | Data descriptors defined here: + | + | __dict__ + | dictionary for instance variables (if defined) + | + | __weakref__ + | list of weak references to the object (if defined) + | + | badge_color + | Find the badge color based on the thresholds. + | + | badge_color_code + | Return the color code for the badge. + | + | badge_svg_text + | The badge SVG text. + | + | badge_width + | The total width of badge. + | + | >>> badge = Badge('pylint', '5', font_name='DejaVu Sans,Verdana,Geneva,sans-serif', + | ... font_size=11) + | >>> badge.badge_width + | 91 + | + | color_split_position + | The SVG x position where the color split should occur. + | + | font_width + | Return the badge font width. + | + | label_anchor + | The SVG x position of the middle anchor for the label text. + | + | label_anchor_shadow + | The SVG x position of the label shadow anchor. + | + | label_width + | The SVG width of the label text. + | + | value_anchor + | The SVG x position of the middle anchor for the value text. + | + | value_anchor_shadow + | The SVG x position of the value shadow anchor. + | + | value_is_float + | Identify whether the value text is a float. + | + | value_is_int + | Identify whether the value text is an int. + | + | value_type + | The Python type associated with the value. + | + | value_width + | The SVG width of the value text. - DATA - BADGE_TEMPLATES = {'coverage': {'label': 'coverage', 'suffix': '%', 't... - COLORS = {'green': '#97CA00', 'lightgrey': '#9f... - DEFAULT_COLOR = '#a4a61d' - DEFAULT_FONT = 'DejaVu Sans,Verdana,Geneva,sans-serif' - DEFAULT_FONT_SIZE = 11 - FONT_WIDTHS = {'DejaVu Sans,Verdana,Geneva,sans-serif': {11: 7}} - NUM_PADDING_CHARS = 0.5 - TEMPLATE_SVG = '\n - + {{ label }} {{ label }} + + {{ value }} {{ value }} @@ -141,7 +144,7 @@ class Badge(object): def __init__(self, label, value, font_name=DEFAULT_FONT, font_size=DEFAULT_FONT_SIZE, num_padding_chars=NUM_PADDING_CHARS, template=TEMPLATE_SVG, value_prefix='', value_suffix='', thresholds=None, default_color=DEFAULT_COLOR, - use_max_when_value_exceeds=True, value_format=None): + use_max_when_value_exceeds=True, value_format=None, text_color=DEFAULT_TEXT_COLOR): """Constructor for Badge class.""" self.label = label self.value = value @@ -156,6 +159,14 @@ class Badge(object): self.template = template self.thresholds = thresholds self.default_color = default_color + + # text_color can be passed as a single value or a pair of comma delimited values + text_colors = text_color.split(',') + self.label_text_color = text_colors[0] + self.value_text_color = text_colors[0] + if len(text_colors) > 1: + self.value_text_color = text_colors[1] + self.use_max_when_value_exceeds = use_max_when_value_exceeds @property @@ -263,6 +274,8 @@ class Badge(object): .replace('{{ value anchor }}', str(self.value_anchor)) \ .replace('{{ value anchor shadow }}', str(self.value_anchor_shadow)) \ .replace('{{ color }}', self.badge_color_code) \ + .replace('{{ label text color }}', self.label_text_color) \ + .replace('{{ value text color }}', self.value_text_color) \ .replace('{{ color split x }}', str(self.color_split_position)) \ .replace('{{ value width }}', str(self.badge_width - self.color_split_position)) @@ -414,6 +427,10 @@ examples: parser.add_argument('-f', '--file', type=str, help='Output file location.') parser.add_argument('-o', '--overwrite', action='store_true', help='Overwrite output file if it already exists.') + parser.add_argument('-r', '--text-color', type=str, help='Text color. Single value affects both label' + 'and value colors. A comma separated pair ' + 'affects label and value text respectively.', + default=DEFAULT_TEXT_COLOR) parser.add_argument('args', nargs=argparse.REMAINDER, help='Pairs of =. ' 'For example 2=red 4=orange 6=yellow 8=good. ' 'Read this as "Less than 2 = red, less than 4 = orange...".') @@ -452,7 +469,7 @@ def main(): default_color=args.color, num_padding_chars=args.padding, font_name=args.font, font_size=args.font_size, template=args.template, use_max_when_value_exceeds=args.use_max, thresholds=threshold_dict, - value_format=args.value_format) + value_format=args.value_format, text_color=args.text_color) if args.file: # Write badge SVG to file diff --git a/test.py b/test.py index c3fb468..2869a0d 100755 --- a/test.py +++ b/test.py @@ -10,6 +10,6 @@ if __name__ == '__main__': thresholds={2: 'red', 4: 'orange', 6: 'green', 8: 'brightgreen'} badge = anybadge.Badge('test', '2.22', value_suffix='%', - thresholds=thresholds) + thresholds=thresholds, text_color='#010101,#101010') print(badge.badge_svg_text)