I appreciate this feedback. I really aim to make things better.
I will say I fundamentally believe standardization follows implementation. Specifically because of discussions like these. We have an implementation, people use it, it’s not perfect, we update it based on new information, and ultimately we converge. I am sorry we can’t provide a finalized description right now.
I would argue that there is more complexity.
Taking “plates should only take wells” as an example. Yes, they should. This is implemented through the generic type ItemizedResource
: Plate
actually inherits from ItemizedResource[Well]
, which means the type checker will raise an error if you initialize it with items other than a Well.
This is a form of documentation, loosely enforced by the type checker. Runtime type checking is not typical or recommended in Python, because it adds a lot of code (two lines per type check at least: if not isinstance(r, Well):\n raise error
). Instead, the convention is to let it happen until some error occurs. If the user uses the API as documented (following type hints) we promise it will work and no error should occur (this is what the type checker enforces), otherwise the user is in control. We shouldn’t really care if the user wants to do experimental stuff.
And you’re right, we should document and formalize these rules more. Documentation has not always been a priority, but is becoming one now (I made a first step by redesigning the docs website for extensibility last week: new docs theme by rickwierenga · Pull Request #249 · PyLabRobot/pylabrobot · GitHub). Incidentally, Plate is one of the resources that has some documentation: Plates — PyLabRobot documentation, and we actually do say that the children will be Well
s. But point taken.
The ‘strict rules’ as we will document them will simply be loosely enforced in the Python implementation, as is customary for Python implementations.
As for strictness checking in LiquidHandler, strictness checking makes the code more complicated. Because of it, we have to look at backend kwargs, do a set difference, potentially raise errors, etc. It only exists to facilitate flexible backends and help users write robot agnostic protocols.
Agree we need ‘unambiguous, well documented, fixed answers’.
The PLR resource model is still being developed, @CamilloMoschner has made great contributions here. The z coordinate of tip spots has not been iterated since my initial implementation*, and so I’m happy to discuss a new definition and changing it. Do you want to make a separate thread for it?
*my initial implementation attempted to stay close to venus. We are moving away from that because venus made some very bad decisions. Some things in PLR do not have good rationales behind right now.
Thank you for clearly stating this. Truly important feedback. We will improve.
It’s not. But why bother checking? No one will do it, so we just ignore it.
Yes
Speaking for Camillo, I think he is referring to “tip rack → tips pot → tip” is physical reality, and so is “plate → well”, but not "“plate → ‘well holder’ → well”. I would agree with Camillo that 2 or three layers stay closer to physical reality.
In the visualizer, I visualize tip spots and wells. Tip spots are separate objects (they have their own class), which change their appearance based on whether they have a tip assigned.
Probably. Made a separate post to discuss: Can we make Tips a Container resource?
I don’t think it has to. But it does require using a tree as the fundamental data structure of the layout (which really is a core assumption) and nodes/classes in this tree to refine basic Resource behavior. Each node needs to handle their ‘local’ responsibility (eg Plates should manage returning Wells, but Plates should not manage the liquids in those wells (that is the job of Well))