Skip to content

Commit

Permalink
Python 3.11 compatibility and Pint typing fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
cgevans committed Nov 1, 2022
1 parent 07f28ed commit b8dc004
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 113 deletions.
4 changes: 2 additions & 2 deletions setup.cfg
Expand Up @@ -27,11 +27,11 @@ package_dir =
=src
packages = find_namespace:
install_requires =
attrs
attrs >= 22.1
numpy
pandas
openpyxl
pint >= 0.19.2
pint >= 0.20
tabulate
toml
typing_extensions >= 4.2
Expand Down
98 changes: 49 additions & 49 deletions src/alhambra_mixes/actions.py
Expand Up @@ -43,9 +43,9 @@ def name(self) -> str: # pragma: no cover

def tx_volume(
self,
mix_vol: Quantity[Decimal] = Q_(DNAN, uL),
mix_vol: DecimalQuantity = Q_(DNAN, uL),
actions: Sequence[AbstractAction] = tuple(),
) -> Quantity[Decimal]: # pragma: no cover
) -> DecimalQuantity: # pragma: no cover
"""The total volume transferred by the action to the sample. May depend on the total mix volume.
Parameters
Expand All @@ -60,14 +60,14 @@ def tx_volume(
def _mixlines(
self,
tablefmt: str | TableFormat,
mix_vol: Quantity[Decimal],
mix_vol: DecimalQuantity,
actions: Sequence[AbstractAction] = tuple(),
) -> Sequence[MixLine]: # pragma: no cover
...

@abstractmethod
def all_components(
self, mix_vol: Quantity[Decimal], actions: Sequence[AbstractAction] = tuple()
self, mix_vol: DecimalQuantity, actions: Sequence[AbstractAction] = tuple()
) -> pd.DataFrame: # pragma: no cover
"""A dataframe containing all base components added by the action.
Expand All @@ -94,8 +94,8 @@ def with_reference(
...

def dest_concentration(
self, mix_vol: Quantity, actions: Sequence[AbstractAction] = tuple()
) -> Quantity:
self, mix_vol: DecimalQuantity, actions: Sequence[AbstractAction] = tuple()
) -> DecimalQuantity:
"""The destination concentration added to the mix by the action.
Raises
Expand All @@ -108,8 +108,8 @@ def dest_concentration(
raise ValueError("Single destination concentration not defined.")

def dest_concentrations(
self, mix_vol: Quantity, actions: Sequence[AbstractAction] = tuple()
) -> Sequence[Quantity[Decimal]]:
self, mix_vol: DecimalQuantity, actions: Sequence[AbstractAction] = tuple()
) -> Sequence[DecimalQuantity]:
raise ValueError

@property
Expand All @@ -120,9 +120,9 @@ def components(self) -> list[AbstractComponent]:
@abstractmethod
def each_volumes(
self,
total_volume: Quantity[Decimal],
total_volume: DecimalQuantity,
actions: Sequence[AbstractAction] = tuple(),
) -> list[Quantity[Decimal]]:
) -> list[DecimalQuantity]:
...

@classmethod
Expand Down Expand Up @@ -161,7 +161,7 @@ def __eq__(self, other: Any) -> bool:
for a in self.__attrs_attrs__: # type: Attribute
v1 = getattr(self, a.name)
v2 = getattr(other, a.name)
if isinstance(v1, Quantity):
if isinstance(v1, ureg.Quantity):
if isnan(v1.m) and isnan(v2.m) and (v1.units == v2.units):
continue
if v1 != v2:
Expand Down Expand Up @@ -198,7 +198,7 @@ def with_reference(
)

@property
def source_concentrations(self) -> list[Quantity[Decimal]]:
def source_concentrations(self) -> list[DecimalQuantity]:
concs = [c.concentration for c in self.components]
return concs

Expand All @@ -213,7 +213,7 @@ def _unstructure(self, experiment: "Experiment" | None) -> dict[str, Any]:
if val is a.default:
continue
# FIXME: nan quantities are always default, and pint handles them poorly
if isinstance(val, Quantity) and isnan(val.m):
if isinstance(val, ureg.Quantity) and isnan(val.m):
continue
d[a.name] = _unstructure(val)
return d
Expand All @@ -240,7 +240,7 @@ def _structure(
return cls(**d)

def all_components(
self, mix_vol: Quantity[Decimal], actions: Sequence[AbstractAction] = tuple()
self, mix_vol: DecimalQuantity, actions: Sequence[AbstractAction] = tuple()
) -> pd.DataFrame:
newdf = _empty_components()

Expand All @@ -265,8 +265,8 @@ def all_components(
def _compactstrs(
self,
tablefmt: str | TableFormat,
dconcs: Sequence[Quantity[Decimal]],
eavols: Sequence[Quantity[Decimal]],
dconcs: Sequence[DecimalQuantity],
eavols: Sequence[DecimalQuantity],
) -> Sequence[MixLine]:
# locs = [(c.name,) + c.location for c in self.components]
# names = [c.name for c in self.components]
Expand Down Expand Up @@ -294,18 +294,18 @@ def _compactstrs(
)

names: list[list[str]] = []
source_concs: list[Quantity[Decimal]] = []
dest_concs: list[Quantity[Decimal]] = []
source_concs: list[DecimalQuantity] = []
dest_concs: list[DecimalQuantity] = []
numbers: list[int] = []
ea_vols: list[Quantity[Decimal]] = []
tot_vols: list[Quantity[Decimal]] = []
ea_vols: list[DecimalQuantity] = []
tot_vols: list[DecimalQuantity] = []
plates: list[str] = []
wells_list: list[list[WellPos]] = []

for plate, plate_comps in locdf.groupby("plate"): # type: str, pd.DataFrame
for vol, plate_vol_comps in plate_comps.groupby(
"ea_vols"
): # type: Quantity[Decimal], pd.DataFrame
): # type: DecimalQuantity, pd.DataFrame
if pd.isna(plate_vol_comps["well"].iloc[0]):
if not pd.isna(plate_vol_comps["well"]).all():
raise ValueError
Expand Down Expand Up @@ -408,7 +408,7 @@ class FixedVolume(ActionWithComponents):
| c1, c2, c3 | 200.00 nM | 66.67 nM | 3 | 5.00 µl | 15.00 µl | | |
"""

