Skip to main content (Source)

#!/usr/bin/env python
# coding: utf-8
# Copyright 2024 Christian Lawson-Perfect
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.
# Convert a WCAG-EM report tool JSON file to reStructuredText
# This script converts the JSON file you get from the [WCAG-EM Report Tool]( into reStructuredText markup.
# It needs the following files:
# * - The data on WCAG criteria used by the report tool.
# * - The English readable names for WCAG criteria. Save as ``WCAG_text.json``.
# Usage:
#   python product-report.json
from collections import defaultdict
from itertools import groupby
import json
import sys
# Load the report data, and the WCAG criterion data
report_json_filename = sys.argv[1]
with open(report_json_filename) as f:
    data = json.load(f)
with open('wcag.json') as f:
    wcag = json.load(f)
with open('WCAG_text.json') as f:
    wcag_text = json.load(f)
wcag_ids = {v['id']: v for v in wcag['2.2'].values()}
criteria_names = {k: v['TITLE'] for k,v in wcag_text['SUCCESS_CRITERION'].items()}
criteria = defaultdict(list)
for item in data['auditSample']:
    id = item['test']['id'][len('WCAG22:'):]
# For each criterion, gather info from the report
report = []
def indent_lines(text, indent):
    lines = text.split('\n')
    return lines[0]+'\n'.join(indent+line for line in lines[1:])
for key, criterion in criteria.items():
    description = ''
    result = ''
    for item in criterion:
        if 'description' in item['result']:
            description = item['result']['description']
        if 'Website' not in item['subject']['type']:
        result = item['result']['outcome']['title']
    result_map = {
        'Passed': 'Supports',
        'Not present': 'Not Applicable',
    result = result_map.get(result, result)
    info = wcag_ids[key]
    num = info['num']
    conformanceLevel = info['conformanceLevel']
    name = criteria_names[num]
        'key': key,
        'description': indent_lines(description, ' '*6),
        'result': result,
        'num': num,
        'conformanceLevel': conformanceLevel,
        'name': name,
# Criteria not assessed
# The following criteria were not assessed:
print("The following criteria were not assessed:\n")
not_assessed = [n for n in wcag_ids.values() if n['id'] not in criteria]
for n in not_assessed:
    print(f'''* {n['num']} {n['id']} ({n['conformanceLevel']}){n['id']}''')
# Produce ReStructuredText of report
for level, items in groupby(sorted(report, key=lambda x: (x['conformanceLevel'], x['num'])), key=lambda x: x['conformanceLevel']):
    header = f'''Table 1: Success Criteria, Level {level}'''
.. list-table::
  :header-rows: 1
     - Criteria
     - Conformance Level
     - Remarks and Explanations''')
    for item in items:
        print('''  -
    - .. _vpat-{key}:
      `{num}: {name} <{key}>`__ (Level {conformanceLevel})
    - {result}
    - {description}'''.format(**item))