This repository has been archived on 2024-06-20. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
coffee.pygments/tests/contrast/test_contrasts.py
2023-02-01 23:26:15 +01:00

100 lines
2.7 KiB
Python

"""
Contrast Tests
~~~~~~~~~~
Pygments styles should be accessible to people with suboptimal vision.
This test ensures that the minimum contrast of styles does not degrade,
and that every rule of a new style fulfills the WCAG AA standard.[1]
[1]: https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html
"""
import json
import os
import pygments.styles
import pygments.token
import wcag_contrast_ratio
JSON_FILENAME = os.path.join(os.path.dirname(__file__), "min_contrasts.json")
WCAG_AA_CONTRAST = 4.5
def hex2rgb(hexstr):
hexstr = hexstr.lstrip("#")
r = int(hexstr[:2], 16) / 255
g = int(hexstr[2:4], 16) / 255
b = int(hexstr[4:], 16) / 255
return (r, g, b)
def get_style_contrasts(style_cls):
return [
(
round(
wcag_contrast_ratio.rgb(
hex2rgb(style["bgcolor"] or style_cls.background_color),
hex2rgb(style["color"] or "#000000")
# we default to black because browsers also do
),
1,
),
ttype,
)
for ttype, style in style_cls.list_styles()
if ttype != pygments.token.Whitespace
]
def builtin_styles():
for style_name in pygments.styles.STYLE_MAP:
yield (style_name, pygments.styles.get_style_by_name(style_name))
def min_contrasts():
return {
name: min(x[0] for x in get_style_contrasts(style))
for name, style in builtin_styles()
}
def update_json():
with open(JSON_FILENAME, "w", encoding="utf-8") as f:
json.dump(
min_contrasts(),
f,
indent=2,
)
def test_contrasts(fail_if_improved=True):
with open(JSON_FILENAME, encoding="utf-8") as f:
previous_contrasts = json.load(f)
for style_name in pygments.styles.STYLE_MAP:
style = pygments.styles.get_style_by_name(style_name)
contrasts = get_style_contrasts(style)
min_contrast = min([x[0] for x in contrasts])
bar = previous_contrasts.get(style_name, WCAG_AA_CONTRAST)
assert not min_contrast < bar, (
"contrast degradation for style '{}'\n"
"The following rules have a contrast lower than the required {}:\n\n"
"{}\n"
).format(
style_name,
bar,
"\n".join(
[
"* {:.2f} {}".format(contrast, ttype)
for contrast, ttype in contrasts
if contrast < bar
]
),
)
if fail_if_improved:
assert (
not min_contrast > bar
), "congrats, you improved a contrast! please run ./scripts/update_contrasts.py"