fixed_volume: Quantity[Decimal] = attrs.field(
fixed_volume: DecimalQuantity = attrs.field(
converter=_parse_vol_required, on_setattr=attrs.setters.convert
)
set_name: str | None = None
Expand All @@ -429,9 +429,9 @@ def __new__(cls, *args, **kwargs):

def dest_concentrations(
self,
mix_vol: Quantity[Decimal] = Q_(DNAN, uL),
mix_vol: DecimalQuantity = Q_(DNAN, uL),
actions: Sequence[AbstractAction] = tuple(),
) -> list[Quantity[Decimal]]:
) -> list[DecimalQuantity]:
return [
x * y
for x, y in zip(
Expand All @@ -441,9 +441,9 @@ def dest_concentrations(

def each_volumes(
self,
mix_vol: Quantity[Decimal] = Q_(DNAN, uL),
mix_vol: DecimalQuantity = Q_(DNAN, uL),
actions: Sequence[AbstractAction] = tuple(),
) -> list[Quantity[Decimal]]:
) -> list[DecimalQuantity]:
return [self.fixed_volume.to(uL)] * len(self.components)

@property
Expand All @@ -456,7 +456,7 @@ def name(self) -> str:
def _mixlines(
self,
tablefmt: str | TableFormat,
mix_vol: Quantity[Decimal],
mix_vol: DecimalQuantity,
actions: Sequence[AbstractAction] = tuple(),
) -> list[MixLine]:
dconcs = self.dest_concentrations(mix_vol)
Expand Down Expand Up @@ -549,7 +549,7 @@ class EqualConcentration(FixedVolume):
def __init__(
self,
components: Sequence[AbstractComponent | str] | AbstractComponent | str,
fixed_volume: str | Quantity,
fixed_volume: str | DecimalQuantity,
set_name: str | None = None,
compact_display: bool = True,
method: Literal["max_volume", "min_volume", "check"]
Expand All @@ -576,17 +576,17 @@ def __init__(
] = "min_volume"

@property
def source_concentrations(self) -> List[Quantity[Decimal]]:
def source_concentrations(self) -> List[DecimalQuantity]:
concs = super().source_concentrations
if any(x != concs[0] for x in concs) and (self.method == "check"):
raise ValueError("Not all components have equal concentration.")
return concs

def each_volumes(
self,
mix_vol: Quantity[Decimal] = Q_(DNAN, uL),
mix_vol: DecimalQuantity = Q_(DNAN, uL),
actions: Sequence[AbstractAction] = tuple(),
) -> list[Quantity[Decimal]]:
) -> list[DecimalQuantity]:
# match self.equal_conc:
if self.method == "min_volume":
sc = self.source_concentrations
Expand All @@ -607,17 +607,17 @@ def each_volumes(

def tx_volume(
self,
mix_vol: Quantity[Decimal] = Q_(DNAN, uL),
mix_vol: DecimalQuantity = Q_(DNAN, uL),
actions: Sequence[AbstractAction] = tuple(),
) -> Quantity[Decimal]:
) -> DecimalQuantity:
if isinstance(self.method, Sequence) and (self.method[0] == "max_fill"):
return self.fixed_volume * len(self.components)
return sum(self.each_volumes(mix_vol), ureg("0.0 uL"))

def _mixlines(
self,
tablefmt: str | TableFormat,
mix_vol: Quantity[Decimal],
mix_vol: DecimalQuantity,
actions: Sequence[AbstractAction] = tuple(),
) -> list[MixLine]:
ml = super()._mixlines(tablefmt, mix_vol)
Expand Down Expand Up @@ -682,29 +682,29 @@ class FixedConcentration(ActionWithComponents):
| *Total:* | | 40.00 nM | | | 25.00 µl | | |
"""

fixed_concentration: Quantity[Decimal] = attrs.field(
fixed_concentration: DecimalQuantity = attrs.field(
converter=_parse_conc_required, on_setattr=attrs.setters.convert
)
set_name: str | None = None
compact_display: bool = True
min_volume: Quantity[Decimal] = attrs.field(
min_volume: DecimalQuantity = attrs.field(
converter=_parse_vol_optional_none_zero,
default=ZERO_VOL,
on_setattr=attrs.setters.convert,
)

def dest_concentrations(
self,
mix_vol: Quantity[Decimal] = Q_(DNAN, uL),
mix_vol: DecimalQuantity = Q_(DNAN, uL),
actions: Sequence[AbstractAction] = tuple(),
) -> list[Quantity[Decimal]]:
) -> list[DecimalQuantity]:
return [self.fixed_concentration] * len(self.components)

def each_volumes(
self,
mix_vol: Quantity[Decimal] = Q_(DNAN, uL),
mix_vol: DecimalQuantity = Q_(DNAN, uL),
actions: Sequence[AbstractAction] = tuple(),
) -> list[Quantity[Decimal]]:
) -> list[DecimalQuantity]:
ea_vols = [
mix_vol * r
for r in _ratio(self.fixed_concentration, self.source_concentrations)
Expand All @@ -726,7 +726,7 @@ def each_volumes(
def _mixlines(
self,
tablefmt: str | TableFormat,
mix_vol: Quantity[Decimal],
mix_vol: DecimalQuantity,
actions: Sequence[AbstractAction] = tuple(),
) -> list[MixLine]:
dconcs = self.dest_concentrations(mix_vol)
Expand Down Expand Up @@ -769,18 +769,18 @@ class ToConcentration(ActionWithComponents):
An action adding an amount of components such that the concentration of each component in the mix
will be at some tapiprget concentration. Unlike FixedConcentration, which *adds* a certain concentration, this takes into account other contents of the mix, and only adds enough to reach a particular final concentration."""

fixed_concentration: Quantity[Decimal] = attrs.field(
fixed_concentration: DecimalQuantity = attrs.field(
converter=_parse_conc_required, on_setattr=attrs.setters.convert
)
compact_display: bool = True
min_volume: Quantity[Decimal] = attrs.field(
min_volume: DecimalQuantity = attrs.field(
converter=_parse_vol_optional,
default=Q_(DNAN, uL),
on_setattr=attrs.setters.convert,
)

def _othercomps(
self, mix_vol: Quantity[Decimal], actions: Sequence[AbstractAction] = tuple()
self, mix_vol: DecimalQuantity, actions: Sequence[AbstractAction] = tuple()
):
cps = _empty_components()

Expand Down Expand Up @@ -817,10 +817,10 @@ def _othercomps(

def dest_concentrations(
self,
mix_vol: Quantity,
mix_vol: DecimalQuantity,
actions: Sequence[AbstractAction] = tuple(),
_othercomps: pd.DataFrame | None = None,
) -> Sequence[Quantity[Decimal]]:
) -> Sequence[DecimalQuantity]:
if _othercomps is None and actions:
_othercomps = self._othercomps(mix_vol, actions)
if _othercomps is not None:
Expand All @@ -836,10 +836,10 @@ def dest_concentrations(

def each_volumes(
self,
mix_vol: Quantity[Decimal] = Q_(DNAN, uL),
mix_vol: DecimalQuantity = Q_(DNAN, uL),
actions: Sequence[AbstractAction] = tuple(),
_othercomps: pd.DataFrame | None = None,
) -> list[Quantity[Decimal]]:
) -> list[DecimalQuantity]:
ea_vols = [
mix_vol * r
for r in _ratio(
Expand All @@ -864,7 +864,7 @@ def each_volumes(
def _mixlines(
self,
tablefmt: str | TableFormat,
mix_vol: Quantity[Decimal],
mix_vol: DecimalQuantity,
actions: Sequence[AbstractAction] = tuple(),
) -> list[MixLine]:
othercomps = self._othercomps(mix_vol, actions)
Expand Down

0 comments on commit b8dc004

Please sign in to comment.