Merge pull request #15 from jongracecox/14-fix-extra-padding-around-long-value-text

14 fix extra padding around long value text
This commit is contained in:
Jon Grace-Cox
2019-06-01 03:42:36 -04:00
committed by GitHub
9 changed files with 530 additions and 238 deletions

9
.gitignore vendored
View File

@@ -105,3 +105,12 @@ ENV/
.DS_Store
demo.svg
# py.test
.pytest_cache
# SVG files generated by the unittests
test_badge_*.svg
# html coverage report
htmlcov/

View File

@@ -1,12 +1,16 @@
dist: xenial
language: python
python:
- '2.7'
- '3.5'
- '3.6'
- '3.7'
install:
- pip install -U setuptools pip -r build-requirements.txt
script:
- python ./test.py
- pytest --doctest-modules --cov=anybadge anybadge.py tests
before_deploy:
- sed -i "s/^version = .*/version = __version__ = \"$TRAVIS_TAG\"/" anybadge.py
deploy:
- provider: pypi
user: jongracecox
@@ -16,12 +20,4 @@ deploy:
on:
tags: true
all_branches: true
python: '3.6'
- provider: pypi
user: jongracecox
password:
secure: "TwKVv2wGesF3zHMtSzC/whgtBfHOG03wYS8bUOeeH4x8g5wQIu9SVyrYSffYE3FxapHbMCzmx7A3IgP4Ma6v4Ik6HqJY7a5DY/na0bcuI40IyCM2J0S0Hbq4E7WXaCCe6t7C5KE7NO3QzIcZboSZBWb78mcKLB2XbuIWMPCXqayGhqh8hynQmhwQ4C5b+jpBXlLtm6+AFH7eJOSdl8iO39RU5TL6FrOjgmks/KvTO0yHaXxmBoRcVudZsv9sAGsUx/UtRA65FPViIgu/dEV8cNtz7HOtL4v9x1mkvsiHF7OJiB1KCzSdUSCI83JSjdh44jjlNx0x2SnPbbwmCR7hi53xszMLbAHqY27hK1O4ntR1Iaui8HhBx8inxwS5z271xEQ9HZ8W9veRaxXxGkzj3LKGzjYflK1UN/ZK2syy5+cF4AEUpqEuQYi2waGhMxxWRo5KA05RLXetvsJYFEHUlATq9aXjMv29yH77KzySgpZe/Emd+Hb7r/7TKDeWXRaWDtUa+lc7G5oHLn6Kmm0iM1lerFKalEO9eoZwO2m1+O47CJ5yTKw1mNsC5Dj6EhG1QeonJWPS5z32vjNvnzRm2psbInt00SE2ClPxY5ASQOdcCMkq4ELGUHVssOGlniVYILs+tiwzrDTaXcckf8lvVvx6CiXfmFY+JYK9q3HYEuE="
distributions: sdist bdist_wheel
on:
branch: master
python: '3.6'
python: '3.7'

375
README.md
View File

