From 00df2edb15ea38c985b6c759677cf700374ef702 Mon Sep 17 00:00:00 2001 From: mgcam Date: Tue, 11 Jun 2024 18:59:28 +0100 Subject: [PATCH] Added an end point for well library data. --- lang_qc/endpoints/pacbio_well.py | 33 +++++++++++- lang_qc/models/pacbio/well.py | 3 +- lang_qc/util/errors.py | 7 +++ tests/endpoints/test_well_libraries.py | 70 ++++++++++++++++++++++++++ tests/test_pb_well_models.py | 5 +- 5 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 tests/endpoints/test_well_libraries.py diff --git a/lang_qc/endpoints/pacbio_well.py b/lang_qc/endpoints/pacbio_well.py index f9d4957..d2a5a61 100644 --- a/lang_qc/endpoints/pacbio_well.py +++ b/lang_qc/endpoints/pacbio_well.py @@ -37,13 +37,18 @@ from lang_qc.db.mlwh_connection import get_mlwh_db from lang_qc.db.qc_connection import get_qc_db from lang_qc.db.qc_schema import User -from lang_qc.models.pacbio.well import PacBioPagedWells, PacBioWellFull +from lang_qc.models.pacbio.well import ( + PacBioPagedWells, + PacBioWellFull, + PacBioWellLibraries, +) from lang_qc.models.qc_flow_status import QcFlowStatusEnum from lang_qc.models.qc_state import QcState, QcStateBasic from lang_qc.util.auth import check_user from lang_qc.util.errors import ( InconsistentInputError, InvalidDictValueError, + MissingLimsDataError, RunNotFoundError, ) from lang_qc.util.type_checksum import ChecksumSHA256 @@ -163,6 +168,32 @@ def get_wells_in_run( return response +@router.get( + "/wells/{id_product}/libraries", + summary="Get well summary and LIMS data for all libraries", + responses={ + status.HTTP_404_NOT_FOUND: {"description": "Well product does not exist"}, + status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid product ID"}, + status.HTTP_409_CONFLICT: {"description": "Missing or incomplete LIMS data"}, + }, + response_model=PacBioWellLibraries, +) +def get_well_lims_info( + id_product: ChecksumSHA256, + mlwhdb_session: Session = Depends(get_mlwh_db), +) -> PacBioWellLibraries: + + db_well = _find_well_product_or_error(id_product, mlwhdb_session) + well_libraries: PacBioWellLibraries + try: + well_libraries = PacBioWellLibraries(db_well=db_well) + except MissingLimsDataError as err: + # 409 - Request conflicts with the current state of the server. + raise HTTPException(409, detail=str(err)) + + return well_libraries + + @router.get( "/products/{id_product}/seq_level", summary="Get full sequencing QC metrics and state for a product", diff --git a/lang_qc/models/pacbio/well.py b/lang_qc/models/pacbio/well.py index e5bf0d8..e809805 100644 --- a/lang_qc/models/pacbio/well.py +++ b/lang_qc/models/pacbio/well.py @@ -31,6 +31,7 @@ from lang_qc.models.pacbio.qc_data import QCDataWell from lang_qc.models.pager import PagedResponse from lang_qc.models.qc_state import QcState +from lang_qc.util.errors import MissingLimsDataError def get_field_names(cls): @@ -199,7 +200,7 @@ def pre_root(cls, values: dict[str, Any]) -> dict[str, Any]: mlwh_db_row: PacBioRunWellMetrics = values.kwargs["db_well"] lims_data = mlwh_db_row.get_experiment_info() if len(lims_data) == 0: - raise ValueError( + raise MissingLimsDataError( f"No LIMS data retrieved for {mlwh_db_row.__repr__()} " "on account of partially linked or unlinked product data." ) diff --git a/lang_qc/util/errors.py b/lang_qc/util/errors.py index 21dab57..aeac0ef 100644 --- a/lang_qc/util/errors.py +++ b/lang_qc/util/errors.py @@ -25,3 +25,10 @@ class EmptyListOfRunNamesError(Exception): class RunNotFoundError(Exception): """Exception to be used when no well metrics data for a run is found.""" + + +class MissingLimsDataError(Exception): + """ + Exception to be used when product LIMS data is not available + or partially missing. + """ diff --git a/tests/endpoints/test_well_libraries.py b/tests/endpoints/test_well_libraries.py new file mode 100644 index 0000000..d35e476 --- /dev/null +++ b/tests/endpoints/test_well_libraries.py @@ -0,0 +1,70 @@ +from fastapi.testclient import TestClient +from sqlalchemy import select + +# from lang_qc.db.mlwh_schema import PacBioRunWellMetrics + + +def test_well_libraries(test_client: TestClient, mlwhdb_load_runs): + """Test retrieval of LIMS library data for a well.""" + + response = test_client.get(f"/pacbio/wells/malformed/libraries") + assert response.status_code == 422 + + id_product = "aaa8bd66e0f0895ea728c1d08103c62d3de8a57a5f879cee45f7b0acc028aa61" + response = test_client.get(f"/pacbio/wells/{id_product}/libraries") + assert response.status_code == 404 + + # Partially linked well + id_product = "26928ba6ec2a00c04dd6c7c68008ec9436e3979a384b9f708dc371c99f272e17" + response = test_client.get(f"/pacbio/wells/{id_product}/libraries") + assert response.status_code == 409 + assert response.json()["detail"] == "".join( + [ + "No LIMS data retrieved for lang_qc.db.mlwh_schema.PacBioRunWellMetrics:", + " pac_bio_run_name=TRACTION-RUN-1140, well_label=C1, plate_number=2,", + " id_pac_bio_product=26928ba6ec2a00c04dd6c7c68008ec9436e3979a384b9f708dc371c99f272e17", + " on account of partially linked or unlinked product data.", + ] + ) + + # Fully linked well + id_product = "513c674f489b106c6af716dd0d210826ff03b7648d50888839c3722ca1b10dbf" + response = test_client.get(f"/pacbio/wells/{id_product}/libraries") + assert response.status_code == 200 + expected_response = { + "id_product": "513c674f489b106c6af716dd0d210826ff03b7648d50888839c3722ca1b10dbf", + "label": "A1", + "plate_number": 2, + "run_name": "TRACTION-RUN-1140", + "run_start_time": "2024-02-23T10:28:12", + "run_complete_time": "2024-02-25T20:53:05", + "well_start_time": "2024-02-24T14:25:12", + "well_complete_time": "2024-02-26T00:27:52", + "run_status": "Complete", + "well_status": "Complete", + "instrument_name": "84093", + "instrument_type": "Revio", + "qc_state": None, + "libraries": [ + { + "study_id": "5901", + "study_name": "DTOL_Darwin Tree of Life", + "sample_id": "9478726", + "sample_name": "DTOL14523243", + "tag_sequence": ["ATCTGCACGTGAGTAT"], + "library_type": "Pacbio_HiFi", + "pool_name": "TRAC-2-7677", + }, + { + "study_id": "5901", + "study_name": "DTOL_Darwin Tree of Life", + "sample_id": "9518398", + "sample_name": "DTOL14180244", + "tag_sequence": ["ATGTACTAGTGAGTAT"], + "library_type": "Pacbio_HiFi", + "pool_name": "TRAC-2-7677", + }, + ], + } + + assert response.json() == expected_response diff --git a/tests/test_pb_well_models.py b/tests/test_pb_well_models.py index ed80b75..ce5560d 100644 --- a/tests/test_pb_well_models.py +++ b/tests/test_pb_well_models.py @@ -11,6 +11,7 @@ PacBioWellLibraries, PacBioWellSummary, ) +from lang_qc.util.errors import MissingLimsDataError from tests.conftest import compare_dates from tests.fixtures.well_data import load_data4well_retrieval, load_dicts_and_users @@ -163,7 +164,7 @@ def test_create_summary_and_library_models_lims_info( pb_well = PacBioWellSummary(db_well=well_row) assert pb_well.study_names == [] - with pytest.raises(ValueError, match=r"No LIMS data retrieved"): + with pytest.raises(MissingLimsDataError, match=r"No LIMS data retrieved"): PacBioWellLibraries(db_well=well_row) # Fully linked wells with one sample @@ -242,5 +243,5 @@ def test_create_summary_and_library_models_lims_info( pb_well = PacBioWellSummary(db_well=well_row) assert pb_well.study_names == [] - with pytest.raises(ValueError, match=r"No LIMS data retrieved"): + with pytest.raises(MissingLimsDataError, match=r"No LIMS data retrieved"): PacBioWellLibraries(db_well=well_row)