1
0
mirror of https://github.com/prometheus/docs.git synced 2026-02-05 06:45:01 +01:00
Files
docs/openmetrics-spec-tests/check_openmetrics_spec.py
György Krajcsovits b0a3961832 fix(abnf-checker): return error on example error
We just printed the error before but not set exit code.

Signed-off-by: György Krajcsovits <gyorgy.krajcsovits@grafana.com>
2025-06-16 13:15:18 +02:00

117 lines
3.5 KiB
Python

#!/bin/env python3
#
# This script opens a markdown file containing the OpenMetrics specification,
# extracts the ABNF grammar from it, and checks if the grammar is valid.
# ABNF grammer must be enclosed in
# ```abnf
# exposition = metricset HASH SP eof [ LF ]
# ...
# ```
# code block, and the top node must be `exposition`.
# It also extracts examples from the OpenMetrics spec file and checks if they
# are valid according to the grammar.
# Exampes must be enclosed in
# ```openmetrics
# ... example content ...
# ```
# code blocks.
from abnf import Rule
import sys
class Grammar(Rule):
pass
# Start node for the OpenMetrics spec.
start_node = 'exposition'
def get_spec(filename):
with open(filename, 'r') as file:
lines = file.readlines()
spec = []
collecting = False
for line in lines:
if collecting:
if line.startswith('```'):
collecting = False
else:
spec.append(line.strip())
continue
if line.startswith('```abnf'):
if len(spec) > 0:
raise ValueError("Multiple ABNF blocks found in the file.")
collecting = True
if len(spec) == 0:
raise ValueError("No or empty ABNF block found in the file. Wanted ```abnf ... ```.")
return '\n'.join(spec)
class example:
def __init__(self, line_number, content):
self.line_number = line_number
self.content = content
class examples:
"""
Extracts examples from the OpenMetrics spec file with generator function.
"""
def __init__(self, filename):
self.file = open(filename, 'r')
self.line_number = 0
def __iter__(self):
return self
def __next__(self):
collecting = False
append_eof = False
start_line = self.line_number
example_lines = []
for line in self.file:
self.line_number += 1
if collecting:
if line.startswith('```'):
collecting = False
break
else:
example_lines.append(line)
elif line.startswith('```openmetrics'):
start_line = self.line_number
collecting = True
if line.startswith('```openmetrics-add-eof'):
append_eof = True
if len(example_lines) > 0:
if append_eof:
example_lines.append('# EOF')
return example(start_line, ''.join(example_lines).strip())
raise StopIteration("No more examples found.")
# Main
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python3 check_openmetrics_spec.py <filename.md>")
sys.exit(1)
filename = sys.argv[1]
if not filename.endswith('.md'):
print(f"Error: {filename} is not a Markdown file.")
sys.exit(1)
spec = get_spec(filename)
try:
Grammar.load_grammar(grammar=spec, strict=True)
except Exception as e:
print(f"Error parsing ABNF: {e}")
sys.exit(1)
print("ABNF parsed successfully.")
exit_code = 0
for ex in examples(filename):
try:
Grammar.get(start_node).parse_all(ex.content)
print(f"Example parsed successfully: {ex.line_number}: {ex.content[:30]}...") # Print first 30 chars
except Exception as e:
print(f"Error parsing example at line {ex.line_number}: {e}\nExample: {ex.content[:30]}...")
exit_code = 2
sys.exit(exit_code)