Skip to content

Commit 52c354f

Browse files
committed
bug(fcsfile): fix recursion when file has no spill string
1 parent 47dcff1 commit 52c354f

File tree

2 files changed

+45
-7
lines changed

2 files changed

+45
-7
lines changed

cellengine/resources/fcs_file.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class FcsFile(DataClassMixin):
3535
sample_name: Optional[str] = field(default=ReadOnly(optional=True)) # type: ignore
3636
size: int = field(default=ReadOnly()) # type: ignore
3737
_spill_string: Optional[str] = field(
38-
metadata=config(field_name="spillString"), default=None
38+
metadata=config(field_name="spillString"),
39+
default=None,
3940
)
4041

4142
def __repr__(self):
@@ -197,6 +198,10 @@ def plot(
197198

198199
def get_file_internal_compensation(self) -> Compensation:
199200
"""Get the file-internal Compensation."""
201+
if not self.has_file_internal_comp or self._spill_string == "":
202+
raise ValueError(
203+
f"FCS File '{self._id}' does not have an internal compensation."
204+
)
200205
return Compensation.from_spill_string(self.spill_string)
201206

202207
@property
@@ -225,10 +230,16 @@ def events(self, events):
225230
def spill_string(self):
226231
if self._spill_string:
227232
return self._spill_string
233+
elif self.has_file_internal_comp:
234+
self._spill_string = (
235+
ce.APIClient().get_fcs_file(self.experiment_id, self._id, as_dict=True)[
236+
"spillString"
237+
]
238+
or ""
239+
) # type: ignore
228240
else:
229-
ss = ce.APIClient().get_fcs_file(self.experiment_id, self._id).spill_string
230-
self._spill_string = ss
231-
return ss
241+
self._spill_string = ""
242+
return self._spill_string
232243

233244
def get_events(
234245
self, inplace: bool = False, destination=None, **kwargs

tests/unit/resources/test_fcsfile.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import os
1+
from io import BufferedReader, BytesIO
22
import json
3+
import os
4+
35
from fcsparser.api import FCSParser
46
from pandas.core.frame import DataFrame
7+
import pytest
58
import responses
6-
from io import BufferedReader, BytesIO
79

8-
from cellengine.resources.fcs_file import FcsFile
910
from cellengine.resources.compensation import Compensation
11+
from cellengine.resources.fcs_file import FcsFile
1012

1113

1214
EXP_ID = "5d38a6f79fae87499999a74b"
@@ -79,6 +81,31 @@ def test_gets_file_internal_compensation(ENDPOINT_BASE, client, fcs_files, spill
7981
assert type(comp) == Compensation
8082

8183

84+
@responses.activate
85+
def test_throws_correct_error_when_no_file_internal_compensation(
86+
ENDPOINT_BASE, client, fcs_files
87+
):
88+
# Given: An FcsFile with no spill string
89+
file_data = fcs_files[0]
90+
file_data["spillString"] = ""
91+
file = FcsFile.from_dict(file_data)
92+
expected_response = fcs_files[0].copy()
93+
responses.add(
94+
responses.GET,
95+
f"{ENDPOINT_BASE}/experiments/{EXP_ID}/fcsfiles/{file._id}",
96+
json=expected_response,
97+
)
98+
99+
# When:
100+
with pytest.raises(ValueError) as err:
101+
comp = file.get_file_internal_compensation()
102+
# Then:
103+
assert (
104+
err.value.args[0]
105+
== f"FCS File '{file._id}' does not have an internal compensation."
106+
)
107+
108+
82109
def test_parse_fcs_file():
83110
events_body = open("tests/data/Acea - Novocyte.fcs", "rb")
84111
parser = FCSParser.from_data(events_body.read())

0 commit comments

Comments
 (0)