diff --git a/pyproject.toml b/pyproject.toml
index 87c892f..19f98f5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -41,6 +41,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
"License :: OSI Approved :: BSD License",
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering",
@@ -104,10 +105,10 @@ dependencies = [
name.echo.features = ["echo"]
[[tool.hatch.envs.hatch-test.matrix]]
-python = ["3.8", "3.9", "3.10", "3.11", "3.12"]
+python = ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
[[tool.hatch.envs.hatch-test.matrix]]
-python = ["3.10", "3.11", "3.12"]
+python = ["3.10", "3.11", "3.12", "3.13"]
feature = ["echo"]
[tool.ruff]
diff --git a/src/alhambra_mixes/mixes.py b/src/alhambra_mixes/mixes.py
index aefd6fb..7712a7b 100644
--- a/src/alhambra_mixes/mixes.py
+++ b/src/alhambra_mixes/mixes.py
@@ -631,9 +631,15 @@ def _tube_map_from_mixline(self, mixline: MixLine) -> str:
def tubes_markdown(self, tablefmt: str | TableFormat = "pipe") -> str:
"""
- :param tablefmt:
+
+ Parameters
+ ----------
+
+ tablefmt:
table format (see :meth:`PlateMap.to_table` for description)
- :return:
+
+ Returns
+ -------
a Markdown (or other format according to `tablefmt`)
string indicating which strands in test tubes to pipette, grouped by the volume
of each
@@ -660,14 +666,20 @@ def display_instructions(
"""
Displays in a Jupyter notebook the result of calling :meth:`Mix.instructions()`.
- :param plate_type:
+ Parameters
+ ----------
+
+ plate_type:
96-well or 384-well plate; default is 96-well.
- :param raise_failed_validation:
+
+ raise_failed_validation:
If validation fails (volumes don't make sense), raise an exception.
- :param combine_plate_actions:
+
+ combine_plate_actions:
If True, then if multiple actions in the Mix take the same volume from the same plate,
they will be combined into a single :class:`PlateMap`.
- :param well_marker:
+
+ well_marker:
By default the strand's name is put in the relevant plate entry. If `well_marker` is specified
and is a string, then that string is put into every well with a strand in the plate map instead.
This is useful for printing plate maps that just put,
@@ -678,22 +690,28 @@ def display_instructions(
that takes as input a string representing the well (such as ``"B3"`` or ``"E11"``),
and outputs a string. For example, giving the identity function
``mix.to_table(well_marker=lambda x: x)`` puts the well address itself in the well.
- :param title_level:
+
+ title_level:
The "title" is the first line of the returned string, which contains the plate's name
and volume to pipette. The `title_level` controls the size, with 1 being the largest size,
(header level 1, e.g., # title in Markdown or
title
in HTML).
- :param warn_unsupported_title_format:
+
+ warn_unsupported_title_format:
If True, prints a warning if `tablefmt` is a currently unsupported option for the title.
The currently supported formats for the title are 'github', 'html', 'unsafehtml', 'rst',
'latex', 'latex_raw', 'latex_booktabs', "latex_longtable". If `tablefmt` is another valid
option, then the title will be the Markdown format, i.e., same as for `tablefmt` = 'github'.
- :param tablefmt:
+
+ tablefmt:
By default set to `'github'` to create a Markdown table. For other options see
https://github.com/astanin/python-tabulate#readme
- :param include_plate_maps:
+
+ include_plate_maps:
If True, include plate maps as part of displayed instructions, otherwise only include the
more compact mixing table (which is always displayed regardless of this parameter).
- :return:
+
+ Returns
+ -------
pipetting instructions in the form of strings combining results of :meth:`Mix.table` and
:meth:`Mix.plate_maps`
"""
@@ -714,9 +732,14 @@ def display_instructions(
def generate_picklist(self, experiment: Experiment | None, _cache_key=None) -> PickList | None:
"""
- :param experiment:
+ Parameters
+ ----------
+
+ experiment:
experiment to use for generating picklist
- :return:
+
+ Returns
+ -------
picklist for the mix
"""
@@ -747,14 +770,21 @@ def instructions(
Returns string combiniing the string results of calling :meth:`Mix.table` and
:meth:`Mix.plate_maps` (then calling :meth:`PlateMap.to_table` on each :class:`PlateMap`).
- :param plate_type:
+ Parameters
+ ----------
+
+ plate_type:
96-well or 384-well plate; default is 96-well.
- :param raise_failed_validation:
+
+
+ raise_failed_validation:
If validation fails (volumes don't make sense), raise an exception.
- :param combine_plate_actions:
+
+ combine_plate_actions:
If True, then if multiple actions in the Mix take the same volume from the same plate,
they will be combined into a single :class:`PlateMap`.
- :param well_marker:
+
+ well_marker:
By default the strand's name is put in the relevant plate entry. If `well_marker` is specified
and is a string, then that string is put into every well with a strand in the plate map instead.
This is useful for printing plate maps that just put,
@@ -765,22 +795,28 @@ def instructions(
that takes as input a string representing the well (such as ``"B3"`` or ``"E11"``),
and outputs a string. For example, giving the identity function
``mix.to_table(well_marker=lambda x: x)`` puts the well address itself in the well.
- :param title_level:
+
+ title_level:
The "title" is the first line of the returned string, which contains the plate's name
and volume to pipette. The `title_level` controls the size, with 1 being the largest size,
(header level 1, e.g., # title in Markdown or title
in HTML).
- :param warn_unsupported_title_format:
+
+ warn_unsupported_title_format:
If True, prints a warning if `tablefmt` is a currently unsupported option for the title.
The currently supported formats for the title are 'github', 'html', 'unsafehtml', 'rst',
'latex', 'latex_raw', 'latex_booktabs', "latex_longtable". If `tablefmt` is another valid
option, then the title will be the Markdown format, i.e., same as for `tablefmt` = 'github'.
- :param tablefmt:
+
+ tablefmt:
By default set to `'github'` to create a Markdown table. For other options see
https://github.com/astanin/python-tabulate#readme
- :param include_plate_maps:
+
+ include_plate_maps:
If True, include plate maps as part of displayed instructions, otherwise only include the
more compact mixing table (which is always displayed regardless of this parameter).
- :return:
+
+ Returns
+ -------
pipetting instructions in the form of strings combining results of :meth:`Mix.table` and
:meth:`Mix.plate_maps`
"""
@@ -1122,7 +1158,10 @@ def to_table(
which creates a Markdown format. To create other formats such as HTML, change the value of
`tablefmt`; see https://github.com/astanin/python-tabulate#readme for other possible formats.
- :param well_marker:
+ Parameters
+ ----------
+
+ well_marker:
By default the strand's name is put in the relevant plate entry. If `well_marker` is specified
and is a string, then that string is put into every well with a strand in the plate map instead.
This is useful for printing plate maps that just put,
@@ -1133,29 +1172,39 @@ def to_table(
that takes as input a string representing the well (such as ``"B3"`` or ``"E11"``),
and outputs a string. For example, giving the identity function
``mix.to_table(well_marker=lambda x: x)`` puts the well address itself in the well.
- :param title_level:
+
+ title_level:
The "title" is the first line of the returned string, which contains the plate's name
and volume to pipette. The `title_level` controls the size, with 1 being the largest size,
(header level 1, e.g., # title in Markdown or title
in HTML).
- :param warn_unsupported_title_format:
+
+ warn_unsupported_title_format:
If True, prints a warning if `tablefmt` is a currently unsupported option for the title.
The currently supported formats for the title are 'github', 'html', 'unsafehtml', 'rst',
'latex', 'latex_raw', 'latex_booktabs', "latex_longtable". If `tablefmt` is another valid
option, then the title will be the Markdown format, i.e., same as for `tablefmt` = 'github'.
- :param tablefmt:
+
+ tablefmt:
By default set to `'github'` to create a Markdown table. For other options see
https://github.com/astanin/python-tabulate#readme
- :param stralign:
+
+ stralign:
See https://github.com/astanin/python-tabulate#readme
- :param missingval:
+
+ missingval:
See https://github.com/astanin/python-tabulate#readme
- :param showindex:
+
+ showindex:
See https://github.com/astanin/python-tabulate#readme
- :param disable_numparse:
+
+ disable_numparse:
See https://github.com/astanin/python-tabulate#readme
- :param colalign:
+
+ colalign:
See https://github.com/astanin/python-tabulate#readme
- :return:
+
+ Returns
+ -------
a string representation of this plate map
"""
if title_level not in [1, 2, 3, 4, 5, 6]:
diff --git a/src/alhambra_mixes/printing.py b/src/alhambra_mixes/printing.py
index 79bc0dc..26802ff 100644
--- a/src/alhambra_mixes/printing.py
+++ b/src/alhambra_mixes/printing.py
@@ -19,11 +19,17 @@ def emphasize(text: str, tablefmt: str | TableFormat, strong: bool = False) -> s
surrounds with pair of *'s; if `strong` is True, with double *'s. For `tablefmt` = `'html'`,
uses ```` or ````.
- :param text:
+ Parameters
+ ----------
+
+ text:
text to emphasize
- :param tablefmt:
+
+ tablefmt:
format in which to add emphasis markup
- :return:
+
+ Returns
+ -------
emphasized version of `text`
"""
# formats a title for a table produced using tabulate,
diff --git a/src/alhambra_mixes/quantitate.py b/src/alhambra_mixes/quantitate.py
index cef5045..59cc918 100644
--- a/src/alhambra_mixes/quantitate.py
+++ b/src/alhambra_mixes/quantitate.py
@@ -139,11 +139,17 @@ def hydrate(
"""
Indicates how much buffer/water volume to add to a dry DNA sample to reach a particular concentration.
- :param target_conc:
+ Parameters
+ ----------
+
+ target_conc:
target concentration. If float/int, units are µM (micromolar).
- :param nmol:
+
+ nmol:
number of nmol (nanomoles) of dry product.
- :return:
+
+ Returns
+ -------
number of µL (microliters) of water/buffer to pipette to reach `target_conc` concentration
"""
target_conc = parse_conc(target_conc)
@@ -162,13 +168,20 @@ def dilute(
"""
Indicates how much buffer/water volume to add to a wet DNA sample to reach a particular concentration.
- :param target_conc:
+ Parameters
+ ----------
+
+ target_conc:
target concentration. If float/int, units are µM (micromolar).
- :param start_conc:
+
+ start_conc:
current concentration of sample. If float/int, units are µM (micromolar).
- :param vol:
+
+ vol:
current volume of sample. If float/int, units are µL (microliters)
- :return:
+
+ Returns
+ -------
number of µL (microliters) of water/buffer to add to dilate to concentration `target_conc`
"""
target_conc = parse_conc(target_conc)
@@ -198,12 +211,18 @@ def measure_conc(
"""
Calculates concentration of DNA sample given an absorbance reading on a NanoDrop machine.
- :param absorbance:
+ Parameters
+ ----------
+
+ absorbance:
UV absorbance at 260 nm. Can either be a single float/int or a nonempty sequence of floats/ints
representing repeated measurements; if the latter then an average is taken.
- :param ext_coef:
+
+ ext_coef:
Extinction coefficient in L/mol*cm.
- :return:
+
+ Returns
+ -------
concentration of DNA sample
"""
if isinstance(absorbance, (float, int)):
@@ -242,19 +261,26 @@ def measure_conc_and_dilute(
Calculates concentration of DNA sample given an absorbance reading on a NanoDrop machine,
then calculates the amount of buffer/water that must be added to dilute it to a target concentration.
- :param absorbance:
+ Parameters
+ ----------
+
+ absorbance:
UV absorbance at 260 nm. Can either be a single float/int or a nonempty sequence of floats/ints
representing repeated measurements; if the latter then an average is taken.
- :param ext_coef:
+
+ ext_coef:
Extinction coefficient in L/mol*cm.
- :param target_conc:
+
+ target_conc:
target concentration. If float/int, units are µM (micromolar).
- :param vol:
+
+ vol:
current volume of sample. If float/int, units are µL (microliters)
NOTE: This is the volume *before* samples are taken to measure absorbance.
It is assumed that each sample taken to measure absorbance is 1 µL.
If that is not the case, then set the parameter `vol_removed` to the total volume removed.
- :param vol_removed:
+
+ vol_removed:
Total volume removed from `vol` to measure absorbance.
For example, if two samples were taken, one at 1 µL and one at 1.5 µL, then set
`vol_removed` = 2.5 µL.
@@ -264,7 +290,9 @@ def measure_conc_and_dilute(
then it is assumed the number of samples is 1 (i.e., `vol_removed` = 1 µL),
otherwise if `absorbance` is a list, then the length of the list is assumed to be the
number of samples taken, each at 1 µL.
- :return:
+
+ Returns
+ -------
The pair (current concentration of DNA sample, volume to add to reach `target_conc`)
"""
if vol_removed is None:
@@ -324,25 +352,34 @@ def measure_conc_and_dilute_from_specs(
{'mon0': (, ),
'adp0': (, )}
- :param filename:
+ Parameters
+ ----------
+
+ filename:
IDT specs file (e.g., coa.csv)
- :param target_conc:
+
+ target_conc:
target concentration to dilute to from measured concentration
- :param absorbances:
+
+ absorbances:
measured absorbance of each strand. Should be a dict mapping each strand name (as it appears in
the "Sequence name" column of `filename`) to an absorbance or nonempty list of absorbances, meaning
UV absorbance at 260 nm. If a list then an average is taken.
- :param vols_removed:
+
+ vols_removed:
dict mapping each strand name to the volume that was removed to take absorbance measurements.
For any strand name not appearing as a key in the dict, it is assumed that 1 microliter was taken
for each absorbance measurement made.
- :param enforce_utf8:
+
+ enforce_utf8:
If `filename` is a text CSV file and this paramter is True, it enforces that `filename` is valid
UTF-8, raising an exception if not. This helps to avoid accidentally dropping Unicode characters
such as µ, which would silently convert a volume from µL to L.
If do not want to convert the specs file to UTF-8 and you are certain that no important Unicode
characters would be dropped, then you can set this parameter to false.
- :return:
+
+ Returns
+ -------
dict mapping each strand name to a pair `(conc, vol)`, where `conc` is its measured concentration
and `vol` is the volume that should be subsequently added to reach concentration `target_conc`
"""
@@ -385,19 +422,26 @@ def display_measure_conc_and_dilute_from_specs(
Like :meth:`measure_conc_and_dilute_from_specs`, but displays the value in a Jupyter
notebook instead of returning it.
- :param filename:
+ Parameters
+ ----------
+
+ filename:
IDT specs file (e.g., coa.csv)
- :param target_conc:
+
+ target_conc:
target concentration to dilute to from measured concentration
- :param absorbances:
+
+ absorbances:
measured absorbance of each strand. Should be a dict mapping each strand name (as it appears in
the "Sequence name" column of `filename`) to an absorbance or nonempty list of absorbances, meaning
UV absorbance at 260 nm. If a list then an average is taken.
- :param vols_removed:
+
+ vols_removed:
dict mapping each strand name to the volume that was removed to take absorbance measurements.
For any strand name not appearing as a key in the dict, it is assumed that 1 microliter was taken
for each absorbance measurement made.
- :param enforce_utf8:
+
+ enforce_utf8:
If `filename` is a text CSV file and this paramter is True, it enforces that `filename` is valid
UTF-8, raising an exception if not. This helps to avoid accidentally dropping Unicode characters
such as µ, which would silently convert a volume from µL to L.
@@ -451,19 +495,27 @@ def hydrate_and_measure_conc_and_dilute(
`target_conc_low` with a subsequent dilution step. (As opposed to requiring a vacufuge to
concentrate the sample higher).
- :param nmol:
+ Parameters
+ ----------
+
+ nmol:
number of nmol (nanomoles) of dry product.
- :param target_conc_high:
+
+ target_conc_high:
target concentration for initial hydration. Should be higher than `target_conc_low`,
- :param target_conc_low:
+
+ target_conc_low:
the "real" target concentration that we will try to hit after the second
addition of water/buffer.
- :param absorbance:
+
+ absorbance:
UV absorbance at 260 nm. Can either be a single float/int or a nonempty sequence of floats/ints
representing repeated measurements; if the latter then an average is taken.
- :param ext_coef:
+
+ ext_coef:
Extinction coefficient in L/mol*cm.
- :param vol_removed:
+
+ vol_removed:
Total volume removed from `vol` to measure absorbance.
For example, if two samples were taken, one at 1 µL and one at 1.5 µL, then set
`vol_removed` = 2.5 µL.
@@ -569,20 +621,27 @@ def hydrate_and_measure_conc_and_dilute_from_specs(
Instead of returning a dictionary, these methods display the result in the Jupyter notebook,
as nicely-formatted Markdown.
- :param filename:
+ Parameters
+ ----------
+
+ filename:
path to IDT Excel/CSV spreadsheet with specs of strands (e.g., coa.csv)
- :param target_conc_high:
+
+ target_conc_high:
target concentration for initial hydration. Should be higher than `target_conc_low`,
- :param target_conc_low:
+
+ target_conc_low:
the "real" target concentration that we will try to hit after the second
addition of water/buffer.
- :param absorbances:
+
+ absorbances:
UV absorbances at 260 nm. Is a dict mapping each strand name to an "absorbance" as defined
in the `absobance` parameter of :func:`hydrate_and_measure_conc_and_dilute`.
In other words the value to which each strand name maps
can either be a single float/int, or a nonempty sequence of floats/ints
representing repeated measurements; if the latter then an average is taken.
- :param vols_removed:
+
+ vols_removed:
Total volumes removed from `vol` to measure absorbance;
is a dict mapping strand names (should be subset of strand names that are keys in `absorbances`).
Can be None, or can have strictly fewer strand names than in `absorbances`;
@@ -595,13 +654,16 @@ def hydrate_and_measure_conc_and_dilute_from_specs(
then it is assumed the number of samples is 1 (i.e., `vol_removed` = 1 µL),
otherwise if `absorbance` is a list, then the length of the list is assumed to be the
number of samples taken, each at 1 µL.
- :param enforce_utf8:
+
+ enforce_utf8:
If `filename` is a text CSV file and this paramter is True, it enforces that `filename` is valid
UTF-8, raising an exception if not. This helps to avoid accidentally dropping Unicode characters
such as µ, which would silently convert a volume from µL to L.
If do not want to convert the specs file to UTF-8 and you are certain that no important Unicode
characters would be dropped, then you can set this parameter to false.
- :return:
+
+ Returns
+ -------
dict mapping each strand name in keys of `absorbances` to a pair (`conc`, `vol_to_add`),
where `conc` is the measured concentration according to the absorbance value(s) of that strandm
and `vol_to_add` is the volume needed to add to reach concentration `target_conc_low`.
@@ -660,20 +722,28 @@ def hydrate_from_specs(
Indicates how much volume to add to a dry DNA sample to reach a particular concentration,
given data in an Excel file in the IDT format.
- :param filename:
+ Parameters
+ ----------
+
+ filename:
path to IDT Excel/CSV spreadsheet with specs of strands (e.g., coa.csv)
- :param target_conc:
+
+ target_conc:
target concentration. If float/int, units are µM (micromolar).
- :param strands:
+
+ strands:
strands to hydrate. Can be list of strand names (strings), or list of of ints indicating
which rows in the Excel spreadsheet to hydrate
- :param enforce_utf8:
+
+ enforce_utf8:
If `filename` is a text CSV file and this paramter is True, it enforces that `filename` is valid
UTF-8, raising an exception if not. This helps to avoid accidentally dropping Unicode characters
such as µ, which would silently convert a volume from µL to L.
If do not want to convert the specs file to UTF-8 and you are certain that no important Unicode
characters would be dropped, then you can set this parameter to false.
- :return:
+
+ Returns
+ -------
dict mapping each strand name to an amount of µL (microliters) of water/buffer
to pipette to reach `target_conc` concentration for that strand
"""
@@ -805,20 +875,27 @@ def measure_conc_from_specs(
Indicates the concentrations of DNA samples, given data in an Excel file in the IDT format and
measured absorbances from a Nanodrop machine.
- :param filename:
+ Parameters
+ ----------
+
+ filename:
path to IDT Excel/CSV spreadsheet with specs of strands (e.g., coa.csv)
- :param absorbances:
+
+ absorbances:
dict mapping each strand name to its absorbance value.
Each absorbance value represents UV absorbance at 260 nm.
Each can either be a single float/int or a nonempty sequence of floats/ints
representing repeated measurements; if the latter then an average is taken.
- :param enforce_utf8:
+
+ enforce_utf8:
If `filename` is a text CSV file and this paramter is True, it enforces that `filename` is valid
UTF-8, raising an exception if not. This helps to avoid accidentally dropping Unicode characters
such as µ, which would silently convert a volume from µL to L.
If do not want to convert the specs file to UTF-8 and you are certain that no important Unicode
characters would be dropped, then you can set this parameter to false.
- :return:
+
+ Returns
+ -------
dict mapping each strand name to a concentration for that strand
"""
name_key = "Sequence Name"
@@ -891,11 +968,16 @@ def display_hydrate_from_specs(
given data in an Excel file in the IDT format,
displaying the result in a jupyter notebook.
- :param filename:
+ Parameters
+ ----------
+
+ filename:
path to IDT Excel/CSV spreadsheet with specs of strands (e.g., coa.csv)
- :param target_conc:
+
+ target_conc:
target concentration. If float/int, units are µM (micromolar).
- :param strands:
+
+ strands:
strands to hydrate. Can be list of strand names (strings), or list of of ints indicating
which rows in the Excel spreadsheet to hydrate
"""
@@ -926,9 +1008,13 @@ def display_measure_conc_from_specs(
given data in an Excel/CSV file in the IDT format,
displaying the result in a jupyter notebook.
- :param filename:
+ Parameters
+ ----------
+
+ filename:
path to IDT Excel/CSV spreadsheet with specs of strands (e.g., coa.csv)
- :param absorbances:
+
+ absorbances:
dict mapping each strand name to its absorbance value.
Each absorbance value represents UV absorbance at 260 nm.
Each can either be a single float/int or a nonempty sequence of floats/ints
diff --git a/src/alhambra_mixes/references.py b/src/alhambra_mixes/references.py
index eb0b5ae..3b07325 100644
--- a/src/alhambra_mixes/references.py
+++ b/src/alhambra_mixes/references.py
@@ -73,23 +73,44 @@ def plate_map(
plate_type: PlateType = PlateType.wells96,
) -> PlateMap:
"""
- :param name:
+ Return a :class:`PlateMap` for a given plate name in the Reference.
+
+ Parameters
+ ----------
+
+ name:
Name of plate to make a :class:`PlateMap` for.
- :param plate_type:
+
+ plate_type:
Either :data:`PlateType.wells96` or :data:`PlateType.wells384`;
default is :data:`PlateType.wells96`.
- :return:
+
+ Returns
+ -------
a :class:`PlateMap` consisting of all strands in this Reference object from plate named
`name`. Currently always makes a 96-well plate.
+
+ Raises
+ ------
+ ValueError:
+ If `name` is not the name of a plate in the reference.
"""
well_to_strand_name = {}
+ found_plate_name = False
+ available_plate_names = set()
for row in self.df.itertuples():
+ available_plate_names.add(row.Plate)
if row.Plate == name: # type: ignore
+ found_plate_name = True
well = row.Well # type: ignore
sequence = row.Sequence # type: ignore
strand = Strand(name=row.Name, sequence=sequence) # type: ignore
well_to_strand_name[well] = strand.name
+ if not found_plate_name:
+ raise ValueError(f'Plate "{name}" not found in reference file.'
+ f'\nAvailable plate names: {", ".join(available_plate_names)}')
+
plate_map = PlateMap(
plate_name=name,
plate_type=plate_type,
diff --git a/src/alhambra_mixes/units.py b/src/alhambra_mixes/units.py
index 01f27ff..c7b30ee 100644
--- a/src/alhambra_mixes/units.py
+++ b/src/alhambra_mixes/units.py
@@ -207,9 +207,14 @@ def normalize(quantity: DecimalQuantity) -> DecimalQuantity:
https://pint.readthedocs.io/en/0.18/tutorial.html#simplifying-units)
and eliminate trailing zeros.
- :param quantity:
+ Parameters
+ ----------
+
+ quantity:
a pint DecimalQuantity
- :return:
+
+ Returns
+ -------
`quantity` normalized to be compact and without trailing zeros.
"""
quantity = cast(DecimalQuantity, quantity.to_compact())
diff --git a/tests/test_references.py b/tests/test_references.py
index dea8d1f..e9a300c 100644
--- a/tests/test_references.py
+++ b/tests/test_references.py
@@ -1,3 +1,4 @@
+import pytest
from alhambra_mixes import Reference
@@ -17,3 +18,11 @@ def test_idt():
eq = (dfo == dfp).all()
print(eq)
assert eq.loc[["Well", "Sequence", "Concentration (nM)"]].all()
+
+
+def test_raise_error_if_plate_name_not_found():
+ r_order = Reference.compile(("tests/data/holes-order.xlsx", "200 µM"))
+
+ # This should raise an error because the plate name "fake plate name" is not found in the reference
+ with pytest.raises(ValueError):
+ r_order.plate_map("fake plate name")