Skip to content

generating higher resolution exceptions for the vnu validator¤

the vnu validator is now available on conda which means it is easier to test your html

    import pandas, pathlib, json, collections, exceptiongroup, re, dataclasses
    file = "../../../nbconvert-a11y/tests/exports/validator/lorenz-executed-default.json"    
    class Violation(Exception):
        map = {}
        def __class_getitem__(cls, id):
            bases = None
            if isinstance(id, tuple): id, bases = id
            if id in cls.map: return cls.map[id]
            return cls.map.setdefault(id, type(id, bases or (Violation,), {}))

        def __repr__(self):
            return super().__repr__()[:150]

exceptions are facetted by their type and info level.

    def messages_to_violations(messages):
        ct = collections.defaultdict(int)
        CSS_START = re.compile("""^“\S+”:""")
        exceptions = []
        for message in messages:
            t = message["type"],
            ct[t[0]] += 1
            if message.get("subType"): t += message.get("subType"),
            msg = message["message"]
            if msg.startswith("CSS:"):
                msg = msg[5:]
                t += "css",         
                if CSS_START.match(msg):
                    prop, _, msg = msg.partition(": ")
                    t += prop[1:-1],
                    id = F"""{message["type"]}-{prop[1:-1]}"""
                else:
                    id =F"""{message["type"]}-{msg.strip()}"""
            else:
                id = F"""{message["type"]}-{msg.strip()}"""
                msg = message["extract"]
            exceptions.append(Violation[id](msg.strip()))
        if exceptions:
            return exceptiongroup.ExceptionGroup(
                F"""{sum(ct.values())} violations: """ + ", ".join(
                    F"""{v} {k}"""  for k, v in ct.items()
                ),
                exceptions)
    exc = messages_to_violations(
        messages := json.loads(pathlib.Path(file).read_text())["messages"]
    ); exc
ExceptionGroup('14 violations: 9 info, 5 error',
               [('n">\n<head><meta charset="utf-8"/>\n<meta'),
                ('"utf-8"/>\n<meta content="width=device-width, initial-scale=1.0" name="viewport"/>\n<titl'),
                ('</script>\n<style type="text/css">\n    p'),
                ('</style>\n<style type="text/css">\n/*---'),
                error-Unknown pseudo-element or pseudo-class “:horizontal”('Unknown pseudo-element or pseudo-class “:horizontal”'),
                error-Unknown pseudo-element or pseudo-class “:vertical”('Unknown pseudo-element or pseudo-class “:vertical”'),
                error-box-shadow("“'0px 4px 4px rgba(0, 0, 0, 0.25)'” is not a “box-shadow” value."),
                error-overflow('“overlay” is not a “overflow” value.'),
                ('</style>\n<style type="text/css">\n/*---'),
                ('</style>\n<style type="text/css">\n/* Fo'),
                ('ndex="0">\n<script type="text/javascript">\nvar e'),
                ('ndex="0">\n<img alt="No description has been provided for this image" class="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAhYAAAGzCAYAAABzfl,
                ('ndex="0">\n<img alt="No description has been provided for this image" class="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAhYAAAGzCAYAAABzfl,
                ('>\n</body>\n<script type="application/vnd.jupyter.widget-state+json">\n{"sta')])

messages_to_violations to violations dynamically generates Exception types for specific responses from the vnu validator.

    print(
        F"we created {len(Violation.map)} exceptions.",
        *Violation.map.values(), sep="\n")
we created 8 exceptions.
<class '__main__.info-Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.'>
<class '__main__.info-The “type” attribute for the “style” element is not needed and should be omitted.'>
<class '__main__.error-Unknown pseudo-element or pseudo-class “:horizontal”'>
<class '__main__.error-Unknown pseudo-element or pseudo-class “:vertical”'>
<class '__main__.error-box-shadow'>
<class '__main__.error-overflow'>
<class '__main__.info-The “type” attribute is unnecessary for JavaScript resources.'>
<class '__main__.error-Stray start tag “script”.'>