rowan-python 2.1.11__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.
- rowan/__init__.py +9 -0
- rowan/constants.py +3 -0
- rowan/folder.py +228 -0
- rowan/project.py +136 -0
- rowan/protein.py +245 -0
- rowan/py.typed +0 -0
- rowan/rowan_rdkit/__init__.py +29 -0
- rowan/rowan_rdkit/chem_utils.py +1012 -0
- rowan/user.py +137 -0
- rowan/utils.py +174 -0
- rowan/workflow.py +1608 -0
- rowan_python-2.1.11.dist-info/METADATA +41 -0
- rowan_python-2.1.11.dist-info/RECORD +15 -0
- rowan_python-2.1.11.dist-info/WHEEL +4 -0
- rowan_python-2.1.11.dist-info/licenses/LICENSE +21 -0
rowan/__init__.py
ADDED
rowan/constants.py
ADDED
rowan/folder.py
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Self
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from .utils import api_client
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Folder(BaseModel):
|
|
10
|
+
"""
|
|
11
|
+
A class representing a folder in the Rowan API.
|
|
12
|
+
|
|
13
|
+
:ivar uuid: The UUID of the folder.
|
|
14
|
+
:ivar name: The name of the folder.
|
|
15
|
+
:ivar parent_uuid: The UUID of the parent folder.
|
|
16
|
+
:ivar notes: Folder notes.
|
|
17
|
+
:ivar starred: Whether the folder is starred.
|
|
18
|
+
:ivar public: Whether the folder is public.
|
|
19
|
+
:ivar created_at: The date and time the folder was created.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
uuid: str
|
|
23
|
+
name: str | None = None
|
|
24
|
+
parent_uuid: str | None = None
|
|
25
|
+
notes: str = ""
|
|
26
|
+
starred: bool = False
|
|
27
|
+
public: bool = False
|
|
28
|
+
created_at: datetime | None = None
|
|
29
|
+
|
|
30
|
+
def __repr__(self) -> str:
|
|
31
|
+
return f"<Folder name='{self.name}' created_at='{self.created_at}' uuid='{self.uuid}'>"
|
|
32
|
+
|
|
33
|
+
def fetch_latest(self, in_place: bool = False) -> Self:
|
|
34
|
+
"""
|
|
35
|
+
Fetch the latest folder data from the API.
|
|
36
|
+
|
|
37
|
+
This method refreshes the folder object with the latest data from the API.
|
|
38
|
+
|
|
39
|
+
:param in_place: Whether to update the current instance in-place.
|
|
40
|
+
:return: The updated instance (self).
|
|
41
|
+
:raises HTTPError: If the API request fails.
|
|
42
|
+
"""
|
|
43
|
+
with api_client() as client:
|
|
44
|
+
response = client.get(f"/folder/{self.uuid}")
|
|
45
|
+
response.raise_for_status()
|
|
46
|
+
data = response.json()
|
|
47
|
+
|
|
48
|
+
if not in_place:
|
|
49
|
+
return self.__class__.model_validate(data)
|
|
50
|
+
|
|
51
|
+
updated_folder = self.model_validate(data)
|
|
52
|
+
|
|
53
|
+
# Update current instance with new data using class-level model_fields
|
|
54
|
+
for field_name in self.__class__.model_fields:
|
|
55
|
+
setattr(self, field_name, getattr(updated_folder, field_name))
|
|
56
|
+
|
|
57
|
+
self.model_rebuild()
|
|
58
|
+
|
|
59
|
+
return self
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def update(
|
|
63
|
+
self,
|
|
64
|
+
name: str | None = None,
|
|
65
|
+
parent_uuid: str | None = None,
|
|
66
|
+
notes: str | None = None,
|
|
67
|
+
starred: bool | None = None,
|
|
68
|
+
public: bool | None = None,
|
|
69
|
+
) -> Self:
|
|
70
|
+
"""
|
|
71
|
+
Update a folder.
|
|
72
|
+
|
|
73
|
+
:param name: The new name of the folder.
|
|
74
|
+
:param parent_uuid: The UUID of the new parent folder.
|
|
75
|
+
:param notes: A description of the folder.
|
|
76
|
+
:param starred: Whether the folder is starred.
|
|
77
|
+
:param public: Whether the folder is public.
|
|
78
|
+
|
|
79
|
+
:return: The updated folder object.
|
|
80
|
+
"""
|
|
81
|
+
payload = {
|
|
82
|
+
"name": name if name is not None else self.name,
|
|
83
|
+
"parent_uuid": parent_uuid if parent_uuid is not None else self.parent_uuid,
|
|
84
|
+
"notes": notes if notes is not None else self.notes,
|
|
85
|
+
"starred": starred if starred is not None else self.starred,
|
|
86
|
+
"public": public if public is not None else self.public,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
with api_client() as client:
|
|
90
|
+
response = client.post(f"/folder/{self.uuid}", json=payload)
|
|
91
|
+
response.raise_for_status()
|
|
92
|
+
updated_data = response.json()
|
|
93
|
+
|
|
94
|
+
self.name = updated_data.get("name")
|
|
95
|
+
self.parent_uuid = updated_data.get("parent_uuid")
|
|
96
|
+
self.notes = updated_data.get("notes")
|
|
97
|
+
self.starred = updated_data.get("starred")
|
|
98
|
+
self.public = updated_data.get("public")
|
|
99
|
+
return self
|
|
100
|
+
|
|
101
|
+
def delete(self) -> None:
|
|
102
|
+
"""
|
|
103
|
+
Delete the folder and all its contents.
|
|
104
|
+
|
|
105
|
+
This is a destructive action, it will delete all the folders and
|
|
106
|
+
workflows that are inside this folder.
|
|
107
|
+
|
|
108
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
109
|
+
"""
|
|
110
|
+
with api_client() as client:
|
|
111
|
+
response = client.delete(f"/folder/{self.uuid}")
|
|
112
|
+
response.raise_for_status()
|
|
113
|
+
|
|
114
|
+
def print_folder_tree(self, max_depth: int = 10, show_uuids: bool = False) -> None:
|
|
115
|
+
"""
|
|
116
|
+
Retrieves a folder tree from the API.
|
|
117
|
+
|
|
118
|
+
:param max_depth: The maximum depth of the folder tree.
|
|
119
|
+
:param show_uuids: Whether to show the UUIDs of the folders.
|
|
120
|
+
:raises HTTPError: If the API request fails.
|
|
121
|
+
"""
|
|
122
|
+
print_folder_tree(self.uuid, max_depth, show_uuids)
|
|
123
|
+
|
|
124
|
+
def retrieve_folder(uuid: str) -> Folder:
|
|
125
|
+
"""
|
|
126
|
+
Retrieves a folder from the API by UUID. Folder UUID can be found in the folder's URL.
|
|
127
|
+
|
|
128
|
+
:param uuid: The UUID of the folder to retrieve.
|
|
129
|
+
:return: A Folder object representing the retrieved folder.
|
|
130
|
+
:raises HTTPError: If the API request fails.
|
|
131
|
+
"""
|
|
132
|
+
with api_client() as client:
|
|
133
|
+
response = client.get(f"/folder/{uuid}")
|
|
134
|
+
response.raise_for_status()
|
|
135
|
+
return Folder(**response.json())
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def list_folders(
|
|
139
|
+
parent_uuid: str | None = None,
|
|
140
|
+
name_contains: str | None = None,
|
|
141
|
+
public: bool | None = None,
|
|
142
|
+
starred: bool | None = None,
|
|
143
|
+
page: int = 0,
|
|
144
|
+
size: int = 10,
|
|
145
|
+
) -> list[Folder]:
|
|
146
|
+
"""
|
|
147
|
+
Retrieve a list of folders based on the specified criteria.
|
|
148
|
+
|
|
149
|
+
:param parent_uuid: UUID of the parent folder to filter by.
|
|
150
|
+
:param name_contains: Substring to search for in folder names.
|
|
151
|
+
:param public: Filter folders by their public status.
|
|
152
|
+
:param starred: Filter folders by their starred status.
|
|
153
|
+
:param page: Pagination parameter to specify the page number.
|
|
154
|
+
:param size: Pagination parameter to specify the number of items per page.
|
|
155
|
+
:return: A list of Folder objects that match the search criteria.
|
|
156
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
params: dict[str, Any] = {
|
|
160
|
+
"page": page,
|
|
161
|
+
"size": size,
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if parent_uuid is not None:
|
|
165
|
+
params["parent_uuid"] = parent_uuid
|
|
166
|
+
if name_contains is not None:
|
|
167
|
+
params["name_contains"] = name_contains
|
|
168
|
+
if public is not None:
|
|
169
|
+
params["public"] = public
|
|
170
|
+
if starred is not None:
|
|
171
|
+
params["starred"] = starred
|
|
172
|
+
|
|
173
|
+
with api_client() as client:
|
|
174
|
+
response = client.get("/folder", params=params)
|
|
175
|
+
response.raise_for_status()
|
|
176
|
+
items = response.json()["folders"]
|
|
177
|
+
|
|
178
|
+
return [Folder(**item) for item in items]
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def create_folder(
|
|
182
|
+
name: str,
|
|
183
|
+
parent_uuid: str | None = None,
|
|
184
|
+
notes: str = "",
|
|
185
|
+
starred: bool = False,
|
|
186
|
+
public: bool = False,
|
|
187
|
+
) -> Folder:
|
|
188
|
+
"""
|
|
189
|
+
Create a new folder.
|
|
190
|
+
|
|
191
|
+
:param name: The name of the folder.
|
|
192
|
+
:param parent_uuid: The UUID of the parent folder.
|
|
193
|
+
:param notes: A description of the folder.
|
|
194
|
+
:param starred: Whether the folder is starred.
|
|
195
|
+
:param public: Whether the folder is public.
|
|
196
|
+
:return: The newly created folder.
|
|
197
|
+
"""
|
|
198
|
+
data = {
|
|
199
|
+
"name": name,
|
|
200
|
+
"parent_uuid": parent_uuid,
|
|
201
|
+
"notes": notes,
|
|
202
|
+
"starred": starred,
|
|
203
|
+
"public": public,
|
|
204
|
+
}
|
|
205
|
+
with api_client() as client:
|
|
206
|
+
response = client.post("/folder", json=data)
|
|
207
|
+
response.raise_for_status()
|
|
208
|
+
folder_data = response.json()
|
|
209
|
+
return Folder(**folder_data)
|
|
210
|
+
|
|
211
|
+
def print_folder_tree(uuid: str, max_depth: int = 10, show_uuids: bool = False) -> None:
|
|
212
|
+
"""
|
|
213
|
+
Retrieves a folder tree from the API.
|
|
214
|
+
|
|
215
|
+
:param uuid: The UUID of the root of the folder tree.
|
|
216
|
+
:param max_depth: The maximum depth of the folder tree.
|
|
217
|
+
:param show_uuids: Whether to show the UUIDs of the folders.
|
|
218
|
+
:raises HTTPError: If the API request fails.
|
|
219
|
+
"""
|
|
220
|
+
params: dict[str, Any] = {
|
|
221
|
+
"max_depth": max_depth,
|
|
222
|
+
"show_uuids": show_uuids,
|
|
223
|
+
}
|
|
224
|
+
with api_client() as client:
|
|
225
|
+
response = client.get(f"/folder/{uuid}/folder_tree", params=params)
|
|
226
|
+
response.raise_for_status()
|
|
227
|
+
folder_data = response.json()
|
|
228
|
+
print(folder_data)
|
rowan/project.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Self
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from .utils import api_client
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Project(BaseModel):
|
|
10
|
+
"""
|
|
11
|
+
A class representing a project in the Rowan API.
|
|
12
|
+
|
|
13
|
+
:ivar uuid: The UUID of the project.
|
|
14
|
+
:ivar name: The name of the project.
|
|
15
|
+
:ivar created_at: The date and time the project was created.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
uuid: str
|
|
19
|
+
name: str | None = None
|
|
20
|
+
created_at: datetime | None = None
|
|
21
|
+
|
|
22
|
+
def __repr__(self) -> str:
|
|
23
|
+
return f"<Project name='{self.name}' created_at='{self.created_at}' uuid='{self.uuid}'>"
|
|
24
|
+
|
|
25
|
+
def update(
|
|
26
|
+
self,
|
|
27
|
+
name: str | None = None,
|
|
28
|
+
) -> Self:
|
|
29
|
+
"""
|
|
30
|
+
Update a project.
|
|
31
|
+
|
|
32
|
+
:param name: The new name of the project.
|
|
33
|
+
|
|
34
|
+
:return: The updated project object.
|
|
35
|
+
"""
|
|
36
|
+
payload = {
|
|
37
|
+
"name": name if name is not None else self.name,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
with api_client() as client:
|
|
41
|
+
response = client.post(f"/project/{self.uuid}", json=payload)
|
|
42
|
+
response.raise_for_status()
|
|
43
|
+
updated_data = response.json()
|
|
44
|
+
|
|
45
|
+
self.name = updated_data.get("name")
|
|
46
|
+
return self
|
|
47
|
+
|
|
48
|
+
def delete(self) -> None:
|
|
49
|
+
"""
|
|
50
|
+
Delete the project.
|
|
51
|
+
|
|
52
|
+
This is a destructive action, it will delete all the folders and
|
|
53
|
+
workflows that are inside this project.
|
|
54
|
+
|
|
55
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
56
|
+
"""
|
|
57
|
+
with api_client() as client:
|
|
58
|
+
response = client.delete(f"/project/{self.uuid}")
|
|
59
|
+
response.raise_for_status()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def retrieve_project(uuid: str) -> Project:
|
|
63
|
+
"""
|
|
64
|
+
Retrieves a project from the API by UUID. Project UUID can be found in the project's URL.
|
|
65
|
+
|
|
66
|
+
:param uuid: The UUID of the project to retrieve.
|
|
67
|
+
:return: A Project object representing the retrieved project.
|
|
68
|
+
:raises HTTPError: If the API request fails.
|
|
69
|
+
"""
|
|
70
|
+
with api_client() as client:
|
|
71
|
+
response = client.get(f"/project/{uuid}")
|
|
72
|
+
response.raise_for_status()
|
|
73
|
+
return Project(**response.json())
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def list_projects(
|
|
77
|
+
name_contains: str | None = None,
|
|
78
|
+
page: int = 0,
|
|
79
|
+
size: int = 10,
|
|
80
|
+
) -> list[Project]:
|
|
81
|
+
"""
|
|
82
|
+
Retrieve a list of projects based on the specified criteria.
|
|
83
|
+
|
|
84
|
+
:param name_contains: Substring to search for in project names.
|
|
85
|
+
:param page: Pagination parameter to specify the page number.
|
|
86
|
+
:param size: Pagination parameter to specify the number of items per page.
|
|
87
|
+
:return: A list of Folder objects that match the search criteria.
|
|
88
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
params: dict[str, Any] = {
|
|
92
|
+
"page": page,
|
|
93
|
+
"size": size,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if name_contains is not None:
|
|
97
|
+
params["name_contains"] = name_contains
|
|
98
|
+
|
|
99
|
+
with api_client() as client:
|
|
100
|
+
response = client.get("/project", params=params)
|
|
101
|
+
response.raise_for_status()
|
|
102
|
+
items = response.json()
|
|
103
|
+
|
|
104
|
+
return [Project(**item) for item in items]
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def create_project(
|
|
108
|
+
name: str,
|
|
109
|
+
) -> Project:
|
|
110
|
+
"""
|
|
111
|
+
Create a new project.
|
|
112
|
+
|
|
113
|
+
:param name: The name of the project.
|
|
114
|
+
:return: The newly created project.
|
|
115
|
+
"""
|
|
116
|
+
data = {
|
|
117
|
+
"name": name,
|
|
118
|
+
}
|
|
119
|
+
with api_client() as client:
|
|
120
|
+
response = client.post("/project", json=data)
|
|
121
|
+
response.raise_for_status()
|
|
122
|
+
project_data = response.json()
|
|
123
|
+
return Project(**project_data)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def default_project() -> Project:
|
|
127
|
+
"""
|
|
128
|
+
Retrieves the default project from the API.
|
|
129
|
+
|
|
130
|
+
:return: A Project object representing the default project.
|
|
131
|
+
:raises HTTPError: If the API request fails.
|
|
132
|
+
"""
|
|
133
|
+
with api_client() as client:
|
|
134
|
+
response = client.get("/user/me/default_project")
|
|
135
|
+
response.raise_for_status()
|
|
136
|
+
return Project(**response.json())
|
rowan/protein.py
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Self
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from .utils import api_client
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Protein(BaseModel):
|
|
11
|
+
"""
|
|
12
|
+
A Rowan protein.
|
|
13
|
+
|
|
14
|
+
Data is not loaded by default to avoid unnecessary downloads that could impact performance.
|
|
15
|
+
Call `load_data()` to fetch and attach the protein data to this `Protein` object.
|
|
16
|
+
|
|
17
|
+
:ivar uuid: The UUID of the protein
|
|
18
|
+
:ivar created_at: The creation date of the protein
|
|
19
|
+
:ivar used_in_workflow: Whether the protein is used in a workflow
|
|
20
|
+
:ivar ancestor_uuid: The UUID of the ancestor protein
|
|
21
|
+
:ivar sanitized: Whether the protein is sanitized
|
|
22
|
+
:ivar name: The name of the protein
|
|
23
|
+
:ivar data: The data of the protein
|
|
24
|
+
:ivar public: Whether the protein is public
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
uuid: str
|
|
28
|
+
created_at: datetime | None = None
|
|
29
|
+
used_in_workflow: bool | None = None
|
|
30
|
+
ancestor_uuid: str | None = None
|
|
31
|
+
sanitized: int | None = None
|
|
32
|
+
name: str | None = None
|
|
33
|
+
data: dict | None = None
|
|
34
|
+
public: bool | None = None
|
|
35
|
+
pocket: list[list[float]] | None = None
|
|
36
|
+
|
|
37
|
+
def __repr__(self):
|
|
38
|
+
return f"<Protein name='{self.name}' created_at='{self.created_at}' uuid='{self.uuid}'>"
|
|
39
|
+
|
|
40
|
+
def refresh(self, in_place: bool = True) -> Self:
|
|
41
|
+
"""
|
|
42
|
+
Loads protein data
|
|
43
|
+
|
|
44
|
+
:return: protein with loaded data
|
|
45
|
+
"""
|
|
46
|
+
with api_client() as client:
|
|
47
|
+
response = client.get(f"/protein/{self.uuid}")
|
|
48
|
+
response.raise_for_status()
|
|
49
|
+
protein_data = response.json()
|
|
50
|
+
if not in_place:
|
|
51
|
+
return self.__class__.model_validate(protein_data)
|
|
52
|
+
|
|
53
|
+
self.name = protein_data.get("name")
|
|
54
|
+
self.data = protein_data.get("data")
|
|
55
|
+
self.public = protein_data.get("public")
|
|
56
|
+
self.pocket = protein_data.get("pocket")
|
|
57
|
+
self.sanitized = protein_data.get("sanitized")
|
|
58
|
+
self.used_in_workflow = protein_data.get("used_in_workflow")
|
|
59
|
+
return self
|
|
60
|
+
|
|
61
|
+
def update(
|
|
62
|
+
self,
|
|
63
|
+
name: str | None = None,
|
|
64
|
+
data: dict | None = None,
|
|
65
|
+
public: bool | None = None,
|
|
66
|
+
pocket: list[list[float]] | None = None,
|
|
67
|
+
) -> Self:
|
|
68
|
+
# Use current values unless new ones are passed in
|
|
69
|
+
"""
|
|
70
|
+
Updates protein data
|
|
71
|
+
|
|
72
|
+
:param name: The new name of the protein
|
|
73
|
+
:param data: The new data of the protein
|
|
74
|
+
:param public: Whether the protein is public
|
|
75
|
+
:param pocket: The new pocket of the protein
|
|
76
|
+
:return: The updated protein object
|
|
77
|
+
"""
|
|
78
|
+
updated_payload = {
|
|
79
|
+
"name": name if name is not None else self.name,
|
|
80
|
+
"data": data if data is not None else self.data,
|
|
81
|
+
"public": public if public is not None else self.public,
|
|
82
|
+
"pocket": pocket if pocket is not None else self.pocket,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
with api_client() as client:
|
|
86
|
+
response = client.post(f"/protein/{self.uuid}", json=updated_payload)
|
|
87
|
+
response.raise_for_status()
|
|
88
|
+
updated_data = response.json()
|
|
89
|
+
|
|
90
|
+
# Update attributes
|
|
91
|
+
self.name = updated_data.get("name")
|
|
92
|
+
self.data = updated_data.get("data")
|
|
93
|
+
self.public = updated_data.get("public")
|
|
94
|
+
self.pocket = updated_data.get("pocket")
|
|
95
|
+
return self
|
|
96
|
+
|
|
97
|
+
def delete(self) -> None:
|
|
98
|
+
"""
|
|
99
|
+
Deletes a protein
|
|
100
|
+
|
|
101
|
+
:raises requests.HTTPError: if the request to the API fails
|
|
102
|
+
"""
|
|
103
|
+
with api_client() as client:
|
|
104
|
+
response = client.delete(f"/protein/{self.uuid}")
|
|
105
|
+
response.raise_for_status()
|
|
106
|
+
|
|
107
|
+
def sanitize(self) -> None:
|
|
108
|
+
"""
|
|
109
|
+
Sanitizes a protein
|
|
110
|
+
|
|
111
|
+
:raises requests.HTTPError: if the request to the API fails
|
|
112
|
+
"""
|
|
113
|
+
with api_client() as client:
|
|
114
|
+
response = client.post(f"/protein/sanitize/{self.uuid}")
|
|
115
|
+
response.raise_for_status()
|
|
116
|
+
|
|
117
|
+
def download_pdb_file(self, path: Path | None = None, name: str | None = None) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Downloads the PDB file for a protein
|
|
120
|
+
|
|
121
|
+
:param path: Directory to save the file to (defaults to current directory)
|
|
122
|
+
:param name: Optional custom name for the file (defaults to protein name)
|
|
123
|
+
:raises requests.HTTPError: if the request to the API fails
|
|
124
|
+
"""
|
|
125
|
+
if path is None:
|
|
126
|
+
path = Path.cwd()
|
|
127
|
+
|
|
128
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
129
|
+
|
|
130
|
+
with api_client() as client:
|
|
131
|
+
response = client.get(f"/protein/{self.uuid}/get_pdb_file")
|
|
132
|
+
response.raise_for_status()
|
|
133
|
+
|
|
134
|
+
file_path = path / f"{name or self.name}.pdb"
|
|
135
|
+
with open(file_path, "wb") as f:
|
|
136
|
+
f.write(response.content)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def retrieve_protein(uuid: str) -> Protein:
|
|
140
|
+
"""
|
|
141
|
+
Retrieves a protein from the API using its UUID.
|
|
142
|
+
|
|
143
|
+
:param uuid: The UUID of the protein to retrieve.
|
|
144
|
+
:return: A Protein object representing the retrieved protein.
|
|
145
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
with api_client() as client:
|
|
149
|
+
response = client.get(f"/protein/{uuid}")
|
|
150
|
+
response.raise_for_status()
|
|
151
|
+
protein_data = response.json()
|
|
152
|
+
|
|
153
|
+
return Protein(**protein_data)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def list_proteins(
|
|
157
|
+
ancestor_uuid: str | None = None,
|
|
158
|
+
name_contains: str | None = None,
|
|
159
|
+
page: int = 0,
|
|
160
|
+
size: int = 20,
|
|
161
|
+
) -> list[Protein]:
|
|
162
|
+
"""
|
|
163
|
+
List proteins
|
|
164
|
+
|
|
165
|
+
:param ancestor_uuid: The UUID of the ancestor protein to filter by
|
|
166
|
+
:param name_contains: Substring to search for in protein names
|
|
167
|
+
:param page: The page number to retrieve
|
|
168
|
+
:param size: The number of items per page
|
|
169
|
+
:return: A list of Protein objects that match the search criteria
|
|
170
|
+
:raises requests.HTTPError: if the request to the API fails
|
|
171
|
+
"""
|
|
172
|
+
params: dict[str, Any] = {"page": page, "size": size}
|
|
173
|
+
if ancestor_uuid is not None:
|
|
174
|
+
params["ancestor_uuid"] = ancestor_uuid
|
|
175
|
+
if name_contains is not None:
|
|
176
|
+
params["name_contains"] = name_contains
|
|
177
|
+
|
|
178
|
+
with api_client() as client:
|
|
179
|
+
response = client.get("/protein", params=params)
|
|
180
|
+
response.raise_for_status()
|
|
181
|
+
results = response.json()["proteins"]
|
|
182
|
+
|
|
183
|
+
return [Protein(**item) for item in results]
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def upload_protein(name: str, file_path: Path, project_uuid: str | None = None) -> Protein:
|
|
187
|
+
"""
|
|
188
|
+
Uploads a protein from a PDB file to the API.
|
|
189
|
+
|
|
190
|
+
:param name: The name of the protein to create
|
|
191
|
+
:param file_path: The path to the PDB file to upload
|
|
192
|
+
:return: A Protein object representing the uploaded protein
|
|
193
|
+
:raises requests.HTTPError: if the request to the API fails
|
|
194
|
+
"""
|
|
195
|
+
with api_client() as client:
|
|
196
|
+
# Step 1: Read the file and post it to the conversion endpoint.
|
|
197
|
+
conversion_payload = {"name": name, "text": file_path.read_text()}
|
|
198
|
+
conversion_response = client.post("/convert/pdb_file_to_protein", json=conversion_payload)
|
|
199
|
+
conversion_response.raise_for_status() # Ensure the request was successful
|
|
200
|
+
|
|
201
|
+
# Extract the JSON data from the conversion response.
|
|
202
|
+
protein_data = conversion_response.json()
|
|
203
|
+
|
|
204
|
+
# Step 2: Use the converted data to create the final protein object.
|
|
205
|
+
creation_payload = {
|
|
206
|
+
"name": name,
|
|
207
|
+
"protein_data": protein_data,
|
|
208
|
+
"project_uuid": project_uuid,
|
|
209
|
+
}
|
|
210
|
+
final_response = client.post("/protein", json=creation_payload)
|
|
211
|
+
final_response.raise_for_status()
|
|
212
|
+
|
|
213
|
+
# Deserialize the final JSON response into a Protein object and return it.
|
|
214
|
+
return Protein(**final_response.json())
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def create_protein_from_pdb_id(name: str, code: str, project_uuid: str | None = None) -> Protein:
|
|
218
|
+
"""
|
|
219
|
+
Creates a protein from a PDB ID.
|
|
220
|
+
|
|
221
|
+
:param name: The name of the protein to create
|
|
222
|
+
:param code: The PDB ID of the protein to create
|
|
223
|
+
:param project_uuid: The UUID of the project to create the protein in
|
|
224
|
+
:return: A Protein object representing the created protein
|
|
225
|
+
:raises requests.HTTPError: if the request to the API fails
|
|
226
|
+
"""
|
|
227
|
+
with api_client() as client:
|
|
228
|
+
# Step 1: Read the file and post it to the conversion endpoint.
|
|
229
|
+
conversion_response = client.post(f"/convert/pdb_id_to_protein?pdb_id={code}")
|
|
230
|
+
conversion_response.raise_for_status() # Ensure the request was successful
|
|
231
|
+
|
|
232
|
+
# Extract the JSON data from the conversion response.
|
|
233
|
+
protein_data = conversion_response.json()
|
|
234
|
+
|
|
235
|
+
# Step 2: Use the converted data to create the final protein object.
|
|
236
|
+
creation_payload = {
|
|
237
|
+
"name": name,
|
|
238
|
+
"protein_data": protein_data,
|
|
239
|
+
"project_uuid": project_uuid,
|
|
240
|
+
}
|
|
241
|
+
final_response = client.post("/protein", json=creation_payload)
|
|
242
|
+
final_response.raise_for_status()
|
|
243
|
+
|
|
244
|
+
# Deserialize the final JSON response into a Protein object and return it.
|
|
245
|
+
return Protein(**final_response.json())
|
rowan/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from .chem_utils import (
|
|
2
|
+
batch_charges,
|
|
3
|
+
batch_conformers,
|
|
4
|
+
batch_energy,
|
|
5
|
+
batch_optimize,
|
|
6
|
+
batch_pka,
|
|
7
|
+
batch_tautomers,
|
|
8
|
+
run_charges,
|
|
9
|
+
run_conformers,
|
|
10
|
+
run_energy,
|
|
11
|
+
run_optimize,
|
|
12
|
+
run_pka,
|
|
13
|
+
run_tautomers,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"batch_charges",
|
|
18
|
+
"batch_conformers",
|
|
19
|
+
"batch_energy",
|
|
20
|
+
"batch_optimize",
|
|
21
|
+
"batch_pka",
|
|
22
|
+
"batch_tautomers",
|
|
23
|
+
"run_charges",
|
|
24
|
+
"run_conformers",
|
|
25
|
+
"run_energy",
|
|
26
|
+
"run_optimize",
|
|
27
|
+
"run_pka",
|
|
28
|
+
"run_tautomers",
|
|
29
|
+
]
|