alphafold3-input 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- alphafold3_input/__about__.py +69 -0
- alphafold3_input/__init__.py +61 -0
- alphafold3_input/bond.py +222 -0
- alphafold3_input/dna.py +260 -0
- alphafold3_input/job.py +565 -0
- alphafold3_input/ligand.py +271 -0
- alphafold3_input/modification.py +175 -0
- alphafold3_input/protein.py +390 -0
- alphafold3_input/py.typed +0 -0
- alphafold3_input/rna.py +348 -0
- alphafold3_input/template.py +209 -0
- alphafold3_input/utils.py +561 -0
- alphafold3_input-0.3.0.dist-info/METADATA +82 -0
- alphafold3_input-0.3.0.dist-info/RECORD +15 -0
- alphafold3_input-0.3.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Package metadata for AlphaFold 3 input models.
|
|
2
|
+
|
|
3
|
+
Provides a normalized interface to distribution metadata for the package.
|
|
4
|
+
|
|
5
|
+
Exports:
|
|
6
|
+
- :data:`__title__`: Package title.
|
|
7
|
+
- :data:`__description__`: Package summary.
|
|
8
|
+
- :data:`__author__`: Package author.
|
|
9
|
+
- :data:`__version__`: Installed version.
|
|
10
|
+
- :data:`__package__`: Distribution name.
|
|
11
|
+
- :data:`__module_name__`: Import path.
|
|
12
|
+
- :data:`__repository__`: Repository URL.
|
|
13
|
+
- :data:`__documentation__`: Documentation URL.
|
|
14
|
+
- :data:`__issues__`: Issue tracker URL.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from importlib.metadata import PackageMetadata, metadata, version
|
|
18
|
+
|
|
19
|
+
__all__: list[str] = [
|
|
20
|
+
"__author__",
|
|
21
|
+
"__description__",
|
|
22
|
+
"__documentation__",
|
|
23
|
+
"__issues__",
|
|
24
|
+
"__module_name__",
|
|
25
|
+
"__package__",
|
|
26
|
+
"__repository__",
|
|
27
|
+
"__title__",
|
|
28
|
+
"__version__",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
__package__: str = "alphafold3_input"
|
|
32
|
+
"""Distribution package name."""
|
|
33
|
+
|
|
34
|
+
__module_name__: str = "alphafold3_input"
|
|
35
|
+
"""Importable top-level module name."""
|
|
36
|
+
|
|
37
|
+
__version__: str = version(__package__)
|
|
38
|
+
"""Installed package version string."""
|
|
39
|
+
|
|
40
|
+
__metadata__: PackageMetadata = metadata(__package__)
|
|
41
|
+
"""Raw distribution metadata."""
|
|
42
|
+
|
|
43
|
+
__title__: str = __metadata__["Name"]
|
|
44
|
+
"""Distribution package name."""
|
|
45
|
+
|
|
46
|
+
__description__: str = __metadata__.get("Summary", "")
|
|
47
|
+
"""Package summary."""
|
|
48
|
+
|
|
49
|
+
__author__: str = __metadata__.get("Author", "")
|
|
50
|
+
"""Package author."""
|
|
51
|
+
|
|
52
|
+
__repository__: str = ""
|
|
53
|
+
"""Repository URL."""
|
|
54
|
+
|
|
55
|
+
__documentation__: str = ""
|
|
56
|
+
"""Documentation URL."""
|
|
57
|
+
|
|
58
|
+
__issues__: str = ""
|
|
59
|
+
"""Issue tracker URL."""
|
|
60
|
+
|
|
61
|
+
for item in __metadata__.json.get("project_url", []):
|
|
62
|
+
label, url = item.split(", ", 1)
|
|
63
|
+
match label:
|
|
64
|
+
case "Repository":
|
|
65
|
+
__repository__ = url
|
|
66
|
+
case "Documentation":
|
|
67
|
+
__documentation__ = url
|
|
68
|
+
case "Issues":
|
|
69
|
+
__issues__ = url
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""AlphaFold 3 input models.
|
|
2
|
+
|
|
3
|
+
This package provides models for constructing AlphaFold 3 input files.
|
|
4
|
+
|
|
5
|
+
It offers a Pythonic, object-oriented interface for defining AlphaFold 3
|
|
6
|
+
jobs, abstracting the underlying JSON input format into typed models and
|
|
7
|
+
validated structures. The implementation closely follows the official
|
|
8
|
+
AlphaFold 3 input specification provided by DeepMind.
|
|
9
|
+
|
|
10
|
+
For full details on the expected input format and supported features,
|
|
11
|
+
refer to the official `AlphaFold 3 input specification
|
|
12
|
+
<https://github.com/google-deepmind/alphafold3/blob/main/docs/input.md>`_.
|
|
13
|
+
|
|
14
|
+
Exports:
|
|
15
|
+
- :data:`JSON_SCHEMA_URL`: canonical JSON Schema URL for editor \
|
|
16
|
+
validation.
|
|
17
|
+
- :class:`Job`, :class:`Dialect`, :class:`Version`: top-level job model \
|
|
18
|
+
and input format enums.
|
|
19
|
+
- :class:`DNA`, :class:`RNA`, :class:`Protein`, :class:`Ligand`: \
|
|
20
|
+
entity models used under :attr:`Job.entities`.
|
|
21
|
+
- :class:`Modification`, :class:`Entity`: residue modification model and \
|
|
22
|
+
its entity-scope enum.
|
|
23
|
+
- :class:`Template`: structural template specification for proteins.
|
|
24
|
+
- :class:`Atom`, :class:`Bond`: covalent bond specification models.
|
|
25
|
+
- :class:`Operation`, :func:`trace`, :func:`reindex`, :func:`realign`: \
|
|
26
|
+
operation trace generation, reindexing, and realignment utilities.
|
|
27
|
+
- :func:`ccd`, :func:`component`: generation of custom chemical \
|
|
28
|
+
component dictionaries.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from .bond import Atom, Bond
|
|
32
|
+
from .dna import DNA
|
|
33
|
+
from .job import JSON_SCHEMA_URL, Dialect, Job, Version
|
|
34
|
+
from .ligand import Ligand
|
|
35
|
+
from .modification import Entity, Modification
|
|
36
|
+
from .protein import Protein
|
|
37
|
+
from .rna import RNA
|
|
38
|
+
from .template import Template
|
|
39
|
+
from .utils import Operation, ccd, component, realign, reindex, trace
|
|
40
|
+
|
|
41
|
+
__all__: list[str] = [
|
|
42
|
+
"DNA",
|
|
43
|
+
"JSON_SCHEMA_URL",
|
|
44
|
+
"RNA",
|
|
45
|
+
"Atom",
|
|
46
|
+
"Bond",
|
|
47
|
+
"Dialect",
|
|
48
|
+
"Entity",
|
|
49
|
+
"Job",
|
|
50
|
+
"Ligand",
|
|
51
|
+
"Modification",
|
|
52
|
+
"Operation",
|
|
53
|
+
"Protein",
|
|
54
|
+
"Template",
|
|
55
|
+
"Version",
|
|
56
|
+
"ccd",
|
|
57
|
+
"component",
|
|
58
|
+
"realign",
|
|
59
|
+
"reindex",
|
|
60
|
+
"trace",
|
|
61
|
+
]
|
alphafold3_input/bond.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""Covalent bond models.
|
|
2
|
+
|
|
3
|
+
This submodule defines :class:`Atom` and :class:`Bond` for specifying
|
|
4
|
+
covalent bonds between entities in an AlphaFold 3 input.
|
|
5
|
+
|
|
6
|
+
Exports:
|
|
7
|
+
- :class:`Atom`: atom specification within an entity.
|
|
8
|
+
- :class:`Bond`: covalent bond between two atoms.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from collections.abc import Sequence
|
|
14
|
+
from typing import Any, Self
|
|
15
|
+
|
|
16
|
+
from pydantic import (
|
|
17
|
+
BaseModel,
|
|
18
|
+
ConfigDict,
|
|
19
|
+
Field,
|
|
20
|
+
model_serializer,
|
|
21
|
+
model_validator,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__: list[str] = [
|
|
25
|
+
"Atom",
|
|
26
|
+
"Bond",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Atom(BaseModel):
|
|
31
|
+
"""Atom specification within an entity.
|
|
32
|
+
|
|
33
|
+
An atom is defined by an :attr:`entity` identifier, a 1-based
|
|
34
|
+
:attr:`residue` index, and an atom :attr:`name`.
|
|
35
|
+
|
|
36
|
+
Attributes:
|
|
37
|
+
entity (str): Entity identifier.
|
|
38
|
+
residue (int): Residue index within the entity.
|
|
39
|
+
name (str): Atom name within the residue.
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
Atom definition.
|
|
43
|
+
|
|
44
|
+
>>> Atom(entity="A", residue=1, name="CB")
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
model_config = ConfigDict(
|
|
48
|
+
extra="forbid",
|
|
49
|
+
frozen=True,
|
|
50
|
+
validate_assignment=False,
|
|
51
|
+
validate_by_name=True,
|
|
52
|
+
validate_by_alias=True,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
entity: str = Field(
|
|
56
|
+
title="entity",
|
|
57
|
+
alias="entity",
|
|
58
|
+
description="Entity identifier.",
|
|
59
|
+
pattern="^[A-Z]+$",
|
|
60
|
+
validation_alias="entity",
|
|
61
|
+
serialization_alias="entity",
|
|
62
|
+
)
|
|
63
|
+
"""Entity identifier."""
|
|
64
|
+
|
|
65
|
+
residue: int = Field(
|
|
66
|
+
title="residue",
|
|
67
|
+
alias="residue",
|
|
68
|
+
description="Residue index within the entity.",
|
|
69
|
+
ge=1,
|
|
70
|
+
validation_alias="residue",
|
|
71
|
+
serialization_alias="residue",
|
|
72
|
+
)
|
|
73
|
+
"""Residue index within the entity."""
|
|
74
|
+
|
|
75
|
+
name: str = Field(
|
|
76
|
+
title="name",
|
|
77
|
+
alias="name",
|
|
78
|
+
description="Atom name within the residue.",
|
|
79
|
+
min_length=1,
|
|
80
|
+
validation_alias="name",
|
|
81
|
+
serialization_alias="name",
|
|
82
|
+
)
|
|
83
|
+
"""Atom name within the residue."""
|
|
84
|
+
|
|
85
|
+
@model_validator(mode="before")
|
|
86
|
+
@classmethod
|
|
87
|
+
def __validate_model(cls: type[Self], data: Any) -> Any:
|
|
88
|
+
"""Coerce compact atom definitions to a mapping.
|
|
89
|
+
|
|
90
|
+
Accepts the AlphaFold 3 list form ``[entity, residue, name]`` and
|
|
91
|
+
converts it to a mapping compatible with field validation.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
data (Any): Raw input data.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Any: A mapping with keys ``entity``, ``residue``, and ``name`` if
|
|
98
|
+
``data`` is a sequence, otherwise the original input.
|
|
99
|
+
|
|
100
|
+
Raises:
|
|
101
|
+
ValueError: If ``data`` is a sequence but does not contain exactly
|
|
102
|
+
three items.
|
|
103
|
+
"""
|
|
104
|
+
if not isinstance(data, Sequence) or isinstance(
|
|
105
|
+
data,
|
|
106
|
+
(str, bytes, bytearray),
|
|
107
|
+
):
|
|
108
|
+
return data
|
|
109
|
+
|
|
110
|
+
if len(data) != len(cls.model_fields):
|
|
111
|
+
msg: str = (
|
|
112
|
+
"Invalid atom definition: expected `[entity, residue, name]`."
|
|
113
|
+
)
|
|
114
|
+
raise ValueError(msg)
|
|
115
|
+
return {"entity": data[0], "residue": data[1], "name": data[2]}
|
|
116
|
+
|
|
117
|
+
@model_serializer(mode="plain")
|
|
118
|
+
def __serialize_model(self: Self) -> tuple[str, int, str]:
|
|
119
|
+
"""Serialize the atom as ``[entity, residue, name]``.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
tuple[str, int, str]: Compact AlphaFold 3 atom representation.
|
|
123
|
+
"""
|
|
124
|
+
return (self.entity, self.residue, self.name)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class Bond(BaseModel):
|
|
128
|
+
"""Covalent bond specification.
|
|
129
|
+
|
|
130
|
+
Defines a covalent bond between the :attr:`source` and the :attr:`target`
|
|
131
|
+
atoms as an AlphaFold 3 bonded atom pair.
|
|
132
|
+
|
|
133
|
+
Bonds are intended for covalently linked multi-residue :class:`Ligand`
|
|
134
|
+
entities, for example glycans. Covalent bonds within or between polymer
|
|
135
|
+
entities such as :class:`DNA`, :class:`RNA`, or :class:`Protein` are not
|
|
136
|
+
supported by AlphaFold 3.
|
|
137
|
+
|
|
138
|
+
Attributes:
|
|
139
|
+
source (Atom): Source atom address.
|
|
140
|
+
target (Atom): Target atom address.
|
|
141
|
+
|
|
142
|
+
Examples:
|
|
143
|
+
Covalent bond between two entities.
|
|
144
|
+
|
|
145
|
+
>>> Bond(
|
|
146
|
+
... source=Atom(entity="A", residue=1, name="CA"),
|
|
147
|
+
... target=Atom(entity="G", residue=1, name="CHA"),
|
|
148
|
+
... )
|
|
149
|
+
|
|
150
|
+
Covalent bond within a multi-residue entity.
|
|
151
|
+
|
|
152
|
+
>>> Bond(
|
|
153
|
+
... source=Atom(entity="I", residue=1, name="O6"),
|
|
154
|
+
... target=Atom(entity="I", residue=2, name="C1"),
|
|
155
|
+
... )
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
model_config = ConfigDict(
|
|
159
|
+
extra="forbid",
|
|
160
|
+
frozen=False,
|
|
161
|
+
validate_assignment=True,
|
|
162
|
+
validate_by_name=True,
|
|
163
|
+
validate_by_alias=True,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
source: Atom = Field(
|
|
167
|
+
title="source",
|
|
168
|
+
alias="source",
|
|
169
|
+
description="Source atom address.",
|
|
170
|
+
validation_alias="source",
|
|
171
|
+
serialization_alias="source",
|
|
172
|
+
)
|
|
173
|
+
"""Source atom address."""
|
|
174
|
+
|
|
175
|
+
target: Atom = Field(
|
|
176
|
+
title="target",
|
|
177
|
+
alias="target",
|
|
178
|
+
description="Target atom address.",
|
|
179
|
+
validation_alias="target",
|
|
180
|
+
serialization_alias="target",
|
|
181
|
+
)
|
|
182
|
+
"""Target atom address."""
|
|
183
|
+
|
|
184
|
+
@model_validator(mode="before")
|
|
185
|
+
@classmethod
|
|
186
|
+
def __validate_model(cls: type[Self], data: Any) -> Any:
|
|
187
|
+
"""Coerce compact bond definitions to a mapping.
|
|
188
|
+
|
|
189
|
+
Accepts the AlphaFold 3 list form ``[[...], [...]]`` and converts it
|
|
190
|
+
to a mapping compatible with field validation.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
data (Any): Raw input data.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
Any: A mapping with keys ``source`` and ``target`` if ``data`` is
|
|
197
|
+
a sequence, otherwise the original input.
|
|
198
|
+
|
|
199
|
+
Raises:
|
|
200
|
+
ValueError: If ``data`` is a sequence but does not contain exactly
|
|
201
|
+
two items.
|
|
202
|
+
"""
|
|
203
|
+
if not isinstance(data, Sequence) or isinstance(
|
|
204
|
+
data,
|
|
205
|
+
(str, bytes, bytearray),
|
|
206
|
+
):
|
|
207
|
+
return data
|
|
208
|
+
|
|
209
|
+
if len(data) != len(cls.model_fields):
|
|
210
|
+
msg: str = "Invalid bond definition: expected `[source, target]`."
|
|
211
|
+
raise ValueError(msg)
|
|
212
|
+
return {"source": data[0], "target": data[1]}
|
|
213
|
+
|
|
214
|
+
@model_serializer(mode="plain")
|
|
215
|
+
def __serialize_model(self: Self) -> tuple[Atom, Atom]:
|
|
216
|
+
"""Serialize the bond as an AlphaFold 3 bonded atom pair.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
tuple[Atom, Atom]: Compact AlphaFold 3 bonded atom pair
|
|
220
|
+
representation.
|
|
221
|
+
"""
|
|
222
|
+
return (self.source, self.target)
|
alphafold3_input/dna.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""DNA chain entity models.
|
|
2
|
+
|
|
3
|
+
This submodule defines :class:`DNA`, which can be used to include polymeric DNA
|
|
4
|
+
entities in an AlphaFold 3 input.
|
|
5
|
+
|
|
6
|
+
Exports:
|
|
7
|
+
- :class:`DNA`: DNA chain entity model.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
from typing import Annotated, Any, Self
|
|
14
|
+
|
|
15
|
+
from pydantic import (
|
|
16
|
+
AliasPath,
|
|
17
|
+
BaseModel,
|
|
18
|
+
ConfigDict,
|
|
19
|
+
Field,
|
|
20
|
+
SerializerFunctionWrapHandler,
|
|
21
|
+
StringConstraints,
|
|
22
|
+
field_validator,
|
|
23
|
+
model_serializer,
|
|
24
|
+
model_validator,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
from .modification import Entity, Modification
|
|
28
|
+
|
|
29
|
+
__all__: list[str] = [
|
|
30
|
+
"DNA",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class DNA(BaseModel):
|
|
35
|
+
"""DNA chain entity specification.
|
|
36
|
+
|
|
37
|
+
A DNA chain is defined by its nucleotide :attr:`sequence`, optional
|
|
38
|
+
:attr:`modifications`, and one or more chain identifiers via :attr:`id`.
|
|
39
|
+
Multiple copies can be defined either by setting :attr:`copies` or by
|
|
40
|
+
providing multiple explicit identifiers in :attr:`id`.
|
|
41
|
+
|
|
42
|
+
The optional :attr:`description` field is supported only when
|
|
43
|
+
:attr:`Job.version` is set to :attr:`Version.IV`.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
id (str | Sequence[str] | None): DNA chain identifier(s).
|
|
47
|
+
description (str | None): Free-text DNA chain description.
|
|
48
|
+
sequence (str): DNA chain nucleotide sequence.
|
|
49
|
+
modifications (Sequence[Modification]): DNA chain residue
|
|
50
|
+
modifications.
|
|
51
|
+
copies (int): Number of DNA chain copies.
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
DNA chain with a description.
|
|
55
|
+
|
|
56
|
+
>>> DNA(
|
|
57
|
+
... description="Promoter for bacteriophage T7 RNA polymerase",
|
|
58
|
+
... sequence="TAATACGACTCACTATAGG",
|
|
59
|
+
... )
|
|
60
|
+
|
|
61
|
+
Multiple copies of a DNA chain.
|
|
62
|
+
|
|
63
|
+
>>> DNA(
|
|
64
|
+
... sequence="GAATTC",
|
|
65
|
+
... copies=2,
|
|
66
|
+
... )
|
|
67
|
+
|
|
68
|
+
DNA chain with modified residues.
|
|
69
|
+
|
|
70
|
+
>>> heptamer = DNA(sequence="GACCTCT")
|
|
71
|
+
>>> heptamer.modify(
|
|
72
|
+
... Modification(type="6OG", position=1),
|
|
73
|
+
... Modification(type="6MA", position=2),
|
|
74
|
+
... )
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
model_config = ConfigDict(
|
|
78
|
+
extra="forbid",
|
|
79
|
+
frozen=False,
|
|
80
|
+
validate_assignment=True,
|
|
81
|
+
validate_by_name=True,
|
|
82
|
+
validate_by_alias=True,
|
|
83
|
+
use_enum_values=False,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
id: (
|
|
87
|
+
Annotated[str, StringConstraints(pattern="^[A-Z]+$")]
|
|
88
|
+
| Sequence[Annotated[str, StringConstraints(pattern="^[A-Z]+$")]]
|
|
89
|
+
| None
|
|
90
|
+
) = Field(
|
|
91
|
+
title="id",
|
|
92
|
+
alias="id",
|
|
93
|
+
description="DNA chain identifier(s).",
|
|
94
|
+
min_length=1,
|
|
95
|
+
validation_alias=AliasPath("dna", "id"),
|
|
96
|
+
serialization_alias="id",
|
|
97
|
+
default=None,
|
|
98
|
+
)
|
|
99
|
+
"""DNA chain identifier(s)."""
|
|
100
|
+
|
|
101
|
+
description: str | None = Field(
|
|
102
|
+
title="description",
|
|
103
|
+
alias="description",
|
|
104
|
+
description="Free-text DNA chain description.",
|
|
105
|
+
validation_alias=AliasPath("dna", "description"),
|
|
106
|
+
serialization_alias="description",
|
|
107
|
+
default=None,
|
|
108
|
+
)
|
|
109
|
+
"""Free-text DNA chain description."""
|
|
110
|
+
|
|
111
|
+
sequence: Annotated[str, StringConstraints(pattern="^[ACGT]+$")] = Field(
|
|
112
|
+
title="sequence",
|
|
113
|
+
alias="sequence",
|
|
114
|
+
description="DNA chain nucleotide sequence.",
|
|
115
|
+
min_length=1,
|
|
116
|
+
validation_alias=AliasPath("dna", "sequence"),
|
|
117
|
+
serialization_alias="sequence",
|
|
118
|
+
)
|
|
119
|
+
"""DNA chain nucleotide sequence."""
|
|
120
|
+
|
|
121
|
+
modifications: Sequence[Modification] = Field(
|
|
122
|
+
title="modifications",
|
|
123
|
+
alias="modifications",
|
|
124
|
+
description="DNA chain residue modifications.",
|
|
125
|
+
validation_alias=AliasPath("dna", "modifications"),
|
|
126
|
+
serialization_alias="modifications",
|
|
127
|
+
default_factory=tuple,
|
|
128
|
+
)
|
|
129
|
+
"""DNA chain residue modifications."""
|
|
130
|
+
|
|
131
|
+
copies: int = Field(
|
|
132
|
+
title="copies",
|
|
133
|
+
alias="copies",
|
|
134
|
+
description="Number of DNA chain copies.",
|
|
135
|
+
ge=1,
|
|
136
|
+
validation_alias="copies",
|
|
137
|
+
exclude=True,
|
|
138
|
+
repr=False,
|
|
139
|
+
default=1,
|
|
140
|
+
)
|
|
141
|
+
"""Number of DNA chain copies."""
|
|
142
|
+
|
|
143
|
+
def modify(self: Self, *modifications: Modification) -> Self:
|
|
144
|
+
"""Append residue modifications to the DNA chain.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
*modifications (Modification): One or more modifications to add.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Self: DNA chain with appended modifications.
|
|
151
|
+
|
|
152
|
+
Raises:
|
|
153
|
+
TypeError: If no modifications were provided.
|
|
154
|
+
"""
|
|
155
|
+
if not modifications:
|
|
156
|
+
msg: str = (
|
|
157
|
+
"Invalid DNA modification: no modifications were provided."
|
|
158
|
+
)
|
|
159
|
+
raise TypeError(msg)
|
|
160
|
+
|
|
161
|
+
self.modifications: tuple[Modification, ...] = tuple(
|
|
162
|
+
self.modifications,
|
|
163
|
+
) + tuple(modifications)
|
|
164
|
+
return self
|
|
165
|
+
|
|
166
|
+
@field_validator("modifications", mode="after")
|
|
167
|
+
@classmethod
|
|
168
|
+
def __scope_modifications(
|
|
169
|
+
cls: type[Self],
|
|
170
|
+
value: Sequence[Modification],
|
|
171
|
+
) -> Sequence[Modification]:
|
|
172
|
+
"""Assign DNA scope to each modification.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
value (Sequence[Modification]): Modification entries.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
Sequence[Modification]: Scoped modification entries.
|
|
179
|
+
"""
|
|
180
|
+
for modification in value:
|
|
181
|
+
object.__setattr__(modification, "scope", Entity.DNA)
|
|
182
|
+
return value
|
|
183
|
+
|
|
184
|
+
@model_validator(mode="after")
|
|
185
|
+
def __validate_modifications(self: Self) -> Self:
|
|
186
|
+
"""Validate residue modifications against the DNA sequence.
|
|
187
|
+
|
|
188
|
+
Ensures that each modification position is within the sequence and that
|
|
189
|
+
no residue is modified more than once.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
Self: Validated DNA chain instance.
|
|
193
|
+
|
|
194
|
+
Raises:
|
|
195
|
+
ValueError: If a modification position is out of range.
|
|
196
|
+
ValueError: If multiple modifications target the same position.
|
|
197
|
+
"""
|
|
198
|
+
length: int = len(self.sequence)
|
|
199
|
+
modified: set[int] = set()
|
|
200
|
+
|
|
201
|
+
for modification in self.modifications:
|
|
202
|
+
if modification.position > length:
|
|
203
|
+
msg: str = (
|
|
204
|
+
"Invalid DNA modification: modification `position` is out "
|
|
205
|
+
f"of range (position={modification.position}, "
|
|
206
|
+
f"len(sequence)={length})."
|
|
207
|
+
)
|
|
208
|
+
raise ValueError(msg)
|
|
209
|
+
|
|
210
|
+
if modification.position in modified:
|
|
211
|
+
msg: str = (
|
|
212
|
+
"Invalid DNA modification list: multiple modifications on "
|
|
213
|
+
f"the same `position` (position={modification.position})."
|
|
214
|
+
)
|
|
215
|
+
raise ValueError(msg)
|
|
216
|
+
|
|
217
|
+
modified.add(modification.position)
|
|
218
|
+
|
|
219
|
+
return self
|
|
220
|
+
|
|
221
|
+
@model_validator(mode="after")
|
|
222
|
+
def __validate_copies(self: Self) -> Self:
|
|
223
|
+
"""Validate consistency between ``id`` and ``copies``.
|
|
224
|
+
|
|
225
|
+
If :attr:`id` is provided, :attr:`copies` is set to ``len(id)``. If
|
|
226
|
+
:attr:`copies` was explicitly provided and is inconsistent with
|
|
227
|
+
:attr:`id`, a :class:`ValueError` is raised.
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
Self: Validated DNA chain instance.
|
|
231
|
+
|
|
232
|
+
Raises:
|
|
233
|
+
ValueError: If ``copies`` is inconsistent with ``id``.
|
|
234
|
+
"""
|
|
235
|
+
if self.id is None:
|
|
236
|
+
return self
|
|
237
|
+
|
|
238
|
+
n: int = len(self.id) if not isinstance(self.id, str) else 1
|
|
239
|
+
|
|
240
|
+
if "copies" in self.model_fields_set and self.copies != n:
|
|
241
|
+
msg: str = (
|
|
242
|
+
"Conflicting DNA configuration: `copies` is inconsistent "
|
|
243
|
+
f"with the length of `id` (copies={self.copies}, len(id)={n})."
|
|
244
|
+
)
|
|
245
|
+
raise ValueError(msg)
|
|
246
|
+
|
|
247
|
+
object.__setattr__(self, "copies", n)
|
|
248
|
+
return self
|
|
249
|
+
|
|
250
|
+
@model_serializer(mode="wrap")
|
|
251
|
+
def __wrapped_serialization(
|
|
252
|
+
self: Self,
|
|
253
|
+
handler: SerializerFunctionWrapHandler,
|
|
254
|
+
) -> dict[str, Any]:
|
|
255
|
+
"""Serialize the entity in wrapped AlphaFold 3 form.
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
dict[str, Any]: Wrapped entity mapping.
|
|
259
|
+
"""
|
|
260
|
+
return {self.__class__.__name__.lower(): handler(self)}
|