33from __future__ import annotations
44
55import asyncio
6- import functools
76import inspect
87import json
98import logging
1312from typing import Any , Callable , Dict , Union , Optional , List , Sequence , Set
1413import warnings
1514
15+ from pylabrobot .machine import MachineFrontend , need_setup_finished
1616from pylabrobot .liquid_handling .strictness import Strictness , get_strictness
1717from pylabrobot .plate_reading import PlateReader
1818from pylabrobot .resources import (
5252logger = logging .getLogger ("pylabrobot" )
5353
5454
55- def need_setup_finished (func : Callable ): # pylint: disable=no-self-argument
56- """ Decorator for methods that require the liquid handler to be set up.
57-
58- Checked by verifying `self.setup_finished` is `True`.
59-
60- Raises:
61- RuntimeError: If the liquid handler is not set up.
62- """
63-
64- @functools .wraps (func )
65- async def wrapper (self , * args , ** kwargs ):
66- if not self .setup_finished :
67- raise RuntimeError ("The setup has not finished. See `LiquidHandler.setup`." )
68- await func (self , * args , ** kwargs ) # pylint: disable=not-callable
69- return wrapper
70-
71-
72- class LiquidHandler :
55+ class LiquidHandler (MachineFrontend ):
7356 """
7457 Front end for liquid handlers.
7558
7659 This class is the front end for liquid handlers; it provides a high-level interface for
7760 interacting with liquid handlers. In the background, this class uses the low-level backend (
7861 defined in `pyhamilton.liquid_handling.backends`) to communicate with the liquid handler.
79-
80- Attributes:
81- setup_finished: Whether the liquid handler has been setup.
8262 """
8363
8464 def __init__ (self , backend : LiquidHandlerBackend , deck : Deck ):
@@ -89,8 +69,9 @@ def __init__(self, backend: LiquidHandlerBackend, deck: Deck):
8969 deck: Deck to use.
9070 """
9171
92- self .backend = backend
93- self .setup_finished = False
72+ super ().__init__ (backend = backend )
73+
74+ self .backend : LiquidHandlerBackend = backend
9475 self ._picked_up_tips96 : Optional [TipRack ] = None # TODO: replace with tracker.
9576
9677 self .deck = deck
@@ -99,21 +80,23 @@ def __init__(self, backend: LiquidHandlerBackend, deck: Deck):
9980
10081 self .head : Dict [int , TipTracker ] = {}
10182
83+
10284 async def setup (self ):
10385 """ Prepare the robot for use. """
10486
10587 if self .setup_finished :
10688 raise RuntimeError ("The setup has already finished. See `LiquidHandler.stop`." )
10789
10890 await self .backend .setup ()
109- self .setup_finished = True
11091
11192 self .head = {c : TipTracker () for c in range (self .backend .num_channels )}
11293
11394 self .resource_assigned_callback (self .deck )
11495 for resource in self .deck .children :
11596 self .resource_assigned_callback (resource )
11697
98+ super ().setup ()
99+
117100 def update_head_state (self , state : Dict [int , Optional [Tip ]]):
118101 """ Update the state of the liquid handler head.
119102
@@ -139,10 +122,6 @@ def clear_head_state(self):
139122
140123 self .update_head_state ({c : None for c in self .head .keys ()})
141124
142- async def stop (self ):
143- await self .backend .stop ()
144- self .setup_finished = False
145-
146125 def _run_async_in_thread (self , func , * args , ** kwargs ):
147126 def callback (* args , ** kwargs ):
148127 loop = asyncio .new_event_loop ()
0 commit comments