File size: 2,004 Bytes
bb6d2aa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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"])
        # tolerate legacy catalogs by dropping retired fields
        for legacy in ("allowed_anchor_spacings", "compatible_residue_types", "token_substitution"):
            d.pop(legacy, None)
        return cls(**d)