from typing import Optional, Any
from dataclasses import dataclass, field
import json
@dataclass
class ChunkValidationResult:
valid: bool = True
schema_errors: list[str] = field(default_factory=list)
ttl_errors: list[str] = field(default_factory=list)
crypto_errors: list[str] = field(default_factory=list)
inspector_errors: list[str] = field(default_factory=list)
policy_errors: list[str] = field(default_factory=list)
@property
def total_errors(self) -> int:
return (
len(self.schema_errors) + len(self.ttl_errors) +
len(self.crypto_errors) + len(self.inspector_errors) +
len(self.policy_errors)
)
def to_dict(self) -> dict[str, Any]:
return {
'valid': self.valid,
'schemaErrors': self.schema_errors,
'ttlErrors': self.ttl_errors,
'cryptoErrors': self.crypto_errors,
'inspectorErrors': self.inspector_errors,
'policyErrors': self.policy_errors,
}
@classmethod
def from_dict(cls, data: dict[str, Any]) -> 'ChunkValidationResult':
return cls(
valid=data.get('valid', True),
schema_errors=data.get('schemaErrors', []),
ttl_errors=data.get('ttlErrors', []),
crypto_errors=data.get('cryptoErrors', []),
inspector_errors=data.get('inspectorErrors', []),
policy_errors=data.get('policyErrors', []),
)
@dataclass
class StreamingValidationState:
chunks_processed: int = 0
chunks_total: int = 0
items_processed: int = 0
items_total: int = 0
valid: bool = True
@property
def progress_percent(self) -> float:
if self.chunks_total == 0:
return 0.0
return (self.chunks_processed / self.chunks_total) * 100
def to_dict(self) -> dict[str, Any]:
return {
'chunksProcessed': self.chunks_processed,
'chunksTotal': self.chunks_total,
'itemsProcessed': self.items_processed,
'itemsTotal': self.items_total,
'valid': self.valid,
}
@classmethod
def from_dict(cls, data: dict[str, Any]) -> 'StreamingValidationState':
return cls(
chunks_processed=data.get('chunksProcessed', 0),
chunks_total=data.get('chunksTotal', 0),
items_processed=data.get('itemsProcessed', 0),
items_total=data.get('itemsTotal', 0),
valid=data.get('valid', True),
)
class StreamingValidator:
def __init__(self):
self.state = StreamingValidationState()
self.chunk_results = []
def add_chunk(
self,
chunk: str,
total_chunks: int,
) -> ChunkValidationResult:
self.state.chunks_total = total_chunks
self.state.chunks_processed += 1
result = ChunkValidationResult(
valid=True,
schema_errors=[],
ttl_errors=[],
crypto_errors=[],
inspector_errors=[],
policy_errors=[],
)
self.state.valid = self.state.valid and result.valid
self.chunk_results.append(result)
return result
def finalize(self) -> dict[str, Any]:
all_schema_errors = []
all_ttl_errors = []
all_crypto_errors = []
all_inspector_errors = []
all_policy_errors = []
for result in self.chunk_results:
all_schema_errors.extend(result.schema_errors)
all_ttl_errors.extend(result.ttl_errors)
all_crypto_errors.extend(result.crypto_errors)
all_inspector_errors.extend(result.inspector_errors)
all_policy_errors.extend(result.policy_errors)
total_errors = (
len(all_schema_errors) + len(all_ttl_errors) +
len(all_crypto_errors) + len(all_inspector_errors) +
len(all_policy_errors)
)
return {
'valid': total_errors == 0,
'totalErrors': total_errors,
'schemaErrors': all_schema_errors,
'ttlErrors': all_ttl_errors,
'cryptoErrors': all_crypto_errors,
'inspectorErrors': all_inspector_errors,
'policyErrors': all_policy_errors,
'state': self.state.to_dict(),
}
def reset(self) -> None:
self.state = StreamingValidationState()
self.chunk_results = []
def get_state(self) -> StreamingValidationState:
return self.state
def validate_chunk(
chunk: str,
policy_json: str,
) -> ChunkValidationResult:
return ChunkValidationResult(
valid=True,
schema_errors=[],
ttl_errors=[],
crypto_errors=[],
inspector_errors=[],
policy_errors=[],
)