Files
edu-industry/admin-tools/crawler/src/edu_crawler/schema.py
T
lofyerandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> 8dff9847e3 feat: add compliant data connectors and lineage
- add authorized nine-source crawler connectors with security controls and packaged schemas
- add the school internship contract to the vendor data standard center
- add bidirectional campus data-to-report lineage with gap ownership and remediation

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-24 16:28:01 +08:00

36 lines
1.3 KiB
Python

"""JSON Schema loading and validation."""
from __future__ import annotations
import json
from functools import lru_cache
from importlib.resources import files
from itertools import islice
from jsonschema import Draft202012Validator, FormatChecker
from .errors import SchemaValidationFailed
@lru_cache(maxsize=8)
def validator_for(schema_name: str) -> Draft202012Validator:
if "/" in schema_name or "\\" in schema_name or not schema_name.endswith(".json"):
raise SchemaValidationFailed(f"Target schema is unavailable: {schema_name}")
resource = files("edu_crawler.schemas").joinpath(schema_name)
if not resource.is_file():
raise SchemaValidationFailed(f"Target schema is unavailable: {schema_name}")
schema = json.loads(resource.read_text(encoding="utf-8"))
Draft202012Validator.check_schema(schema)
return Draft202012Validator(schema, format_checker=FormatChecker())
def validate_record(schema_name: str, record: dict) -> None:
errors = list(islice(validator_for(schema_name).iter_errors(record), 5))
if not errors:
return
summaries = []
for error in errors:
path = ".".join(str(part) for part in error.absolute_path) or "$"
summaries.append(f"{path}: {error.validator} validation failed")
raise SchemaValidationFailed("; ".join(summaries))