Skip to content

Commit 7148f83

Browse files
committed
feat(apiclient): add CRUD methods for instantiated entities
1 parent 6f40660 commit 7148f83

File tree

3 files changed

+95
-7
lines changed

3 files changed

+95
-7
lines changed

.flake8

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[flake8]
2-
ignore = E226,E302,E41,W503
2+
ignore = E226,E302,E41,W503,E704
33
max-line-length = 88
44
exclude = tests/*

.github/workflows/push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
uses: TrueBrain/actions-flake8@master
2626
with:
2727
max_line_length: 88
28-
extend-ignore: E203
28+
extend-ignore: E203, E704
2929
test:
3030
runs-on: ubuntu-latest
3131
strategy:

cellengine/utils/api_client/APIClient.py

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
from __future__ import annotations
2-
import os
2+
from functools import lru_cache
3+
from getpass import getpass
34
import json
5+
import os
6+
from typing import Any, Dict, List, Optional, TypeVar, Union, overload
7+
48
import pandas
5-
from getpass import getpass
6-
from typing import Any, Dict, List, Union, Optional
7-
from functools import lru_cache
89
from requests_toolbelt.multipart.encoder import MultipartEncoder
910

10-
from cellengine.utils.api_client.BaseAPIClient import BaseAPIClient
11+
from cellengine.utils import converter
1112
from cellengine.utils.api_client.APIError import APIError
13+
from cellengine.utils.api_client.BaseAPIClient import BaseAPIClient
1214
from cellengine.utils.singleton import Singleton
15+
1316
from ...resources.attachment import Attachment
1417
from ...resources.compensation import Compensation
1518
from ...resources.experiment import Experiment
@@ -20,6 +23,28 @@
2023
from ...resources.scaleset import ScaleSet
2124

2225

26+
CE = TypeVar(
27+
"CE",
28+
bound=Union[
29+
Attachment, Compensation, Experiment, FcsFile, Gate, Plot, Population, ScaleSet
30+
],
31+
)
32+
33+
34+
def create_many(client: APIClient, entities: List[CE], **kwargs) -> List[Gate]:
35+
body = [client.unstructure_and_clean(e) for e in entities]
36+
(classes, paths, payload) = list(zip(*body))
37+
_class = set(classes)
38+
if len(_class) != 1 or Gate not in _class:
39+
raise TypeError(f"Type or types {_class} cannot be created in bulk.")
40+
return client.post_and_structure(
41+
List[_class.pop()], # type: ignore
42+
set(paths).pop(),
43+
list(payload),
44+
kwargs=kwargs,
45+
)
46+
47+
2348
class APIClient(BaseAPIClient, metaclass=Singleton):
2449
_API_NAME = "CellEngine Python Toolkit"
2550

@@ -119,6 +144,69 @@ def update_entity(self, experiment_id, _id, entity_type, body) -> dict:
119144
json=body,
120145
)
121146

147+
def _get_path(self, entity: CE) -> str:
148+
fullpath = f"{self.base_url}/{entity.path}"
149+
return fullpath
150+
151+
def post_and_structure(self, _class, path, body, **kwargs):
152+
res = self._post(f"{self.base_url}/{path}", json=body, params=kwargs)
153+
return converter.structure(res, _class)
154+
155+
def unstructure_and_clean(self, entity):
156+
(cls, path, body) = (
157+
entity.__class__,
158+
entity.path,
159+
converter.unstructure(entity),
160+
)
161+
if body["_id"] == "None" or body["_id"] is None:
162+
del body["_id"] # https://github.com/primitybio/cellengine/issues/5800
163+
return (cls, path, body)
164+
165+
# fmt: off
166+
# temporary fix for https://github.com/psf/black/issues/1797
167+
@overload
168+
def create(self, entity: Attachment, **kwargs) -> Attachment: ...
169+
@overload
170+
def create(self, entity: Compensation, **kwargs) -> Compensation: ...
171+
@overload
172+
def create(self, entity: Experiment, **kwargs) -> Experiment: ...
173+
@overload
174+
def create(self, entity: FcsFile, **kwargs) -> FcsFile: ...
175+
@overload
176+
def create(self, entity: Gate, **kwargs) -> Gate: ...
177+
@overload
178+
def create(self, entity: Population, **kwargs) -> Population: ...
179+
@overload
180+
def create(self, entity: ScaleSet, **kwargs) -> ScaleSet: ...
181+
# fmt: on
182+
183+
def create(
184+
self, entity, **kwargs
185+
) -> Union[
186+
Attachment,
187+
Compensation,
188+
Experiment,
189+
FcsFile,
190+
Gate,
191+
Population,
192+
ScaleSet,
193+
]:
194+
"""Create a local entity on CellEngine."""
195+
if isinstance(entity, list):
196+
return create_many(self, entity, **kwargs)
197+
body = self.unstructure_and_clean(entity)
198+
return self.post_and_structure(*body)
199+
200+
def update(self, entity, params: Dict = None):
201+
path = self._get_path(entity)
202+
data = converter.unstructure(entity)
203+
res = self._patch(path, json=data, params=params)
204+
return converter.structure(res, entity.__class__)
205+
206+
def delete(self, entity, params: Dict = None) -> None:
207+
path = self._get_path(entity)
208+
self._delete(path, params=params)
209+
122210
def delete_entity(self, experiment_id, entity_type, _id):
123211
url = f"{self.base_url}/experiments/{experiment_id}/{entity_type}/{_id}"
124212
self._delete(url)

0 commit comments

Comments
 (0)