# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 # # Generate RST documentation from extracted error codes. # This script takes a CSV file (produced by err_codes_extract.py) and generates # an RST file suitable for inclusion in Sphinx documentation. # # Usage: # python err_codes_to_rst.py --csv errors.csv --output error_codes.inc # python err_codes_to_rst.py --search-dirs components/ --output error_codes.inc # import argparse import csv import os import sys # Allow importing err_codes_extract from same directory sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from err_codes_extract import extract_all # noqa: E402 from err_codes_extract import search_headers # noqa: E402 def read_csv_entries(csv_path: str) -> list[tuple[str, int, str]]: """Read error codes from a CSV file.""" entries: list[tuple[str, int, str]] = [] with open(csv_path, encoding='utf-8') as f: reader = csv.DictReader(f) for row in reader: name = row['name'] value = int(row['value']) comment = row.get('comment', '') entries.append((name, value, comment)) return entries def generate_rst(entries: list[tuple[str, int, str]]) -> str: """Generate RST content from error code entries. Output format matches the existing esp_err_defs.inc generated by gen_esp_err_to_name.py so it can be used as a drop-in replacement in the docs build (included via ``.. include-build-file::``). """ lines: list[str] = [] # Sort by value: negative values first (ascending), then non-negative (ascending) sorted_entries = sorted(entries, key=lambda e: (e[1], e[0])) for name, value, comment in sorted_entries: line = f':c:macro:`{name}` ' if value > 0: line += f'**(0x{value:x})**' else: line += f'({value:d})' if comment: line += f': {comment}' lines.append(line) lines.append('') return '\n'.join(lines) def main() -> None: parser = argparse.ArgumentParser(description='Generate RST documentation of ESP error codes') parser.add_argument('--csv', default=None, help='Input CSV file with error codes (from err_codes_extract.py)') parser.add_argument( '--search-dirs', nargs='*', default=[], help='Directories to search recursively for header files' ) parser.add_argument('--base-path', default=None, help='Base path for computing relative paths') parser.add_argument('--output', required=True, help='Output RST file path') args = parser.parse_args() base_path = args.base_path if base_path is None: base_path = os.environ.get('IDF_PATH', os.getcwd()) if args.csv: entries = read_csv_entries(args.csv) elif args.search_dirs: headers = search_headers(args.search_dirs, base_path) err_codes = extract_all(headers, base_path) entries = [(ec.name, ec.value, ec.comment) for ec in err_codes if ec.value is not None] else: print('Error: Specify either --csv or --search-dirs.', file=sys.stderr) sys.exit(1) rst_content = generate_rst(entries) os.makedirs(os.path.dirname(os.path.abspath(args.output)), exist_ok=True) with open(args.output, 'w', encoding='utf-8') as f: f.write(rst_content) print(f'Generated {args.output} with {len(entries)} error codes') if __name__ == '__main__': main()