Initial commit

This commit is contained in:
Denys Zaitsev
2026-04-03 23:25:54 +03:00
parent 531a1301d5
commit d7e1066c60
3843 changed files with 1554468 additions and 0 deletions
+53
View File
@@ -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=[])