Coverage for queue_cli/core/schema.py: 0.00%
37 statements
« prev ^ index » next coverage.py v7.10.6, created at 2026-04-13 14:26 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2026-04-13 14:26 +0000
1"""
2Schema validation and translation for match messages.
4Handles validation against the canonical schema and translation
5between the external schema (match-scraper) and internal schema (celery tasks).
6"""
8import json
9from pathlib import Path
10from typing import Any
12import jsonschema
13from jsonschema import ValidationError
16class SchemaValidator:
17 """Validates and translates match message schemas."""
19 # Field name mappings from canonical schema to internal schema
20 FIELD_MAPPINGS = {
21 "date": "match_date",
22 "score_home": "home_score",
23 "score_away": "away_score",
24 "status": "match_status",
25 "match_id": "external_match_id",
26 }
28 def __init__(self, schema_path: str | None = None):
29 """
30 Initialize schema validator.
32 Args:
33 schema_path: Path to JSON schema file. If None, uses default schema.
34 """
35 if schema_path is None:
36 # Default to canonical schema in docs
37 schema_path = str(
38 Path(__file__).parent.parent.parent.parent / "docs" / "08-integrations" / "match-message-schema.json"
39 )
41 with open(schema_path) as f:
42 self.schema = json.load(f)
44 def validate(self, data: dict[str, Any]) -> tuple[bool, list[str], list[str]]:
45 """
46 Validate data against schema.
48 Args:
49 data: Data to validate
51 Returns:
52 Tuple of (is_valid, errors, warnings)
53 """
54 errors = []
55 warnings = []
57 try:
58 jsonschema.validate(instance=data, schema=self.schema)
59 except ValidationError as e:
60 errors.append(f"Schema validation failed: {e.message}")
61 return False, errors, warnings
63 # Check for fields that need translation
64 for canonical_field, internal_field in self.FIELD_MAPPINGS.items():
65 if canonical_field in data and internal_field in data:
66 warnings.append(f"Both '{canonical_field}' and '{internal_field}' present. Using '{internal_field}'.")
68 return True, errors, warnings
70 def translate_to_internal(self, data: dict[str, Any]) -> dict[str, Any]:
71 """
72 Translate from canonical schema (match-scraper) to internal schema (celery tasks).
74 Args:
75 data: Data in canonical schema format
77 Returns:
78 Data in internal schema format
79 """
80 result = data.copy()
82 for canonical_field, internal_field in self.FIELD_MAPPINGS.items():
83 if canonical_field in result and internal_field not in result:
84 result[internal_field] = result[canonical_field]
86 return result
88 def translate_to_canonical(self, data: dict[str, Any]) -> dict[str, Any]:
89 """
90 Translate from internal schema (celery tasks) to canonical schema (match-scraper).
92 Args:
93 data: Data in internal schema format
95 Returns:
96 Data in canonical schema format
97 """
98 result = data.copy()
100 # Reverse mapping
101 reverse_mappings = {v: k for k, v in self.FIELD_MAPPINGS.items()}
103 for internal_field, canonical_field in reverse_mappings.items():
104 if internal_field in result and canonical_field not in result:
105 result[canonical_field] = result[internal_field]
107 return result