cgevans / mixes

BSD 3-Clause "New" or "Revised" License
0 stars 1 forks source link

generalized `LabStep` #26

Open dave-doty opened 1 year ago

dave-doty commented 1 year ago

Create a notion of a generalize "lab step", which is just an object with an instructions method that can be called to get Markdown describing the lab step (much like Mix.instructions currently), or a string (in which case the string itself is the Markdown, used for "manually" describing lab steps).

An Experiment can have a list of LabStep's, and it can also have an instructions method that simply iterates over each LabStep, calling instructions on each (checking whether it's just a string also).

This could be done with an explicit abstract superclass that has an abstract method instructions.

A simpler way (given Python's type system) that would still allow mypy to type is to use the typing.Protocol class to say that LabStep is a type alias for str | LabStepObject, where LabStepObject is used to define the type signature of the instructions method (e.g., takes a tablefmt parameter for any tables that appear in the instructions), e.g.

from typing import Protocol, TypeAlias
from tabulate import TableFormat

class LabStepObject(Protocol):
    def instructions(self, tablefmt: str | TableFormat, ...):
        ...

LabStep: TypeAlias = str | LabStepObject

It's not obvious what the type signature of instructions should be. Currently for Mix it's a mish-mash of stuff that happens to be relevant for making mixes, and much of it would be irrelevant for, for example, specifying which samples go to which gel lanes (see #21, idea 3). So we want to brainstorm how to redesign the type signature to simplify implementing new lab steps. Perhaps some of those parameters can become fields in the object instead, so that they are specific to that type of lab step. (For example, all the stuff related to plates could be fields in Mix since a Mix might deal with plates, but it wouldn't make sense for anything about plates to be specified for a LabStep that tracks samples in gel lanes.)

One way to do this is make a Preferences class, which contains all the "preferences" for every situation we encounter (whether to combine plate actions, use well markers, tablefmt, etc.), and most LabStep objects ignore most of the fields in Preferences, and use only the fields relevant to their situation. For this to be usable, all of the fields should be optional and have a default value, which in many cases will simply be ignored.