mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-23 04:26:36 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import re
|
||||
import io
|
||||
from typing import List, Any
|
||||
from pydantic import BaseModel
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
Image = None
|
||||
|
||||
class ValidationResult(BaseModel):
|
||||
valid: bool
|
||||
errors: List[str]
|
||||
|
||||
class IBatchValidator(ABC):
|
||||
@abstractmethod
|
||||
def validate_batch_size(self, batch: Any) -> ValidationResult: pass
|
||||
@abstractmethod
|
||||
def check_sequence_continuity(self, batch: Any, expected_start: int) -> ValidationResult: pass
|
||||
@abstractmethod
|
||||
def validate_naming_convention(self, filenames: List[str]) -> ValidationResult: pass
|
||||
@abstractmethod
|
||||
def validate_format(self, image_data: bytes) -> ValidationResult: pass
|
||||
|
||||
class BatchValidator(IBatchValidator):
|
||||
"""H08: Validates image batch integrity, sequence continuity, and format."""
|
||||
def validate_batch_size(self, batch: Any) -> ValidationResult:
|
||||
if len(batch.images) < 10: return ValidationResult(valid=False, errors=[f"Batch size {len(batch.images)} below minimum 10"])
|
||||
if len(batch.images) > 50: return ValidationResult(valid=False, errors=[f"Batch size {len(batch.images)} exceeds maximum 50"])
|
||||
return ValidationResult(valid=True, errors=[])
|
||||
|
||||
def check_sequence_continuity(self, batch: Any, expected_start: int) -> ValidationResult:
|
||||
try:
|
||||
seqs = [int(re.match(r"AD(\d{6})\.", f, re.I).group(1)) for f in batch.filenames]
|
||||
if seqs[0] != expected_start: return ValidationResult(valid=False, errors=[f"Expected start {expected_start}"])
|
||||
for i in range(len(seqs) - 1):
|
||||
if seqs[i+1] != seqs[i] + 1: return ValidationResult(valid=False, errors=["Gap detected"])
|
||||
return ValidationResult(valid=True, errors=[])
|
||||
except Exception as e:
|
||||
return ValidationResult(valid=False, errors=[str(e)])
|
||||
|
||||
def validate_naming_convention(self, filenames: List[str]) -> ValidationResult:
|
||||
ptn = re.compile(r"^AD\d{6}\.(jpg|JPG|png|PNG)$")
|
||||
errs = [f"Invalid naming for {f}" for f in filenames if not ptn.match(f)]
|
||||
return ValidationResult(valid=len(errs) == 0, errors=errs)
|
||||
|
||||
def validate_format(self, image_data: bytes) -> ValidationResult:
|
||||
if len(image_data) > 10 * 1024 * 1024: return ValidationResult(valid=False, errors=["Size > 10MB"])
|
||||
if not Image: return ValidationResult(valid=True, errors=[])
|
||||
try: img = Image.open(io.BytesIO(image_data)); img.verify()
|
||||
except Exception as e: return ValidationResult(valid=False, errors=[f"Corrupted: {e}"])
|
||||
return ValidationResult(valid=True, errors=[])
|
||||
Reference in New Issue
Block a user