Skip to content

Commit e73520a

Browse files
Implement on_underflow in worklist transfer methods
1 parent 789216f commit e73520a

File tree

4 files changed

+54
-2
lines changed

4 files changed

+54
-2
lines changed

robotools/evotools/test_worklist.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
from robotools.evotools import EvoWorklist, Labwares
55
from robotools.evotools.types import Tip
6+
from robotools.liquidhandling.exceptions import (
7+
VolumeUnderflowError,
8+
VolumeUnderflowWarning,
9+
)
610
from robotools.liquidhandling.labware import Labware, Trough
711
from robotools.worklists.exceptions import InvalidOperationError
812

@@ -589,6 +593,19 @@ def test_history_condensation_within_labware(self) -> None:
589593
)
590594
return
591595

596+
def test_transfer_on_underflow(self):
597+
A = Labware("A", 3, 2, min_volume=100, max_volume=2000, initial_volumes=500)
598+
with EvoWorklist() as wl:
599+
wl.transfer(A, "A01", A, "A02", 600, on_underflow="debug")
600+
assert A.volumes[0, 0] == 100
601+
assert A.volumes[0, 1] == 1100
602+
with pytest.warns(VolumeUnderflowWarning, match="500.0 - 600.0 < 100"):
603+
wl.transfer(A, "B01", A, "B02", 600, on_underflow="warn")
604+
assert A.volumes[1, 0] == 100
605+
assert A.volumes[1, 1] == 1100
606+
with pytest.raises(VolumeUnderflowError, match="500.0 - 600.0 < 100"):
607+
wl.transfer(A, "C01", A, "C02", 600, on_underflow="raise")
608+
592609

593610
class TestTroughLabwareWorklist:
594611
def test_aspirate(self) -> None:

robotools/evotools/worklist.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ def transfer(
230230
label: Optional[str] = None,
231231
wash_scheme: Literal[1, 2, 3, 4, "flush", "reuse"] = 1,
232232
partition_by: str = "auto",
233+
on_underflow: Literal["debug", "warn", "raise"] = "raise",
233234
**kwargs,
234235
) -> None:
235236
"""Transfer operation between two labwares.
@@ -260,6 +261,14 @@ def transfer(
260261
'auto': partitioning by source unless the source is a Trough
261262
'source': partitioning by source columns
262263
'destination': partitioning by destination columns
264+
on_underflow
265+
What to do about volume underflows (going below ``vmin``) in non-empty wells.
266+
267+
Options:
268+
269+
- ``"debug"`` mentions the underflowing wells in a log message at DEBUG level.
270+
- ``"warn"`` emits an :class:`~robotools.liquidhandling.exceptions.VolumeUnderflowWarning`. This `can be captured in unit tests <https://docs.pytest.org/en/stable/how-to/capture-warnings.html#additional-use-cases-of-warnings-in-tests>`_.
271+
- ``"raise"`` raises a :class:`~robotools.liquidhandling.exceptions.VolumeUnderflowError` about underflowing wells.
263272
kwargs
264273
Additional keyword arguments to pass to aspirate and dispense.
265274
Most prominent example: `liquid_class`.
@@ -317,7 +326,7 @@ def transfer(
317326
if len(vs) > p:
318327
v = vs[p]
319328
if v > 0:
320-
self.aspirate(source, s, v, label=None, **kwargs)
329+
self.aspirate(source, s, v, label=None, on_underflow=on_underflow, **kwargs)
321330
self.dispense(
322331
destination,
323332
d,

robotools/fluenttools/test_worklist.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import pytest
22

33
from robotools.fluenttools.worklist import FluentWorklist
4+
from robotools.liquidhandling.exceptions import (
5+
VolumeUnderflowError,
6+
VolumeUnderflowWarning,
7+
)
48
from robotools.liquidhandling.labware import Labware
59

610

@@ -42,3 +46,16 @@ def test_transfer_flush(self):
4246
assert len(wl) == 3
4347
assert wl[-1] == "F;"
4448
pass
49+
50+
def test_transfer_on_underflow(self):
51+
A = Labware("A", 3, 2, min_volume=100, max_volume=2000, initial_volumes=500)
52+
with FluentWorklist() as wl:
53+
wl.transfer(A, "A01", A, "A02", 600, on_underflow="debug")
54+
assert A.volumes[0, 0] == 100
55+
assert A.volumes[0, 1] == 1100
56+
with pytest.warns(VolumeUnderflowWarning, match="500.0 - 600.0 < 100"):
57+
wl.transfer(A, "B01", A, "B02", 600, on_underflow="warn")
58+
assert A.volumes[1, 0] == 100
59+
assert A.volumes[1, 1] == 1100
60+
with pytest.raises(VolumeUnderflowError, match="500.0 - 600.0 < 100"):
61+
wl.transfer(A, "C01", A, "C02", 600, on_underflow="raise")

robotools/fluenttools/worklist.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def transfer(
4343
label: Optional[str] = None,
4444
wash_scheme: Literal[1, 2, 3, 4, "flush", "reuse"] = 1,
4545
partition_by: str = "auto",
46+
on_underflow: Literal["debug", "warn", "raise"] = "raise",
4647
**kwargs,
4748
) -> None:
4849
"""Transfer operation between two labwares.
@@ -73,6 +74,14 @@ def transfer(
7374
'auto': partitioning by source unless the source is a Trough
7475
'source': partitioning by source columns
7576
'destination': partitioning by destination columns
77+
on_underflow
78+
What to do about volume underflows (going below ``vmin``) in non-empty wells.
79+
80+
Options:
81+
82+
- ``"debug"`` mentions the underflowing wells in a log message at DEBUG level.
83+
- ``"warn"`` emits an :class:`~robotools.liquidhandling.exceptions.VolumeUnderflowWarning`. This `can be captured in unit tests <https://docs.pytest.org/en/stable/how-to/capture-warnings.html#additional-use-cases-of-warnings-in-tests>`_.
84+
- ``"raise"`` raises a :class:`~robotools.liquidhandling.exceptions.VolumeUnderflowError` about underflowing wells.
7685
kwargs
7786
Additional keyword arguments to pass to aspirate and dispense.
7887
Most prominent example: `liquid_class`.
@@ -127,7 +136,7 @@ def transfer(
127136
if len(vs) > p:
128137
v = vs[p]
129138
if v > 0:
130-
self.aspirate(source, s, v, label=None, **kwargs)
139+
self.aspirate(source, s, v, label=None, on_underflow=on_underflow, **kwargs)
131140
self.dispense(
132141
destination,
133142
d,

0 commit comments

Comments
 (0)