From 8f4332c4ab808d24e6d721b41db7e8c030fb3fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Sv=C3=A4rd?= <60181709+Karl-Svard@users.noreply.github.com> Date: Thu, 28 Mar 2024 14:13:20 +0100 Subject: [PATCH] add more options to aliquot EPP, refactored some options (#490) ### Changed - made the "Calculate Aliquot Volume" EPP more general by allowing for custom UDF names as CLI input - refactored some click options --- cg_lims/EPPs/udf/calculate/aliquot_volume.py | 63 +++++++++++++++---- .../EPPs/udf/calculate/calculate_amount_ng.py | 2 +- .../udf/calculate/calculate_amount_ng_fmol.py | 2 +- .../EPPs/udf/calculate/ont_aliquot_volume.py | 4 +- cg_lims/options.py | 2 +- .../EPPs/udf/calculate/test_aliquot_volume.py | 30 ++++++++- 6 files changed, 83 insertions(+), 20 deletions(-) diff --git a/cg_lims/EPPs/udf/calculate/aliquot_volume.py b/cg_lims/EPPs/udf/calculate/aliquot_volume.py index 701847d8..b4472c43 100644 --- a/cg_lims/EPPs/udf/calculate/aliquot_volume.py +++ b/cg_lims/EPPs/udf/calculate/aliquot_volume.py @@ -3,6 +3,7 @@ from typing import List import click +from cg_lims import options from cg_lims.exceptions import LimsError, MissingUDFsError from cg_lims.get.artifacts import get_artifacts from genologics.entities import Artifact, Process @@ -10,36 +11,66 @@ LOG = logging.getLogger(__name__) -def calculate_volumes(artifacts: List[Artifact], process: Process): +def calculate_volumes( + artifacts: List[Artifact], + process: Process, + concentration_udf: str, + sample_volume_udf: str, + buffer_volume_udf: str, + total_volume_udf: str, + amount_needed_udf: str, +): """Calculates volumes for diluting samples. The total volume differ depending on - type of sample. It is given by the process udf 'Total Volume (ul)'.""" + type of sample. It is given by the process udf .""" - max_volume = process.udf.get("Total Volume (ul)") + max_volume = process.udf.get(total_volume_udf) if not max_volume: - raise MissingUDFsError("Process udf missing: Total Volume (ul)") + raise MissingUDFsError(f"Process udf missing:{total_volume_udf}") missing_udfs = 0 for art in artifacts: - concentration = art.udf.get("Concentration") - amount = art.udf.get("Amount needed (ng)") + concentration = art.udf.get(concentration_udf) + amount = art.udf.get(amount_needed_udf) if not amount or not concentration: missing_udfs += 1 continue - art.udf["Sample Volume (ul)"] = amount / float(concentration) - art.udf["Volume H2O (ul)"] = max_volume - art.udf["Sample Volume (ul)"] + art.udf[sample_volume_udf] = amount / float(concentration) + art.udf[buffer_volume_udf] = max_volume - art.udf[sample_volume_udf] art.put() if missing_udfs: raise MissingUDFsError( - f"UDFs 'Concentration' and/or 'Amount needed (ng)' missing for {missing_udfs} samples" + f"UDFs '{concentration_udf}' and/or '{amount_needed_udf}' missing for {missing_udfs} samples" ) @click.command() +@options.concentration_udf(help="Name of the concentration (ng/ul) artifact UDF") +@options.volume_udf(help="Name of the sample volume artifact UDF") +@options.buffer_udf(help="Name of the buffer volume artifact UDF") +@options.total_volume_udf(help="Name of the total volume process UDF") +@options.amount_ng_udf( + help="Use if you want to overwrite the default UDF name 'Amount needed (ng)'" +) +@options.measurement( + help="UDFs will be calculated and set on measurement artifacts. Use in QC steps." +) +@options.input( + help="UDFs will be calculated ans set on input artifacts. Use non-output generating steps." +) @click.pass_context -def aliquot_volume(ctx): +def aliquot_volume( + ctx: click.Context, + concentration_udf: str, + volume_udf: str, + buffer_udf: str, + total_volume_udf: str, + amount_ng_udf: str = "Amount needed (ng)", + measurement: bool = False, + input: bool = False, +): """Calculates amount needed for samples.""" LOG.info(f"Running {ctx.command_path} with params: {ctx.params}") @@ -47,8 +78,16 @@ def aliquot_volume(ctx): process = ctx.obj["process"] try: - artifacts = get_artifacts(process=process, input=False) - calculate_volumes(artifacts=artifacts, process=process) + artifacts = get_artifacts(process=process, input=input, measurement=measurement) + calculate_volumes( + artifacts=artifacts, + process=process, + concentration_udf=concentration_udf, + sample_volume_udf=volume_udf, + buffer_volume_udf=buffer_udf, + total_volume_udf=total_volume_udf, + amount_needed_udf=amount_ng_udf, + ) message = "Volumes have been calculated for all samples." LOG.info(message) click.echo(message) diff --git a/cg_lims/EPPs/udf/calculate/calculate_amount_ng.py b/cg_lims/EPPs/udf/calculate/calculate_amount_ng.py index 77235536..bde917e0 100644 --- a/cg_lims/EPPs/udf/calculate/calculate_amount_ng.py +++ b/cg_lims/EPPs/udf/calculate/calculate_amount_ng.py @@ -12,7 +12,7 @@ @click.command() -@options.concentration_udf_option() +@options.concentration_udf() @options.amount_udf_option() @options.volume_udf() @options.subtract_volume_option() diff --git a/cg_lims/EPPs/udf/calculate/calculate_amount_ng_fmol.py b/cg_lims/EPPs/udf/calculate/calculate_amount_ng_fmol.py index 83c7a3c0..45469dcb 100644 --- a/cg_lims/EPPs/udf/calculate/calculate_amount_ng_fmol.py +++ b/cg_lims/EPPs/udf/calculate/calculate_amount_ng_fmol.py @@ -112,7 +112,7 @@ def set_amounts( @click.command() @options.process_types() -@options.concentration_udf_option() +@options.concentration_udf() @options.volume_udf_option() @options.preset_volume() @options.size_udf() diff --git a/cg_lims/EPPs/udf/calculate/ont_aliquot_volume.py b/cg_lims/EPPs/udf/calculate/ont_aliquot_volume.py index 40f3186b..794392f6 100644 --- a/cg_lims/EPPs/udf/calculate/ont_aliquot_volume.py +++ b/cg_lims/EPPs/udf/calculate/ont_aliquot_volume.py @@ -93,7 +93,7 @@ def set_volumes( @click.command() @options.process_types() -@options.concentration_udf_option() +@options.concentration_udf() @options.size_udf() @options.volume_udf(help="Name of sample volume UDF") @options.buffer_udf() @@ -115,7 +115,7 @@ def ont_aliquot_volume( volume_udf: str, buffer_udf: str, amount_fmol_udf: str = "Amount needed (fmol)", - amount_ng_udf: str = "Amount needed (fmol)", + amount_ng_udf: str = "Amount needed (ng)", total_volume_udf: Optional[str] = None, measurement: bool = False, input: bool = False, diff --git a/cg_lims/options.py b/cg_lims/options.py index cb28be9b..a5695b22 100644 --- a/cg_lims/options.py +++ b/cg_lims/options.py @@ -279,7 +279,7 @@ def volume_udf_option( return click.option("--volume-udf", required=False, help=help) -def concentration_udf_option( +def concentration_udf( help: str = "String of UDF used to get concentration value", ) -> click.option: return click.option("--concentration-udf", required=True, help=help) diff --git a/tests/EPPs/udf/calculate/test_aliquot_volume.py b/tests/EPPs/udf/calculate/test_aliquot_volume.py index 0a29604d..317f9bf1 100644 --- a/tests/EPPs/udf/calculate/test_aliquot_volume.py +++ b/tests/EPPs/udf/calculate/test_aliquot_volume.py @@ -38,7 +38,15 @@ def test_calculate_volumes( artifact_1.put() # WHEN calculating the aliquot sample and water volumes - calculate_volumes(artifacts=[artifact_1], process=process) + calculate_volumes( + artifacts=[artifact_1], + process=process, + concentration_udf="Concentration", + sample_volume_udf="Sample Volume (ul)", + buffer_volume_udf="Volume H2O (ul)", + total_volume_udf="Total Volume (ul)", + amount_needed_udf="Amount needed (ng)", + ) # THEN the correct values are calculated for the artifact UDFs 'Volume H2O (ul)' and 'Sample Volume (ul)' assert artifact_1.udf["Sample Volume (ul)"] == sample_vol @@ -73,7 +81,15 @@ def test_calculate_volumes_missing_artifact_udf(lims: Lims, udf_name: str): # WHEN calculating the aliquot sample and water volumes # THEN MissingUDFsError is being raised, while also correctly setting the values for artifact_2 with pytest.raises(MissingUDFsError): - calculate_volumes(artifacts=[artifact_1, artifact_2], process=process) + calculate_volumes( + artifacts=[artifact_1, artifact_2], + process=process, + concentration_udf="Concentration", + sample_volume_udf="Sample Volume (ul)", + buffer_volume_udf="Volume H2O (ul)", + total_volume_udf="Total Volume (ul)", + amount_needed_udf="Amount needed (ng)", + ) assert artifact_2.udf["Sample Volume (ul)"] == 20 assert artifact_2.udf["Volume H2O (ul)"] == 30 @@ -94,4 +110,12 @@ def test_calculate_volumes_missing_process_udf(lims: Lims): # WHEN calculating the aliquot sample and water volumes # THEN MissingUDFsError is being raised with pytest.raises(MissingUDFsError): - calculate_volumes(artifacts=[artifact_1], process=process) + calculate_volumes( + artifacts=[artifact_1], + process=process, + concentration_udf="Concentration", + sample_volume_udf="Sample Volume (ul)", + buffer_volume_udf="Volume H2O (ul)", + total_volume_udf="Total Volume (ul)", + amount_needed_udf="Amount needed (ng)", + )