Skip to content

Commit 911640b

Browse files
committed
src(population): Use attrs + cattrs
1 parent 11bf3c4 commit 911640b

File tree

3 files changed

+48
-31
lines changed

3 files changed

+48
-31
lines changed

cellengine/resources/population.py

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,46 @@
11
from __future__ import annotations
2-
from dataclasses import field
3-
from typing import Optional
2+
from typing import Dict, Optional
3+
from attr import define, field
44

5-
from dataclasses_json.cfg import config
6-
from cellengine.utils.dataclass_mixin import DataClassMixin, ReadOnly
7-
8-
from dataclasses import dataclass
95
import cellengine as ce
6+
from cellengine.utils import converter
7+
from cellengine.utils.readonly import readonly
108

119

12-
@dataclass
13-
class Population(DataClassMixin):
10+
@define
11+
class Population:
12+
_id: str = field(on_setattr=readonly)
13+
experiment_id: str = field(on_setattr=readonly)
1414
name: str
1515
gates: str
16+
unique_name: Optional[str] = field(default=None, on_setattr=readonly)
1617
parent_id: Optional[str] = None
1718
terminal_gate_gid: Optional[str] = None
18-
_id: str = field(
19-
metadata=config(field_name="_id"), default=ReadOnly()
20-
) # type: ignore
21-
experiment_id: str = field(default=ReadOnly()) # type: ignore
22-
unique_name: str = field(default=ReadOnly()) # type: ignore
2319

2420
def __repr__(self):
2521
return f"Population(_id='{self._id}', name='{self.name}')"
2622

27-
@classmethod
28-
def get(cls, experiment_id: str, _id: str = None, name: str = None):
29-
kwargs = {"name": name} if name else {"_id": _id}
30-
return ce.APIClient().get_population(experiment_id, **kwargs)
23+
@property
24+
def client(self):
25+
return ce.APIClient()
26+
27+
@property
28+
def path(self):
29+
return f"experiments/{self.experiment_id}/populations/{self._id}".rstrip(
30+
"/None"
31+
)
3132

3233
@classmethod
33-
def create(cls, experiment_id: str, population: dict) -> Population:
34-
return ce.APIClient().post_population(experiment_id, population)
34+
def from_dict(cls, data: Dict):
35+
return converter.structure(data, cls)
36+
37+
def to_dict(self) -> Dict:
38+
return converter.unstructure(self)
3539

3640
def update(self):
3741
"""Save changes to this Population to CellEngine."""
38-
res = ce.APIClient().update_entity(
39-
self.experiment_id, self._id, "populations", self.to_dict()
40-
)
41-
self.__dict__.update(Population.from_dict(res).__dict__)
42+
res = self.client.update(self)
43+
self.__setstate__(res.__getstate__()) # type: ignore
4244

4345
def delete(self):
44-
ce.APIClient().delete_entity(self.experiment_id, "populations", self._id)
46+
self.client.delete_entity(self.experiment_id, "populations", self._id)

tests/fixtures/api-populations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pytest
22

33

4-
@pytest.fixture(scope="session")
4+
@pytest.fixture(scope="function")
55
def populations():
66
populations = [
77
{

tests/unit/resources/test_population.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
EXP_ID = "5d38a6f79fae87499999a74b"
99

1010

11-
@pytest.fixture(scope="module")
11+
@pytest.fixture(scope="function")
1212
def population(client, populations):
13-
return Population.from_dict(populations[0])
13+
pop = populations[0]
14+
if "uniqueName" in pop.keys():
15+
pop.pop("uniqueName")
16+
return Population.from_dict(pop)
1417

1518

1619
def population_tester(population):
@@ -28,25 +31,37 @@ def population_tester(population):
2831

2932

3033
@responses.activate
31-
def test_should_get_population(ENDPOINT_BASE, population, populations):
34+
def test_should_get_population(client, ENDPOINT_BASE, population, populations):
3235
responses.add(
3336
responses.GET,
3437
ENDPOINT_BASE + f"/experiments/{EXP_ID}/populations/{population._id}",
3538
json=populations[0],
3639
)
37-
pop = Population.get(EXP_ID, population._id)
40+
pop = client.get_population(EXP_ID, population._id)
41+
assert pop.unique_name is None
3842
population_tester(pop)
3943

4044

4145
@responses.activate
42-
def test_should_post_population(ENDPOINT_BASE, population, populations):
46+
def test_get_populations_returns_unique_name(client, ENDPOINT_BASE, populations):
47+
responses.add(
48+
responses.GET,
49+
ENDPOINT_BASE + f"/experiments/{EXP_ID}/populations",
50+
json=populations,
51+
)
52+
pops = client.get_populations(EXP_ID)
53+
assert all([pop.unique_name for pop in pops])
54+
55+
56+
@responses.activate
57+
def test_should_post_population(client, ENDPOINT_BASE, population, populations):
4358
responses.add(
4459
responses.POST,
4560
ENDPOINT_BASE + f"/experiments/{EXP_ID}/populations",
4661
json=populations[0],
4762
)
4863
payload = populations[0].copy()
49-
pop = Population.create(EXP_ID, payload)
64+
pop = client.post_population(EXP_ID, payload)
5065
population_tester(pop)
5166

5267

0 commit comments

Comments
 (0)