| from __future__ import annotations |
|
|
| from dataclasses import dataclass, field, asdict |
| from typing import Any, Optional |
|
|
|
|
| @dataclass |
| class LeadExample: |
| example_id: str |
| linear_sequence: str |
| target_id: Optional[str] = None |
| target_context: Optional[dict[str, Any]] = None |
| protected_positions: list[int] = field(default_factory=list) |
| preferred_property_direction: dict[str, str] = field(default_factory=dict) |
| thresholds: dict[str, float] = field(default_factory=dict) |
| known_active_motif_positions: Optional[list[int]] = None |
|
|
| def to_dict(self) -> dict[str, Any]: |
| return asdict(self) |
|
|
|
|
| @dataclass |
| class BuildingBlock: |
| """Stapling building block. |
| |
| The geometry / motif fields drive CP-Composer-style feasibility: |
| - `motif`: sequence-level pattern; for K↔D/E lactam stapling this is |
| {"i_aa": ["K"], "j_aa": ["D","E"], "spacings": [3, 4]}. |
| - `ca_window`: allowed Cα(i)-Cα(j) distance window in Å. |
| |
| `chemistry_class` is now restricted to {"stapled"} (head_to_tail / |
| disulfide / bicycle were removed; the previous hydrocarbon i,i+4 / i,i+7 |
| blocks were also removed because they fall outside CP-Composer's scope). |
| """ |
|
|
| block_id: str |
| name: str |
| chemistry_class: str |
| synthetic_accessibility_score: float |
| cost_score: float |
| spps_score: float |
| motif: Optional[dict[str, Any]] = None |
| ca_window: tuple[float, float] = (4.0, 6.5) |
|
|
| def to_dict(self) -> dict[str, Any]: |
| d = asdict(self) |
| d["ca_window"] = list(self.ca_window) |
| return d |
|
|
| @classmethod |
| def from_dict(cls, d: dict[str, Any]) -> "BuildingBlock": |
| d = dict(d) |
| if "ca_window" in d and isinstance(d["ca_window"], list): |
| d["ca_window"] = tuple(d["ca_window"]) |
| |
| for legacy in ("allowed_anchor_spacings", "compatible_residue_types", "token_substitution"): |
| d.pop(legacy, None) |
| return cls(**d) |
|
|