validate_json.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. #!/usr/bin/env python3
  2. import re
  3. from pathlib import Path
  4. from pprint import pprint
  5. import json5
  6. import jstyleson
  7. import yaml
  8. # 'json', 'json5' or 'yaml'
  9. # json: strict, but doesn't preserve line numbers necessarily, since it strips comments before parsing
  10. # json5: strict and preserves line numbers even for files with line comments
  11. # yaml: less strict, allows e.g. leading zeros
  12. VALIDATION_TYPE = "json5"
  13. errors = []
  14. for path in sorted(Path(".").glob("**/*.json")):
  15. # because path is an object and not a string
  16. path_str = str(path)
  17. try:
  18. with open(path_str, "r") as file:
  19. if VALIDATION_TYPE == "json":
  20. jstyleson.load(file)
  21. elif VALIDATION_TYPE == "json5":
  22. json5.load(file)
  23. elif VALIDATION_TYPE == "yaml":
  24. file = file.read().replace("\t", " ")
  25. file = file.replace("//", "#")
  26. yaml.safe_load(file)
  27. print(f"Validation of {path_str} succeeded")
  28. except Exception as exc:
  29. print(f"Validation of {path_str} failed")
  30. pprint(exc)
  31. error_pos = path_str
  32. # create error position strings for each type of parser
  33. if hasattr(exc, "pos"):
  34. # 'json'
  35. # https://stackoverflow.com/a/72850269/2278742
  36. error_pos = f"{path_str}:{exc.lineno}:{exc.colno}"
  37. print(error_pos)
  38. elif VALIDATION_TYPE == "json5":
  39. # 'json5'
  40. pos = re.findall(r"\d+", str(exc))
  41. error_pos = f"{path_str}:{pos[0]}:{pos[-1]}"
  42. elif hasattr(exc, "problem_mark"):
  43. # 'yaml'
  44. mark = exc.problem_mark
  45. error_pos = f"{path_str}:{mark.line+1}:{mark.column+1}"
  46. print(error_pos)
  47. errors.append({"error_pos": error_pos, "error_msg": exc})
  48. if errors:
  49. print("Summary of errors:")
  50. pprint(errors)
  51. raise Exception("Not all JSON files are valid")