1- # Copyright 2020 Lynn Root
1+ # Copyright 2020-2024 Lynn Root
22"""Module for generating an SVG badge.
33
44Inspired by `coverage-badge <https://github.com/dbrgn/coverage-badge>`_.
55"""
6+ from __future__ import annotations
67
78import os
89import sys
910
1011from importlib import resources
12+ from typing import Union
1113from xml .dom import minidom
1214
1315
1618except ImportError : # pragma: no cover
1719 cairosvg = None
1820
21+ from interrogate .coverage import InterrogateResults
1922
20- DEFAULT_FILENAME = "interrogate_badge"
21- COLORS = {
23+
24+ NumberType = Union [int , float ]
25+
26+ DEFAULT_FILENAME : str = "interrogate_badge"
27+ COLORS : dict [str , str ] = {
2228 "brightgreen" : "#4c1" ,
2329 "green" : "#97CA00" ,
2430 "yellowgreen" : "#a4a61d" ,
2834 "lightgrey" : "#9f9f9f" ,
2935}
3036
31- COLOR_RANGES = [
37+ COLOR_RANGES : list [ tuple [ int , str ]] = [
3238 (95 , "brightgreen" ),
3339 (90 , "green" ),
3440 (75 , "yellowgreen" ),
3541 (60 , "yellow" ),
3642 (40 , "orange" ),
3743 (0 , "red" ),
3844]
39- SUPPORTED_OUTPUT_FORMATS = ["svg" , "png" ]
45+ SUPPORTED_OUTPUT_FORMATS : list [ str ] = ["svg" , "png" ]
4046# depending on the character length of the result (e.g. 100, 99.9, 9.9)
4147# a few values in the svg template need to adjust so it's readable.
4248# Tuple of values: (svg_width, rect_width, text_x, text_length)
43- SVG_WIDTH_VALUES = {
49+ SVG_WIDTH_VALUES : dict [
50+ str , dict [str , tuple [int , int , NumberType , NumberType ]]
51+ ] = {
4452 # integer
4553 "100" : {
4654 "plastic" : (135 , 43 , 1140 , 330 ),
7179}
7280
7381
74- def save_badge (badge , output , output_format = None ):
82+ def save_badge (
83+ badge : str , output : str , output_format : str | None = None
84+ ) -> str :
7585 """Save badge to the specified path.
7686
7787 .. versionadded:: 1.4.0 new ``output_format`` keyword argument
@@ -116,7 +126,9 @@ def save_badge(badge, output, output_format=None):
116126 return output
117127
118128
119- def _get_badge_measurements (result , style ):
129+ def _get_badge_measurements (
130+ result : float , style : str
131+ ) -> dict [str , NumberType ]:
120132 """Lookup templated style values based on result number."""
121133 if result == 100 :
122134 width_values = SVG_WIDTH_VALUES ["100" ]
@@ -133,15 +145,15 @@ def _get_badge_measurements(result, style):
133145 }
134146
135147
136- def _format_result (result ) :
148+ def _format_result (result : float ) -> str :
137149 """Format result into string for templating."""
138150 # do not include decimal if it's 100
139151 if result == 100 :
140152 return "100"
141153 return f"{ result :.1f} "
142154
143155
144- def get_badge (result , color , style = None ):
156+ def get_badge (result : float , color : str , style : str | None = None ) -> str :
145157 """Generate an SVG from template.
146158
147159 :param float result: coverage % result.
@@ -154,9 +166,9 @@ def get_badge(result, color, style=None):
154166 style = "flat-square-modified"
155167 template_file = f"{ style } -style.svg"
156168 badge_template_values = _get_badge_measurements (result , style )
157- result = _format_result (result )
158- badge_template_values ["result" ] = result
159- badge_template_values ["color" ] = color
169+ formatted_result = _format_result (result )
170+ badge_template_values ["result" ] = formatted_result # type: ignore
171+ badge_template_values ["color" ] = color # type: ignore
160172
161173 if sys .version_info >= (3 , 9 ):
162174 tmpl = (
@@ -171,7 +183,7 @@ def get_badge(result, color, style=None):
171183 return tmpl
172184
173185
174- def should_generate_badge (output , color , result ) :
186+ def should_generate_badge (output : str , color : str , result : float ) -> bool :
175187 """Detect if existing badge needs updating.
176188
177189 This is to help avoid unnecessary newline updates. See
@@ -186,8 +198,8 @@ def should_generate_badge(output, color, result):
186198 logo doesn't exist.
187199
188200 :param str output: path to output badge file
189- :param float result: coverage % result.
190201 :param str color: color of badge.
202+ :param float result: coverage % result.
191203 :return: Whether or not the badge SVG file should be generated.
192204 :rtype: bool
193205 """
@@ -228,13 +240,13 @@ def should_generate_badge(output, color, result):
228240 for t in texts
229241 if t .hasAttribute ("data-interrogate" )
230242 ]
231- result = f"{ result :.1f} %"
232- if result in current_results :
243+ formatted_result = f"{ result :.1f} %"
244+ if formatted_result in current_results :
233245 return False
234246 return True
235247
236248
237- def get_color (result ) :
249+ def get_color (result : float ) -> str :
238250 """Get color for current doc coverage percent.
239251
240252 :param float result: coverage % result
@@ -247,7 +259,12 @@ def get_color(result):
247259 return COLORS ["lightgrey" ]
248260
249261
250- def create (output , result , output_format = None , output_style = None ):
262+ def create (
263+ output : str ,
264+ result : InterrogateResults ,
265+ output_format : str | None = None ,
266+ output_style : str | None = None ,
267+ ) -> str :
251268 """Create a status badge.
252269
253270 The badge file will only be written if it doesn't exist, or if the
@@ -263,6 +280,11 @@ def create(output, result, output_format=None, output_style=None):
263280 :param str output: path to output badge file.
264281 :param coverage.InterrogateResults result: results of coverage
265282 interrogation.
283+ :param str output_format: output format of the badge. Options: "svg", "png".
284+ Default: "svg"
285+ :param str output_style: badge styling. Options: "plastic", "social",
286+ "flat", "flat-square", "flat-square-modified", "for-the-badge".
287+ Default: "flat-square-modified"
266288 :return: path to output badge file.
267289 :rtype: str
268290 """
0 commit comments