def _record_samples_in_dart(self):
        def export_result_with_error(error_description):
            LOGGER.critical(error_description)

            return ExportResult(
                success=False,
                create_plate_errors=[
                    CreatePlateError(
                        type=ErrorType.
                        ExportingPostFeedback,  # This error will only reach the imports record
                        origin=RABBITMQ_CREATE_FEEDBACK_ORIGIN_ROOT,
                        description=error_description,
                    )
                ],
            )

        LOGGER.info("Adding to DART")
        message_uuid = self._message.message_uuid.value
        plate_barcode = self._message.plate_barcode.value

        if (sql_server_connection := create_dart_sql_server_conn(
                self._config)) is None:
            return export_result_with_error(
                f"Error connecting to DART database for plate with barcode '{plate_barcode}' "
                f"in message with UUID '{message_uuid}'")
Exemple #2
0
def test_create_dart_sql_server_conn(config):
    with patch("pyodbc.connect") as mock_connect:
        conn_string = (
            f"DRIVER={config.DART_DB_DRIVER};SERVER={config.DART_DB_HOST};"
            f"PORT={config.DART_DB_PORT};DATABASE={config.DART_DB_DBNAME};"
            f"UID={config.DART_DB_RW_USER};PWD={config.DART_DB_RW_PASSWORD}")
        create_dart_sql_server_conn(config)
        mock_connect.assert_called_with(conn_string)
Exemple #3
0
def insert_plates_and_wells_into_dart(docs_to_insert: List[SampleDoc], config: Config) -> bool:
    """Insert plates and wells into the DART database.
    Create in DART with docs_to_insert

    Arguments:
        docs_to_insert {List[SampleDoc]} -- List of any unprocessed samples

    Returns:
        {bool} -- True if the insert was successful; otherwise False
    """

    logger.info("Adding to DART")

    if (sql_server_connection := create_dart_sql_server_conn(config)) is not None:
        try:
            cursor = sql_server_connection.cursor()

            group_iterator: Iterator[Tuple[Any, Any]] = groupby(docs_to_insert, lambda x: x[FIELD_PLATE_BARCODE])

            for plate_barcode, samples in group_iterator:
                try:
                    samples = list(samples)
                    centre_config = centre_config_for_samples(config, samples)
                    plate_state = add_dart_plate_if_doesnt_exist(
                        cursor, plate_barcode, centre_config[CENTRE_KEY_BIOMEK_LABWARE_CLASS]
                    )
                    if plate_state == DART_STATE_PENDING:
                        for sample in samples:
                            add_dart_well_properties(cursor, sample, plate_barcode)
                    cursor.commit()
                except Exception as e:
                    logging_collection.add_error(
                        "TYPE 33",
                        f"DART database inserts failed for plate {plate_barcode} in priority samples inserts",
                    )
                    logger.exception(e)
                    # rollback statements executed since previous commit/rollback
                    cursor.rollback()
                    return False

            logger.debug("DART database inserts completed successfully for priority samples")
            return True
        except Exception as e:
            logging_collection.add_error(
                "TYPE 30",
                "DART database inserts failed for priority samples",
            )
            logger.critical(f"Critical error for priority samples: {e}")
            logger.exception(e)
            return False
        finally:
            sql_server_connection.close()
def pending_plate_barcodes_from_dart(config: Config) -> List[str]:
    """Fetch the barcodes of all plates from DART that are in the 'pending' state

    Arguments:
        config {Config} -- application config specifying database details

    Returns:
        List[str] -- barcodes of pending plates
    """
    sql_server_connection = create_dart_sql_server_conn(config)
    if sql_server_connection is None:
        # to be caught by calling method
        raise ValueError("Unable to establish DART SQL Server connection")

    plate_barcodes = []
    cursor = sql_server_connection.cursor()

    try:
        rows = cursor.execute(SQL_DART_GET_PLATE_BARCODES,
                              DART_STATE_PENDING).fetchall()
        plate_barcodes = [row[0] for row in rows]
    except Exception as e:
        logger.error("Failed fetching pending plate barcodes from DART")
        logger.exception(e)
    finally:
        sql_server_connection.close()

    return plate_barcodes
def update_dart_fields(config: Config, samples: List[SampleDoc]) -> bool:
    """Updates DART plates and wells following updates to the filtered positive fields

    Arguments:
        config {Config} -- application config specifying database details
        samples {List[Dict[str, str]]} -- the list of samples to update in DART

    Returns:
        bool -- whether the updates completed successfully
    """
    sql_server_connection = create_dart_sql_server_conn(config)
    if sql_server_connection is None:
        raise ValueError("Unable to establish DART SQL Server connection")

    dart_updated_successfully = True
    labclass_by_centre_name = biomek_labclass_by_centre_name(config.CENTRES)
    try:
        logger.info("Writing to DART")

        cursor = sql_server_connection.cursor()

        for plate_barcode, samples_in_plate in groupby_transform(
                samples,
                lambda x: x[FIELD_PLATE_BARCODE],
                reducefunc=lambda x: list(x)):
            try:
                labware_class = labclass_by_centre_name[samples_in_plate[0]
                                                        [FIELD_SOURCE]]
                plate_state = add_dart_plate_if_doesnt_exist(
                    cursor,
                    plate_barcode,
                    labware_class  # type:ignore
                )
                if plate_state == DART_STATE_PENDING:
                    for sample in samples_in_plate:
                        if sample[FIELD_RESULT] == POSITIVE_RESULT_VALUE:
                            well_index = get_dart_well_index(
                                sample.get(FIELD_COORDINATE, None))
                            if well_index is not None:
                                well_props = map_mongo_doc_to_dart_well_props(
                                    sample)
                                set_dart_well_properties(
                                    cursor,
                                    plate_barcode,
                                    well_props,
                                    well_index  # type:ignore
                                )
                            else:
                                raise ValueError(
                                    "Unable to determine DART well index for sample "
                                    f"{sample[FIELD_ROOT_SAMPLE_ID]} in plate {plate_barcode}"
                                )
                cursor.commit()
                dart_updated_successfully &= True
            except Exception as e:
                logger.error(
                    f"Failed updating DART for samples in plate {plate_barcode}"
                )
                logger.exception(e)
                cursor.rollback()
                dart_updated_successfully = False

        logger.info("Updating DART completed")
    except Exception as e:
        logger.error("Failed updating DART")
        logger.exception(e)
        dart_updated_successfully = False
    finally:
        sql_server_connection.close()

    return dart_updated_successfully
Exemple #6
0
def test_create_dart_sql_server_conn_expection(config):
    with patch("pyodbc.connect", side_effect=pyodbc.Error()):
        assert create_dart_sql_server_conn(config) is None
Exemple #7
0
def test_create_dart_sql_server_conn_none(config):
    with patch("pyodbc.connect", return_value=None):
        assert create_dart_sql_server_conn(config) is None