""" Модель данных проекта для сохранения/загрузки в JSON """ from typing import List, Dict, Optional from dataclasses import dataclass, asdict from datetime import datetime import json @dataclass class ReagentData: """Данные реагента""" name: str percentage: float unit: str conversion_factor: float dilution_factor: float def to_dict(self) -> Dict: return asdict(self) @classmethod def from_dict(cls, data: Dict) -> 'ReagentData': return cls( name=data['name'], percentage=data['percentage'], unit=data['unit'], conversion_factor=data.get('conversion_factor', 1.0), dilution_factor=data.get('dilution_factor', 1.0) ) @dataclass class FactorData: """Данные фактора эксперимента""" name: str center: float low: float high: float step: float step_type: str unit: str percentage: Optional[float] = None dilution_factor: Optional[float] = None def to_dict(self) -> Dict: d = asdict(self) # Удаляем None значения return {k: v for k, v in d.items() if v is not None} @classmethod def from_dict(cls, data: Dict) -> 'FactorData': return cls( name=data['name'], center=data['center'], low=data['low'], high=data['high'], step=data.get('step', 0), step_type=data.get('step_type', 'абс'), unit=data.get('unit', ''), percentage=data.get('percentage'), dilution_factor=data.get('dilution_factor') ) @dataclass class ResponseData: """Данные отклика эксперимента""" name: str unit: str def to_dict(self) -> Dict: return asdict(self) @classmethod def from_dict(cls, data: Dict) -> 'ResponseData': return cls( name=data['name'], unit=data.get('unit', '') ) @dataclass class ExperimentResultsData: """Результаты эксперимента""" design: List[Dict] # План эксперимента results: List[List[float]] # Результаты измерений responses: List[ResponseData] # Отклики def to_dict(self) -> Dict: return { 'design': self.design, 'results': self.results, 'responses': [r.to_dict() for r in self.responses] } @classmethod def from_dict(cls, data: Dict) -> 'ExperimentResultsData': return cls( design=data['design'], results=data['results'], responses=[ResponseData.from_dict(r) for r in data['responses']] ) @dataclass class ProjectData: """Полные данные проекта""" # Информация о проекте project_name: str created_at: str modified_at: str version: str = "1.0" # Данные калькулятора сред medium_total_volume: float = 1000.0 medium_volume_unit: str = "мл" medium_solvent: str = "Вода" medium_reagents: List[ReagentData] = None # Данные эксперимента experiment_factors: List[FactorData] = None experiment_responses: List[ResponseData] = None experiment_center_points: int = 3 experiment_randomize: bool = True experiment_results: Optional[ExperimentResultsData] = None def __post_init__(self): if self.medium_reagents is None: self.medium_reagents = [] if self.experiment_factors is None: self.experiment_factors = [] if self.experiment_responses is None: self.experiment_responses = [] def to_dict(self) -> Dict: """Конвертирует в словарь для JSON""" return { 'project_info': { 'name': self.project_name, 'created_at': self.created_at, 'modified_at': self.modified_at, 'version': self.version }, 'medium_calculator': { 'total_volume': self.medium_total_volume, 'volume_unit': self.medium_volume_unit, 'solvent': self.medium_solvent, 'reagents': [r.to_dict() for r in self.medium_reagents] }, 'experiment': { 'factors': [f.to_dict() for f in self.experiment_factors], 'responses': [r.to_dict() for r in self.experiment_responses], 'center_points': self.experiment_center_points, 'randomize': self.experiment_randomize, 'results': self.experiment_results.to_dict() if self.experiment_results else None } } @classmethod def from_dict(cls, data: Dict) -> 'ProjectData': """Создаёт объект из словаря""" project_info = data.get('project_info', {}) medium = data.get('medium_calculator', {}) experiment = data.get('experiment', {}) # Создаём объект obj = cls( project_name=project_info.get('name', 'Новый проект'), created_at=project_info.get('created_at', datetime.now().isoformat()), modified_at=project_info.get('modified_at', datetime.now().isoformat()), version=project_info.get('version', '1.0'), medium_total_volume=medium.get('total_volume', 1000.0), medium_volume_unit=medium.get('volume_unit', 'мл'), medium_solvent=medium.get('solvent', 'Вода'), medium_reagents=[ReagentData.from_dict(r) for r in medium.get('reagents', [])], experiment_factors=[FactorData.from_dict(f) for f in experiment.get('factors', [])], experiment_responses=[ResponseData.from_dict(r) for r in experiment.get('responses', [])], experiment_center_points=experiment.get('center_points', 3), experiment_randomize=experiment.get('randomize', True), experiment_results=ExperimentResultsData.from_dict(experiment['results']) if experiment.get('results') else None ) return obj def save_to_file(self, filename: str): """Сохраняет проект в JSON файл""" self.modified_at = datetime.now().isoformat() with open(filename, 'w', encoding='utf-8') as f: json.dump(self.to_dict(), f, ensure_ascii=False, indent=2) @classmethod def load_from_file(cls, filename: str) -> 'ProjectData': """Загружает проект из JSON файла""" with open(filename, 'r', encoding='utf-8') as f: data = json.load(f) return cls.from_dict(data) def create_new_project(name: str = "Новый проект") -> ProjectData: """Создаёт новый проект с текущей датой""" now = datetime.now().isoformat() return ProjectData( project_name=name, created_at=now, modified_at=now )