|
1 | 1 | from __future__ import annotations
|
2 |
| -import os |
| 2 | +from collections import defaultdict |
| 3 | +from functools import lru_cache |
| 4 | +from getpass import getpass |
3 | 5 | import json
|
| 6 | +import os |
| 7 | +from typing import Any, Dict, List, Optional, TypeVar, Union, overload |
| 8 | + |
4 | 9 | import pandas
|
5 |
| -from getpass import getpass |
6 |
| -from typing import Any, Dict, List, Union, Optional |
7 |
| -from functools import lru_cache |
8 | 10 | from requests_toolbelt.multipart.encoder import MultipartEncoder
|
9 | 11 |
|
10 |
| -from cellengine.utils.api_client.BaseAPIClient import BaseAPIClient |
| 12 | +from cellengine.utils import converter |
11 | 13 | from cellengine.utils.api_client.APIError import APIError
|
| 14 | +from cellengine.utils.api_client.BaseAPIClient import BaseAPIClient |
12 | 15 | from cellengine.utils.singleton import Singleton
|
| 16 | + |
13 | 17 | from ...resources.attachment import Attachment
|
14 | 18 | from ...resources.compensation import Compensation
|
15 | 19 | from ...resources.experiment import Experiment
|
|
20 | 24 | from ...resources.scaleset import ScaleSet
|
21 | 25 |
|
22 | 26 |
|
| 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 | + |
23 | 49 | class APIClient(BaseAPIClient, metaclass=Singleton):
|
24 | 50 | _API_NAME = "CellEngine Python Toolkit"
|
25 | 51 |
|
@@ -119,6 +145,69 @@ def update_entity(self, experiment_id, _id, entity_type, body) -> dict:
|
119 | 145 | json=body,
|
120 | 146 | )
|
121 | 147 |
|
| 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 | + |
122 | 211 | def delete_entity(self, experiment_id, entity_type, _id):
|
123 | 212 | url = f"{self.base_url}/experiments/{experiment_id}/{entity_type}/{_id}"
|
124 | 213 | self._delete(url)
|
|
0 commit comments