@@ -208,185 +208,218 @@ Here is the output of ``help(anybadge)``::
Help on module anybadge:
NAME
anybadge - anybadge
FILE
/home/jon/Git/anybadge/anybadge.py
anybadge - anybadge
DESCRIPTION
A Python module for generating badges for your projects, with a focus on
simplicity and flexibility.
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'
|
| 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='<?xml version="1.0" encoding="UTF-8"?>\n<svg xmln...hor }}" y="14">{{ value }}</text>\n </g>\n</svg>', 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.
builtins.object
Badge
class Badge(builtins.object)
| Badge(label, value, font_name='DejaVu Sans,Verdana,Geneva,sans-serif', font_size=11, num_padding_chars=0.5, template='<?xml version="1.0" encoding="UTF-8"?>\n<svg xmlns="http://www.w3.org/2000/svg" width="{{ badge width }}" height="20">\n <linearGradient id="b" x2="0" y2="100%">\n <stop offset="0" stop-color="#bbb" stop-opacity=".1"/>\n <stop offset="1" stop-opacity=".1"/>\n </linearGradient>\n <mask id="a">\n <rect width="{{ badge width }}" height="20" rx="3" fill="#fff"/>\n </mask>\n <g mask="url(#a)">\n <path fill="#555" d="M0 0h{{ color split x }}v20H0z"/>\n <path fill="{{ color }}" d="M{{ color split x }} 0h{{ value width }}v20H{{ color split x }}z"/>\n <path fill="url(#b)" d="M0 0h{{ badge width }}v20H0z"/>\n </g>\n <g fill="{{ label text color }}" text-anchor="middle" font-family="{{ font name }}" font-size="{{ font size }}">\n <text x="{{ label anchor shadow }}" y="15" fill="#010101" fill-opacity=".3">{{ label }}</text>\n <text x="{{ label anchor }}" y="14">{{ label }}</text>\n </g>\n <g fill="{{ value text color }}" text-anchor="middle" font-family="{{ font name }}" font-size="{{ font size }}">\n <text x="{{ value anchor shadow }}" y="15" fill="#010101" fill-opacity=".3">{{ value }}</text>\n <text x="{{ value anchor }}" y="14">{{ value }}</text>\n </g>\n</svg>', value_prefix='', value_suffix='', thresholds=None, default_color='#4c1', use_max_when_value_exceeds=True, value_format=None, text_color='#fff')
|
| 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', 8, 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 '#4c1'
| >>> badge = Badge('pylint', 11, use_max_when_value_exceeds=False,
| ... thresholds={2: 'red', 4: 'orange', 8: 'yellow',
| ... 10: 'green'})
| >>> badge.badge_color
| '#4c1'
|
| Methods defined here:
|
| __init__(self, label, value, font_name='DejaVu Sans,Verdana,Geneva,sans-serif', font_size=11, num_padding_chars=0.5, template='<?xml version="1.0" encoding="UTF-8"?>\n<svg xmlns="http://www.w3.org/2000/svg" width="{{ badge width }}" height="20">\n <linearGradient id="b" x2="0" y2="100%">\n <stop offset="0" stop-color="#bbb" stop-opacity=".1"/>\n <stop offset="1" stop-opacity=".1"/>\n </linearGradient>\n <mask id="a">\n <rect width="{{ badge width }}" height="20" rx="3" fill="#fff"/>\n </mask>\n <g mask="url(#a)">\n <path fill="#555" d="M0 0h{{ color split x }}v20H0z"/>\n <path fill="{{ color }}" d="M{{ color split x }} 0h{{ value width }}v20H{{ color split x }}z"/>\n <path fill="url(#b)" d="M0 0h{{ badge width }}v20H0z"/>\n </g>\n <g fill="{{ label text color }}" text-anchor="middle" font-family="{{ font name }}" font-size="{{ font size }}">\n <text x="{{ label anchor shadow }}" y="15" fill="#010101" fill-opacity=".3">{{ label }}</text>\n <text x="{{ label anchor }}" y="14">{{ label }}</text>\n </g>\n <g fill="{{ value text color }}" text-anchor="middle" font-family="{{ font name }}" font-size="{{ font size }}">\n <text x="{{ value anchor shadow }}" y="15" fill="#010101" fill-opacity=".3">{{ value }}</text>\n <text x="{{ value anchor }}" y="14">{{ value }}</text>\n </g>\n</svg>', value_prefix='', value_suffix='', thresholds=None, default_color='#4c1', 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.
|
| Args:
| text(str): Text to get the pixel width of.
|
| Returns:
| int: Pixel width of the given text based on the badges selected font.
|
| 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')
| 34
|
| write_badge(self, file_path, overwrite=False)
| Write badge to file.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| badge_color
| Badge color based on the configured thresholds.
|
| Returns: str
|
| badge_color_code
| Return the color code for the badge.
|
| Returns: str
|
| badge_svg_text
| The badge SVG text.
|
| Returns: str
|
| badge_width
| The total width of badge.
|
| Returns: int
|
| Examples:
|
| >>> badge = Badge('pylint', '5')
| >>> badge.badge_width
| 103
|
| color_split_position
| The SVG x position where the color split should occur.
|
| Returns: int
|
| font_width
| Return the width multiplier for a font.
|
| Returns:
| int: Maximum pixel width of badges selected font.
|
| Example:
|
| >>> Badge(label='x', value='1').font_width
| 10
|
| label_anchor
| The SVG x position of the middle anchor for the label text.
|
| Returns: float
|
| label_anchor_shadow
| The SVG x position of the label shadow anchor.
|
| Returns: float
|
| label_width
| The SVG width of the label text.
|
| Returns: int
|
| value_anchor
| The SVG x position of the middle anchor for the value text.
|
| Returns: float
|
| value_anchor_shadow
| The SVG x position of the value shadow anchor.
|
| Returns: float
|
| value_is_float
| Identify whether the value text is a float.
|
| Returns: bool
|
| value_is_int
| Identify whether the value text is an int.
|
| Returns: bool
|
| value_type
| The Python type associated with the value.
|
| Returns: type
|
| value_width
| The SVG width of the value text.
|
| Returns: int
FUNCTIONS
main()
Generate a badge based on command line arguments.
parse_args()
Parse the command line arguments.
main()
Generate a badge based on command line arguments.
parse_args()
Parse the command line arguments.
DATA
BADGE_TEMPLATES = {'coverage': {'label': 'coverage', 'suffix': '%', 't...
COLORS = {'green': '#97CA00', 'lightgrey': '#9f9f9f', 'orange': '#fe7d...
DEFAULT_COLOR = '#a4a61d'
DEFAULT_FONT = 'DejaVu Sans,Verdana,Geneva,sans-serif'
DEFAULT_FONT_SIZE = 11
DEFAULT_TEXT_COLOR = '#fff'
FONT_WIDTHS = {'DejaVu Sans,Verdana,Geneva,sans-serif': {11: 7}}
NUM_PADDING_CHARS = 0.5
TEMPLATE_SVG = '<?xml version="1.0" encoding="UTF-8"?>\n<svg xmln...ho...
__summary__ = 'A simple, flexible badge generator.'
__title__ = 'anybadge'
__uri__ = 'https://github.com/jongracecox/anybadge'
__version__ = '0.2.0.dev1'
__version_info__ = ('0', '2', '0', 'dev1')
version = '0.2.0.dev1'
BADGE_TEMPLATES = {'coverage': {'label': 'coverage', 'suffix': '%', 't...
COLORS = {'green': '#4c1', 'lightgrey': '#9f9f9f', 'orange': '#fe7d37'...
DEFAULT_COLOR = '#4c1'
DEFAULT_FONT = 'DejaVu Sans,Verdana,Geneva,sans-serif'
DEFAULT_FONT_SIZE = 11
DEFAULT_TEXT_COLOR = '#fff'
FONT_WIDTHS = {'DejaVu Sans,Verdana,Geneva,sans-serif': {11: 10}}
NUM_PADDING_CHARS = 0.5
TEMPLATE_SVG = '<?xml version="1.0" encoding="UTF-8"?>\n<svg xmln...ho...
__summary__ = 'A simple, flexible badge generator.'
__title__ = 'anybadge'
__uri__ = 'https://github.com/jongracecox/anybadge'
__version_info__ = ('0', '0', '0')
digits = '0123456789'
version = '0.0.0'
VERSION
0.2.0.dev1
0.0.0
```

View File

@@ -8,8 +8,9 @@ simplicity and flexibility.
import os
import re
# Package information
version = __version__ = "0.1.0.dev2"
version = __version__ = "0.0.0"
__version_info__ = tuple(re.split('[.-]', __version__))
__title__ = "anybadge"
__summary__ = "A simple, flexible badge generator."
@@ -27,7 +28,7 @@ DEFAULT_TEXT_COLOR = '#fff'
# supported fonts and font sizes.
FONT_WIDTHS = {
'DejaVu Sans,Verdana,Geneva,sans-serif': {
11: 7
11: 10
}
}
@@ -171,7 +172,10 @@ class Badge(object):
@property
def value_is_float(self):
"""Identify whether the value text is a float."""
"""Identify whether the value text is a float.
Returns: bool
"""
try:
_ = float(self.value)
except ValueError:
@@ -181,7 +185,10 @@ class Badge(object):
@property
def value_is_int(self):
"""Identify whether the value text is an int."""
"""Identify whether the value text is an int.
Returns: bool
"""
try:
a = float(self.value)
b = int(a)
@@ -192,7 +199,10 @@ class Badge(object):
@property
def value_type(self):
"""The Python type associated with the value."""
"""The Python type associated with the value.
Returns: type
"""
if self.value_is_float:
return float
elif self.value_is_int:
@@ -202,60 +212,96 @@ class Badge(object):
@property
def label_width(self):
"""The SVG width of the label text."""
return self.get_text_width(self.label)
"""The SVG width of the label text.
Returns: int
"""
return int(self.get_text_width(self.label) + (2.0 * self.num_padding_chars * self.font_width))
@property
def value_width(self):
"""The SVG width of the value text."""
return self.get_text_width(str(self.value_text))
"""The SVG width of the value text.
Returns: int
"""
return int(self.get_text_width(str(self.value_text)) + (self.num_padding_chars * self.font_width))
@property
def font_width(self):
"""Return the badge font width."""
return self.get_font_width(font_name=self.font_name, font_size=self.font_size)
"""Return the width multiplier for a font.
Returns:
int: Maximum pixel width of badges selected font.
Example:
>>> Badge(label='x', value='1').font_width
10
"""
return FONT_WIDTHS[self.font_name][self.font_size]
@property
def color_split_position(self):
"""The SVG x position where the color split should occur."""
return self.get_text_width(' ') + self.label_width + \
int(float(self.font_width) * float(self.num_padding_chars))
"""The SVG x position where the color split should occur.
Returns: int
"""
return int(self.font_width + self.label_width +
float(self.font_width) * float(self.num_padding_chars))
@property
def label_anchor(self):
"""The SVG x position of the middle anchor for the label text."""
"""The SVG x position of the middle anchor for the label text.
Returns: float
"""
return self.color_split_position / 2
@property
def value_anchor(self):
"""The SVG x position of the middle anchor for the value text."""
"""The SVG x position of the middle anchor for the value text.
Returns: float
"""
return self.color_split_position + ((self.badge_width - self.color_split_position) / 2)
@property
def label_anchor_shadow(self):
"""The SVG x position of the label shadow anchor."""
"""The SVG x position of the label shadow anchor.
Returns: float
"""
return self.label_anchor + 1
@property
def value_anchor_shadow(self):
"""The SVG x position of the value shadow anchor."""
"""The SVG x position of the value shadow anchor.
Returns: float
"""
return self.value_anchor + 1
@property
def badge_width(self):
"""The total width of badge.
>>> badge = Badge('pylint', '5', font_name='DejaVu Sans,Verdana,Geneva,sans-serif',
... font_size=11)
>>> badge.badge_width
91
Returns: int
Examples:
>>> badge = Badge('pylint', '5')
>>> badge.badge_width
103
"""
return self.get_text_width(' ' + ' ' * int(float(self.num_padding_chars) * 2.0)) \
+ self.label_width + self.value_width
padding = int(self.font_width * (self.num_padding_chars + 3))
return padding + self.label_width + self.value_width
@property
def badge_svg_text(self):
"""The badge SVG text."""
"""The badge SVG text.
Returns: str
"""
# Identify whether template is a file or the actual template text
if len(self.template.split('\n')) == 1:
@@ -279,30 +325,29 @@ class Badge(object):
.replace('{{ color split x }}', str(self.color_split_position)) \
.replace('{{ value width }}', str(self.badge_width - self.color_split_position))
@staticmethod
def 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
"""
return FONT_WIDTHS[font_name][font_size]
def get_text_width(self, text):
"""Return the width of text.
Args:
text(str): Text to get the pixel width of.
Returns:
int: Pixel width of the given text based on the badges selected font.
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
34
"""
return len(text) * self.get_font_width(self.font_name, self.font_size)
return _get_approx_string_width(text, self.font_width)
@property
def badge_color(self):
"""Find the badge color based on the thresholds."""
"""Badge color based on the configured thresholds.
Returns: str"""
# If no thresholds were passed then return the default color
if not self.thresholds:
return self.default_color
@@ -331,7 +376,10 @@ class Badge(object):
@property
def badge_color_code(self):
"""Return the color code for the badge."""
"""Return the color code for the badge.
Returns: str
"""
color = self.badge_color
if color[0] == '#':
return color
@@ -357,6 +405,113 @@ class Badge(object):
file_handle.write(self.badge_svg_text)
# Based on the following SO answer: https://stackoverflow.com/a/16008023/6252525
def _get_approx_string_width(text, font_width, fixed_width=False):
"""
Get the approximate width of a string using a specific average font width.
Args:
text(str): Text string to calculate width of.
font_width(int): Average width of font characters.
fixed_width(bool): Indicates that the font is fixed width.
Returns:
int: Width of string in pixels.
Examples:
Call the function with a string and the maximum character width of the font you are using:
>>> int(_get_approx_string_width('hello', 10))
29
This example shows the comparison of simplistic calculation based on a fixed width.
Given a test string and a fixed font width of 10, we can calculate the width
by multiplying the length and the font character with:
>>> test_string = 'GOOGLE|ijkl'
>>> _get_approx_string_width(test_string, 10, fixed_width=True)
110
Since some characters in the string are thinner than others we expect that the
apporximate text width will be narrower than the fixed width calculation:
>>> _get_approx_string_width(test_string, 10)
77
"""
if fixed_width:
return len(text) * font_width
size = 0.0
# A dictionary containing percentages that relate to how wide
# each character will be represented in a variable width font.
# These percentages can be calculated using the ``_get_character_percentage_dict`` function.
char_width_percentages = {
"lij|' ": 40.0,
'![]fI.,:;/\\t': 50.0,
'`-(){}r"': 60.0,
'*^zcsJkvxy': 70.0,
'aebdhnopqug#$L+<>=?_~FZT0123456789': 70.0,
'BSPEAKVXY&UwNRCHD': 70.0,
'QGOMm%W@': 100.0
}
for s in text:
percentage = 100.0
for k in char_width_percentages.keys():
if s in k:
percentage = char_width_percentages[k]
break
size += (percentage / 100.0) * float(font_width)
return int(size)
# This is a helper function that can be used to generate alternate dictionaries
# for the _get_approx_string_width function. The function is not needed for
# normal operation of this package, and since it depends on the PIL package,
# which is not included in the dependencies the function will remain commented out.
#
# def _get_character_percentage_dict(font_path, font_size):
# """Get the dictionary used to estimate variable width font text lengths.
#
# Args:
# font_path(str): Path to valid font file.
# font_size(int): Font size to use.
#
# Returns: dict
#
# This function can be used to calculate the dictionary used in the
# ``get_approx_string_width`` function.
#
# Examples:
# >>> _get_character_percentage_dict('/Library/Fonts/Verdana.ttf', 9) # doctest: +ELLIPSIS
# {"lij|' ": 40, '![]fI.,:;/\\\\t': 50, '`-(){}r"': 60, '*^zcsJkvxy': 70, ...
# """
# from PIL import ImageFont
#
# # List of groups in size order, smallest to largest
# char_width_groups = [
# "lij|' ",
# '![]fI.,:;/\\t',
# '`-(){}r"',
# '*^zcsJkvxy',
# 'aebdhnopqug#$L+<>=?_~FZT' + digits,
# 'BSPEAKVXY&UwNRCHD',
# 'QGOMm%W@',
# ]
#
# def get_largest_in_group(group):
# """Get the widest character from the group."""
# return max([ImageFont.truetype(font_path, font_size).getsize(c)[0] for c in group])
#
# largest = char_width_groups[-1]
# font_width = get_largest_in_group(largest)
# return {group: int((get_largest_in_group(group) / font_width) * 100)
# for group in char_width_groups}
def parse_args():
"""Parse the command line arguments."""
import argparse
@@ -477,5 +632,6 @@ def main():
else:
print(badge.badge_svg_text)
if __name__ == '__main__':
main()

View File

@@ -1,4 +1,5 @@
mister-bump>=1.0.0
m2r
restructuredtext_lint
pygments
pytest
pytest-cov

View File

@@ -1,6 +1,7 @@
#!/usr/bin/python
import os
import re
from setuptools import setup
from mister_bump import bump
from m2r import parse_from_file
import restructuredtext_lint
@@ -16,16 +17,22 @@ if errors:
raise ValueError('README.md contains errors: ',
', '.join([e.message for e in errors]))
# Attempt to get version number from TravisCI environment variable
version = os.environ.get('TRAVIS_TAG', default='0.0.0')
# Remove leading 'v'
version = re.sub('^v', '', version)
setup(
name='anybadge',
description='Simple, flexible badge generator for project badges.',
long_description=rst_readme,
version=bump(),
version=version,
author='Jon Grace-Cox',
author_email='jongracecox@gmail.com',
py_modules=['anybadge', 'anybadge_server'],
setup_requires=['setuptools', 'wheel'],
tests_require=[],
tests_require=['unittest'],
install_requires=[],
data_files=[],
options={

15
test.py
View File

@@ -1,15 +0,0 @@
#!/usr/bin/python
"""
anybadge test module.
"""
import anybadge
if __name__ == '__main__':
thresholds={2: 'red', 4: 'orange', 6: 'green', 8: 'brightgreen'}
badge = anybadge.Badge('test', '2.22', value_suffix='%',
thresholds=thresholds, text_color='#010101,#101010')
print(badge.badge_svg_text)

0
tests/__init__.py Normal file
View File

105
tests/test_anybadge.py Normal file
View File

@@ -0,0 +1,105 @@
from unittest import TestCase
from anybadge import Badge
class TestAnybadge(TestCase):
"""Test case class for anybadge package."""
def test_badge_width_with_long_value_text(self):
"""Test the width of a badge generated with a long text value."""
badge = Badge(label='CppCheck',
value='err: 2 | warn: 9 | info: 99 | style: 365',
default_color='red')
badge.write_badge('test_badge_1.svg', overwrite=True)
self.assertLessEqual(badge.badge_width, 326)
def test_badge_width_with_long_value_text_zero_padding(self):
"""Test the width of a badge generated with a long text value."""
badge = Badge(label='CppCheck',
value='err: 2 | warn: 9 | info: 99 | style: 365',
default_color='red',
num_padding_chars=0)
badge.write_badge('test_badge_2.svg', overwrite=True)
self.assertLessEqual(badge.badge_width, 306)
def test_badge_width_with_medium_value_text(self):
"""Test the width of a badge generated with a medium text value."""
badge = Badge(label='medium',
value='89.67%',
default_color='green')
badge.write_badge('test_badge_3.svg', overwrite=True)
self.assertLessEqual(badge.badge_width, 138)
def test_badge_width_with_medium_value_text_zero_pad(self):
"""Test the width of a badge generated with a medium text value."""
badge = Badge(label='medium',
value='89.67%',
default_color='green',
num_padding_chars=0)
badge.write_badge('test_badge_4.svg', overwrite=True)
self.assertLessEqual(badge.badge_width, 118)
def test_badge_width_with_short_value_text(self):
"""Test the width of a badge generated with a short text value."""
badge = Badge(label='short',
value='1',
default_color='green')
badge.write_badge('test_badge_5.svg', overwrite=True)
self.assertLessEqual(badge.badge_width, 101)
def test_badge_width_with_short_value_text_zero_pad(self):
"""Test the width of a badge generated with a short text value."""
badge = Badge(label='short',
value='1',
default_color='green',
num_padding_chars=0)
badge.write_badge('test_badge_6.svg', overwrite=True)
self.assertLessEqual(badge.badge_width, 81)
def test_badge_width_with_tiny_value_text(self):
"""Test the width of a badge generated with a short text value."""
badge = Badge(label='a',
value='1',
default_color='green')
badge.write_badge('test_badge_7.svg', overwrite=True)
self.assertLessEqual(badge.badge_width, 76)
def test_badge_with_thresholds(self):
"""Test generating a badge using thresholds."""
thresholds = {
2: 'red', 4: 'orange', 6: 'green', 8: 'brightgreen'
}
badge = Badge('test', '2.22', value_suffix='%',
thresholds=thresholds)
badge.write_badge('test_badge_8.svg')
def test_badge_with_text_color(self):
"""Test generating a badge with alternate text_color."""
badge = Badge('test', '2.22', value_suffix='%',
text_color='#010101,#101010')
badge.write_badge('test_badge_9.svg')