Skip to content

Commit 8579276

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

File tree

3 files changed

+96
-7
lines changed

3 files changed

+96
-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: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
from __future__ import annotations
2-
import os
2+
from collections import defaultdict
3+
from functools import lru_cache
4+
from getpass import getpass
35
import json
6+
import os
7+
from typing import Any, Dict, List, Optional, TypeVar, Union, overload
8+
49
import pandas
5-
from getpass import getpass
6-
from typing import Any, Dict, List, Union, Optional
7-
from functools import lru_cache
810
from requests_toolbelt.multipart.encoder import MultipartEncoder
911

10-
from cellengine.utils.api_client.BaseAPIClient import BaseAPIClient
12+
from cellengine.utils import converter
1113
from cellengine.utils.api_client.APIError import APIError
14+
from cellengine.utils.api_client.BaseAPIClient import BaseAPIClient
1215
from cellengine.utils.singleton import Singleton
16+
1317
from ...resources.attachment import Attachment
1418
from ...resources.compensation import Compensation
1519
from ...resources.experiment import Experiment
@@ -20,6 +24,28 @@
2024
from ...resources.scaleset import ScaleSet
2125

2226

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

@@ -119,6 +145,69 @@ def update_entity(self, experiment_id, _id, entity_type, body) -> dict:
119145
json=body,
120146
)
121147

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

0 commit comments

Comments
 (0)