Coverage for src / tracekit / schemas / __init__.py: 84%
37 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 23:04 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 23:04 +0000
1"""JSON Schema definitions for TraceKit configuration types.
3This module provides JSON Schema definitions for validating various
4configuration file types used in TraceKit, including packet formats,
5device mappings, bus configurations, and protocol definitions.
8Example:
9 >>> from tracekit.schemas import load_schema, validate_config
10 >>> schema = load_schema("packet_format")
11 >>> validate_config(config_dict, "packet_format")
12 True
13"""
15from __future__ import annotations
17import json
18from pathlib import Path
19from typing import Any
21from tracekit.config.schema import (
22 ConfigSchema,
23 get_schema_registry,
24 register_schema,
25 validate_against_schema,
26)
28__all__ = [
29 "SCHEMA_NAMES",
30 "get_schema_path",
31 "load_schema",
32 "register_builtin_schemas",
33 "validate_config",
34]
36# Schema type names
37SCHEMA_NAMES = [
38 "packet_format",
39 "device_mapping",
40 "bus_configuration",
41 "protocol_definition",
42]
45def get_schema_path(schema_name: str) -> Path:
46 """Get the file path for a schema definition.
48 Args:
49 schema_name: Schema name (e.g., "packet_format").
51 Returns:
52 Path to the JSON schema file.
54 Raises:
55 ValueError: If schema name is not recognized.
56 FileNotFoundError: If schema file does not exist.
57 """
58 if schema_name not in SCHEMA_NAMES:
59 raise ValueError(f"Unknown schema name: {schema_name}. Available schemas: {SCHEMA_NAMES}")
61 schema_dir = Path(__file__).parent
62 schema_file = schema_dir / f"{schema_name}.json"
64 if not schema_file.exists(): 64 ↛ 65line 64 didn't jump to line 65 because the condition on line 64 was never true
65 raise FileNotFoundError(f"Schema file not found: {schema_file}")
67 return schema_file
70def load_schema(schema_name: str) -> dict[str, Any]:
71 """Load a JSON schema definition from disk.
73 Args:
74 schema_name: Schema name (e.g., "packet_format").
76 Returns:
77 JSON schema dictionary.
78 """
79 schema_path = get_schema_path(schema_name)
81 with open(schema_path) as f:
82 result: dict[str, Any] = json.load(f)
83 return result
86def validate_config(
87 config: dict[str, Any],
88 schema_name: str,
89 *,
90 strict: bool = False,
91) -> bool:
92 """Validate a configuration dictionary against a schema.
94 Args:
95 config: Configuration dictionary to validate.
96 schema_name: Schema name (e.g., "packet_format").
97 strict: If True, fail on additional properties.
99 Returns:
100 True if validation passes.
102 Example:
103 >>> config = {"name": "test", "packet": {...}, "header": {...}}
104 >>> validate_config(config, "packet_format")
105 True
106 """
107 # Use the existing validation system from config.schema
108 return validate_against_schema(config, schema_name, strict=strict)
111def register_builtin_schemas() -> None:
112 """Register all built-in configuration schemas.
114 This function registers the following schemas:
115 - packet_format: Binary packet format configurations
116 - device_mapping: Device ID to name mappings
117 - bus_configuration: Parallel bus configurations
118 - protocol_definition: Protocol DSL definitions
122 The schemas are registered with the global SchemaRegistry and can
123 be accessed via validate_against_schema() or get_schema_registry().
124 """
125 registry = get_schema_registry()
127 # Load and register each schema
128 for schema_name in SCHEMA_NAMES:
129 # Skip if already registered
130 if registry.has_schema(schema_name): 130 ↛ 131line 130 didn't jump to line 131 because the condition on line 130 was never true
131 continue
133 schema_dict = load_schema(schema_name)
135 # Extract version from $id if present
136 version = "1.0.0" # default
137 if "$id" in schema_dict: 137 ↛ 145line 137 didn't jump to line 145 because the condition on line 137 was always true
138 # Extract version from URI like .../v1.0.0.json
139 schema_id = schema_dict["$id"]
140 if "/v" in schema_id: 140 ↛ 141line 140 didn't jump to line 141 because the condition on line 140 was never true
141 version_part = schema_id.split("/v")[-1]
142 version = version_part.replace(".json", "")
144 # Create ConfigSchema object
145 config_schema = ConfigSchema(
146 name=schema_name,
147 version=version,
148 schema=schema_dict,
149 description=schema_dict.get("description", ""),
150 uri=schema_dict.get("$id"),
151 )
153 # Register with global registry
154 register_schema(config_schema, set_default=True)
157# Auto-register schemas on module import
158register_builtin_schemas()