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}'")
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)
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
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
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