From ce04443a00b5e245fb3799067b1355ef6f22d946 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 13 Sep 2022 13:10:25 +0200 Subject: [PATCH 01/41] Remove, reviewer answer, unavailable while running --- clarity_epp/export/email.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/clarity_epp/export/email.py b/clarity_epp/export/email.py index addf6c1..c27a9bc 100644 --- a/clarity_epp/export/email.py +++ b/clarity_epp/export/email.py @@ -22,7 +22,12 @@ def sequencing_run(lims, email_settings, process_id): if process.step.actions.escalation: message += "\nManager Review LIMS:\n" - message += "{0}: {1}\n".format(process.step.actions.escalation['author'].name, process.step.actions.escalation['request']) - message += "{0}: {1}\n".format(process.step.actions.escalation['reviewer'].name, process.step.actions.escalation['answer']) - - send_email(email_settings['server'], email_settings['from'], email_settings['to_sequencing_run_complete'], subject, message) + message += "{0}: {1}\n".format( + process.step.actions.escalation['author'].name, + process.step.actions.escalation['request'] + ) + + send_email( + email_settings['server'], email_settings['from'], email_settings['to_sequencing_run_complete'], + subject, message + ) From 6b6f0f0f3e7f1cdca74f310f554c6557be2ac552 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Wed, 12 Oct 2022 11:06:36 +0200 Subject: [PATCH 02/41] Add tecan purify_normalise samplesheet --- clarity_epp/export/tecan.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/clarity_epp/export/tecan.py b/clarity_epp/export/tecan.py index e444c23..a47ab2f 100755 --- a/clarity_epp/export/tecan.py +++ b/clarity_epp/export/tecan.py @@ -5,9 +5,8 @@ import clarity_epp.export.utils -def samplesheet(lims, process_id, output_file): +def samplesheet_qc(lims, process_id, type, output_file): """Create Tecan samplesheet.""" - output_file.write('Position\tSample\n') process = Process(lims, id=process_id) well_plate = {} @@ -18,8 +17,18 @@ def samplesheet(lims, process_id, output_file): else: well_plate[placement] = artifact.name - for well in clarity_epp.export.utils.sort_96_well_plate(well_plate.keys()): - output_file.write('{well}\t{sample}\n'.format( - well=well, - sample=well_plate[well] - )) + if type == 'qc': + output_file.write('Position\tSample\n') + for well in clarity_epp.export.utils.sort_96_well_plate(well_plate.keys()): + output_file.write('{well}\t{sample}\n'.format( + well=well, + sample=well_plate[well] + )) + + elif type == 'purify_normalise': + output_file.write('Sample\tPosition\n') + for well in clarity_epp.export.utils.sort_96_well_plate(well_plate.keys()): + output_file.write('{sample}\t{well}\n'.format( + sample=well_plate[well], + well=well + )) \ No newline at end of file From 64d4cbc9a16001b6126b8b9034b093eb69147eb7 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Wed, 12 Oct 2022 11:07:06 +0200 Subject: [PATCH 03/41] Add tecan purify_normalise samplesheet --- clarity_epp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clarity_epp.py b/clarity_epp.py index 86eb90d..2c69795 100755 --- a/clarity_epp.py +++ b/clarity_epp.py @@ -128,7 +128,7 @@ def export_tapestation(args): def export_tecan(args): """Export samplesheets for tecan machine.""" - clarity_epp.export.tecan.samplesheet(lims, args.process_id, args.output_file) + clarity_epp.export.tecan.samplesheet(lims, args.process_id, args.type, args.output_file) def export_workflow(args): @@ -330,6 +330,7 @@ def placement_complete_step(args): parser_export_tecan = subparser_export.add_parser('tecan', help='Create tecan samplesheets', parents=[output_parser]) parser_export_tecan.add_argument('process_id', help='Clarity lims process id') + parser_export_tecan.add_argument('type', choices=['qc', 'purify_normalise'], help='Samplesheet type') parser_export_tecan.set_defaults(func=export_tecan) parser_export_workflow = subparser_export.add_parser( From 4f26923342568eda7d9766f785af1f4e71cb72c8 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Wed, 12 Oct 2022 11:11:37 +0200 Subject: [PATCH 04/41] Fix function name --- clarity_epp/export/tecan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clarity_epp/export/tecan.py b/clarity_epp/export/tecan.py index a47ab2f..0eddeeb 100755 --- a/clarity_epp/export/tecan.py +++ b/clarity_epp/export/tecan.py @@ -5,7 +5,7 @@ import clarity_epp.export.utils -def samplesheet_qc(lims, process_id, type, output_file): +def samplesheet(lims, process_id, type, output_file): """Create Tecan samplesheet.""" process = Process(lims, id=process_id) well_plate = {} From 43a10f9782176ce2fbed3a2a59415de7c031280d Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Wed, 12 Oct 2022 16:54:51 +0200 Subject: [PATCH 05/41] Add placement script for tecan --- clarity_epp.py | 9 ++++++ clarity_epp/placement/__init__.py | 1 + clarity_epp/placement/tecan.py | 50 +++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 clarity_epp/placement/tecan.py diff --git a/clarity_epp.py b/clarity_epp.py index 2c69795..a4d3fbe 100755 --- a/clarity_epp.py +++ b/clarity_epp.py @@ -221,6 +221,11 @@ def placement_complete_step(args): clarity_epp.placement.step.finish_protocol_complete(lims, args.process_id) +def placement_tecan(args): + """Placement tecan process, distribute artifacts over two containers""" + clarity_epp.placement.tecan.place_samples(lims, args.process_id) + + if __name__ == "__main__": parser = argparse.ArgumentParser() subparser = parser.add_subparsers() @@ -419,5 +424,9 @@ def placement_complete_step(args): parser_placement_unpooling.add_argument('process_id', help='Clarity lims process id') parser_placement_unpooling.set_defaults(func=placement_unpooling) + parser_placement_tecan = subparser_placement.add_parser('tecan', help='Placement of samples in tecan step') + parser_placement_tecan.add_argument('process_id', help='Clarity lims process id') + parser_placement_tecan.set_defaults(func=placement_tecan) + args = parser.parse_args() args.func(args) diff --git a/clarity_epp/placement/__init__.py b/clarity_epp/placement/__init__.py index 6c6bff7..f5f088d 100644 --- a/clarity_epp/placement/__init__.py +++ b/clarity_epp/placement/__init__.py @@ -5,3 +5,4 @@ import clarity_epp.placement.plate import clarity_epp.placement.pool import clarity_epp.placement.step +import clarity_epp.placement.tecan \ No newline at end of file diff --git a/clarity_epp/placement/tecan.py b/clarity_epp/placement/tecan.py new file mode 100644 index 0000000..ae00f07 --- /dev/null +++ b/clarity_epp/placement/tecan.py @@ -0,0 +1,50 @@ +from genologics.entities import Process, Container, Containertype + + +def get_well_location(index): + locations = [ + 'A:1', 'B:1', 'C:1', 'D:1', 'E:1', 'F:1', 'G:1', 'H:1', + 'A:2', 'B:2', 'C:2', 'D:2', 'E:2', 'F:2', 'G:2', 'H:2', + 'A:3', 'B:3', 'C:3', 'D:3', 'E:3', 'F:3', 'G:3', 'H:3', + 'A:4', 'B:4', 'C:4', 'D:4', 'E:4', 'F:4', 'G:4', 'H:4', + 'A:5', 'B:5', 'C:5', 'D:5', 'E:5', 'F:5', 'G:5', 'H:5', + 'A:6', 'B:6', 'C:6', 'D:6', 'E:6', 'F:6', 'G:6', 'H:6', + 'A:7', 'B:7', 'C:7', 'D:7', 'E:7', 'F:7', 'G:7', 'H:7', + 'A:8', 'B:8', 'C:8', 'D:8', 'E:8', 'F:8', 'G:8', 'H:8', + 'A:9', 'B:9', 'C:9', 'D:9', 'E:9', 'F:9', 'G:9', 'H:9', + 'A:10', 'B:10', 'C:10', 'D:10', 'E:10', 'F:10', 'G:10', 'H:10', + 'A:11', 'B:11', 'C:11', 'D:11', 'E:11', 'F:11', 'G:11', 'H:11', + 'A:12', 'B:12', 'C:12', 'D:12', 'E:12', 'F:12', 'G:12', 'H:12' + ] + return locations[index] + + +def place_artifacts(lims, process_id): + """Place artifacts on two containers, 2 artifacts per sample.""" + process = Process(lims, id=process_id) + + # Create containers + well_plate = Containertype(lims, id='1') + purify_container = Container.create(lims, type=well_plate) + normalise_container = Container.create(lims, type=well_plate) + purify_container.name = f"zuiveren_{purify_container.name}" + normalise_container.name = f"normaliseren_{normalise_container.name}" + purify_container.put() + normalise_container.put() + + # Keep track of placements + purify_container_placement = [] + normalise_container_placement = [] + placement_list = [] + + # Place all artifacts + for artifact in process.analytes()[0]: + if artifact.name not in purify_container_placement: + placement_list.append([artifact, (purify_container, get_well_location(len(purify_container_placement)))]) + purify_container_placement.append(artifact.name) + else: + placement_list.append([artifact, (normalise_container, get_well_location(len(normalise_container_placement)))]) + normalise_container_placement.append(artifact.name) + + process.step.placements.set_placement_list(placement_list) + process.step.placements.post() From fe7a1f802ac5707746f94089bbd8e6c2534b0570 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Wed, 12 Oct 2022 16:58:07 +0200 Subject: [PATCH 06/41] Fix function name --- clarity_epp.py | 2 +- clarity_epp/placement/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clarity_epp.py b/clarity_epp.py index a4d3fbe..6f80200 100755 --- a/clarity_epp.py +++ b/clarity_epp.py @@ -223,7 +223,7 @@ def placement_complete_step(args): def placement_tecan(args): """Placement tecan process, distribute artifacts over two containers""" - clarity_epp.placement.tecan.place_samples(lims, args.process_id) + clarity_epp.placement.tecan.place_artifacts(lims, args.process_id) if __name__ == "__main__": diff --git a/clarity_epp/placement/__init__.py b/clarity_epp/placement/__init__.py index f5f088d..c9d5394 100644 --- a/clarity_epp/placement/__init__.py +++ b/clarity_epp/placement/__init__.py @@ -5,4 +5,4 @@ import clarity_epp.placement.plate import clarity_epp.placement.pool import clarity_epp.placement.step -import clarity_epp.placement.tecan \ No newline at end of file +import clarity_epp.placement.tecan From 36b67b2fc29467b6c6f4512718ac684fb876176c Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Wed, 12 Oct 2022 16:59:43 +0200 Subject: [PATCH 07/41] Remove f string --- clarity_epp/placement/tecan.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clarity_epp/placement/tecan.py b/clarity_epp/placement/tecan.py index ae00f07..0943602 100644 --- a/clarity_epp/placement/tecan.py +++ b/clarity_epp/placement/tecan.py @@ -27,8 +27,8 @@ def place_artifacts(lims, process_id): well_plate = Containertype(lims, id='1') purify_container = Container.create(lims, type=well_plate) normalise_container = Container.create(lims, type=well_plate) - purify_container.name = f"zuiveren_{purify_container.name}" - normalise_container.name = f"normaliseren_{normalise_container.name}" + purify_container.name = "zuiveren_{id}".format(id=purify_container.name) + normalise_container.name = "normaliseren_{id}".format(id=normalise_container.name) purify_container.put() normalise_container.put() From fd0b5e5377af89943f3a51ffc2361b7dcd19eb85 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Thu, 13 Oct 2022 10:42:07 +0200 Subject: [PATCH 08/41] Make sure samples are set to same well location --- clarity_epp/placement/tecan.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clarity_epp/placement/tecan.py b/clarity_epp/placement/tecan.py index 0943602..b8a2c9b 100644 --- a/clarity_epp/placement/tecan.py +++ b/clarity_epp/placement/tecan.py @@ -33,18 +33,18 @@ def place_artifacts(lims, process_id): normalise_container.put() # Keep track of placements - purify_container_placement = [] - normalise_container_placement = [] + container_placement = {} placement_list = [] # Place all artifacts for artifact in process.analytes()[0]: - if artifact.name not in purify_container_placement: - placement_list.append([artifact, (purify_container, get_well_location(len(purify_container_placement)))]) - purify_container_placement.append(artifact.name) - else: - placement_list.append([artifact, (normalise_container, get_well_location(len(normalise_container_placement)))]) - normalise_container_placement.append(artifact.name) + if artifact.name not in container_placement: # Add first artifact to purify_container + well_location = get_well_location(len(container_placement)) + placement_list.append([artifact, (purify_container, well_location)]) + container_placement[artifact.name] = well_location + else: # Add second artifact to normalise_container on same position + well_location = container_placement[artifact.name] + placement_list.append([artifact, (normalise_container, well_location)]) process.step.placements.set_placement_list(placement_list) process.step.placements.post() From e6553761f1c63c858c0aa7a7544b7a01298079ed Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 25 Oct 2022 16:04:59 +0200 Subject: [PATCH 09/41] Update tecan samplesheet --- clarity_epp/export/tecan.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/clarity_epp/export/tecan.py b/clarity_epp/export/tecan.py index 0eddeeb..b6bfd3b 100755 --- a/clarity_epp/export/tecan.py +++ b/clarity_epp/export/tecan.py @@ -12,23 +12,28 @@ def samplesheet(lims, process_id, type, output_file): for placement, artifact in process.output_containers()[0].placements.items(): placement = ''.join(placement.split(':')) - if len(artifact.samples) == 1: # Remove 'meet_id' from artifact name if artifact is not a pool - well_plate[placement] = artifact.name.split('_')[0] - else: - well_plate[placement] = artifact.name + well_plate[placement] = artifact if type == 'qc': output_file.write('Position\tSample\n') for well in clarity_epp.export.utils.sort_96_well_plate(well_plate.keys()): - output_file.write('{well}\t{sample}\n'.format( + # Set correct artifact name + artifact = well_plate[well] + if len(artifact.samples) == 1: + artifact_name = artifact.name.split('_')[0] + else: + artifact_name = artifact.name + + output_file.write('{well}\t{artifact}\n'.format( well=well, - sample=well_plate[well] + artifact=artifact_name )) elif type == 'purify_normalise': - output_file.write('Sample\tPosition\n') + output_file.write('SourceTubeID\tPositionID\n') for well in clarity_epp.export.utils.sort_96_well_plate(well_plate.keys()): + sample = artifact.samples[0] # assume one sample per tube output_file.write('{sample}\t{well}\n'.format( - sample=well_plate[well], + sample=sample.udf['Dx Fractienummer'], well=well )) \ No newline at end of file From 06affc5342cda01626d6be9827cbd94c6c8fef6a Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 25 Oct 2022 16:21:36 +0200 Subject: [PATCH 10/41] Use final_volume to correct for s1/s2/s4 volume differences --- clarity_epp/export/manual_pipetting.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clarity_epp/export/manual_pipetting.py b/clarity_epp/export/manual_pipetting.py index 70a2dd4..01dbf5d 100755 --- a/clarity_epp/export/manual_pipetting.py +++ b/clarity_epp/export/manual_pipetting.py @@ -311,6 +311,7 @@ def samplesheet_multiplex_sequence_pool(lims, process_id, output_file): input_pools = [] total_sample_count = 0 total_load_uL = 0 + final_volume = float(process.udf['Final volume'].split()[0]) for input_pool in process.all_inputs(): input_pool_conc = float(input_pool.udf['Dx Concentratie fluorescentie (ng/ul)']) @@ -339,11 +340,11 @@ def samplesheet_multiplex_sequence_pool(lims, process_id, output_file): # Last calcuations and print sample for input_pool in input_pools: input_pool_load_pM = (float(process.udf['Dx Laadconcentratie (pM)'])/total_sample_count) * input_pool['sample_count'] - input_pool_load_uL = 150.0 / (input_pool['pM']/input_pool_load_pM) + input_pool_load_uL = final_volume / (input_pool['pM']/input_pool_load_pM) total_load_uL += input_pool_load_uL output_file.write('{0}\t{1:.2f}\n'.format(input_pool['name'], input_pool_load_uL)) - tris_HCL_uL = 150 - total_load_uL + tris_HCL_uL = final_volume - total_load_uL output_file.write('{0}\t{1:.2f}\n'.format('Tris-HCL', tris_HCL_uL)) From d69a47aa6a9b21e58394ccd9a766576099b283ce Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 25 Oct 2022 16:52:15 +0200 Subject: [PATCH 11/41] Update overmaat to 30% --- clarity_epp/export/manual_pipetting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clarity_epp/export/manual_pipetting.py b/clarity_epp/export/manual_pipetting.py index 01dbf5d..6917034 100755 --- a/clarity_epp/export/manual_pipetting.py +++ b/clarity_epp/export/manual_pipetting.py @@ -456,11 +456,11 @@ def sammplesheet_exonuclease(lims, process_id, output_file): # Caculate for sample count for i, item in enumerate(data): - data[i].append(sample_count * item[1] * 1.25) + data[i].append(sample_count * item[1] * 1.30) # Calculate total data.append([ - 'TOTAL (incl. 25% overmaat)', + 'TOTAL (incl. 30% overmaat)', sum([item[1] for item in data]), sum([item[2] for item in data]), ]) From 3c29bfa60089f7450486166aec463c16cee90e72 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 25 Oct 2022 16:55:17 +0200 Subject: [PATCH 12/41] Update volume mip_multiplex_pool --- clarity_epp/export/manual_pipetting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clarity_epp/export/manual_pipetting.py b/clarity_epp/export/manual_pipetting.py index 6917034..6bba8c5 100755 --- a/clarity_epp/export/manual_pipetting.py +++ b/clarity_epp/export/manual_pipetting.py @@ -556,9 +556,9 @@ def samplesheet_mip_multiplex_pool(lims, process_id, output_file): if input_artifact['concentration'] < avg_concentration * 0.5: input_artifact['volume'] = 20 elif input_artifact['concentration'] > avg_concentration * 1.5: - input_artifact['volume'] = 2 + input_artifact['volume'] = 1 else: - input_artifact['volume'] = 5 + input_artifact['volume'] = 2 if input_artifact['plate_id'] not in input_containers: input_containers[input_artifact['plate_id']] = {} From b4832ac320315428f2fd82e126245a5c03a38a5c Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Thu, 27 Oct 2022 15:18:13 +0200 Subject: [PATCH 13/41] Update storage location label --- clarity_epp/export/labels.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/clarity_epp/export/labels.py b/clarity_epp/export/labels.py index a514fb0..f63ae8f 100644 --- a/clarity_epp/export/labels.py +++ b/clarity_epp/export/labels.py @@ -30,10 +30,13 @@ def container_sample(lims, process_id, output_file, description=''): def storage_location(lims, process_id, output_file): """Generate storage location label file.""" process = Process(lims, id=process_id) + + # Write header + output_file.write('Bakje\tpos\n') + for artifact in process.analytes()[0]: - storage_location = artifact.samples[0].udf['Dx Opslaglocatie'] - output_file.write('{sample}\t{storage_location}\t{birth_date}\n'.format( - sample=artifact.samples[0].name, - storage_location=storage_location, - birth_date=artifact.samples[0].udf['Dx Geboortejaar'] + storage_location = artifact.samples[0].udf['Dx Opslaglocatie'].split() + output_file.write('{tray}\t{pos}\n'.format( + tray=storage_location[0][2:6], # Select 4 digits from: CB[1-9][1-9][1-9][1-9]KK + pos=storage_location[1] )) From 7fe5b52f601369b807448211be8a44d46f7709c8 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Fri, 28 Oct 2022 15:24:31 +0200 Subject: [PATCH 14/41] pep8 --- clarity_epp/export/utils.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/clarity_epp/export/utils.py b/clarity_epp/export/utils.py index 7bf6a25..4132edd 100755 --- a/clarity_epp/export/utils.py +++ b/clarity_epp/export/utils.py @@ -9,11 +9,18 @@ def sort_96_well_plate(wells): """ order = [ - 'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', - 'H3', 'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'A6', 'B6', 'C6', 'D6', 'E6', 'F6', - 'G6', 'H6', 'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'A9', 'B9', 'C9', 'D9', 'E9', - 'F9', 'G9', 'H9', 'A10', 'B10', 'C10', 'D10', 'E10', 'F10', 'G10', 'H10', 'A11', 'B11', 'C11', 'D11', 'E11', 'F11', 'G11', 'H11', 'A12', - 'B12', 'C12', 'D12', 'E12', 'F12', 'G12', 'H12' + 'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', + 'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', + 'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', + 'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', + 'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', + 'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', + 'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', + 'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', + 'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', + 'A10', 'B10', 'C10', 'D10', 'E10', 'F10', 'G10', 'H10', + 'A11', 'B11', 'C11', 'D11', 'E11', 'F11', 'G11', 'H11', + 'A12', 'B12', 'C12', 'D12', 'E12', 'F12', 'G12', 'H12' ] order = dict(zip(order, range(len(order)))) From 3ca901d00ef8a17d95ceab6b8bdeed3b49c2ca34 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Fri, 28 Oct 2022 15:30:41 +0200 Subject: [PATCH 15/41] Add index --- clarity_epp/export/tecan.py | 7 ++++--- clarity_epp/export/utils.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/clarity_epp/export/tecan.py b/clarity_epp/export/tecan.py index b6bfd3b..54bc0de 100755 --- a/clarity_epp/export/tecan.py +++ b/clarity_epp/export/tecan.py @@ -30,10 +30,11 @@ def samplesheet(lims, process_id, type, output_file): )) elif type == 'purify_normalise': - output_file.write('SourceTubeID\tPositionID\n') + output_file.write('SourceTubeID\tPositionID\tPositionIndex\n') for well in clarity_epp.export.utils.sort_96_well_plate(well_plate.keys()): sample = artifact.samples[0] # assume one sample per tube - output_file.write('{sample}\t{well}\n'.format( + output_file.write('{sample}\t{well}\t{index}\n'.format( sample=sample.udf['Dx Fractienummer'], - well=well + well=well, + index=clarity_epp.export.utils.get_well_index(well, one_based=True) )) \ No newline at end of file diff --git a/clarity_epp/export/utils.py b/clarity_epp/export/utils.py index 4132edd..1f9d20c 100755 --- a/clarity_epp/export/utils.py +++ b/clarity_epp/export/utils.py @@ -56,3 +56,31 @@ def get_process_types(lims, process_types_names): process_types.append(process_type.name) return process_types + + +def get_well_index(well, one_based=False): + """Return well index + + Arguments: + well -- well str: 'A1' + + """ + wells = [ + 'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', + 'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', + 'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', + 'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', + 'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', + 'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', + 'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', + 'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', + 'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', + 'A10', 'B10', 'C10', 'D10', 'E10', 'F10', 'G10', 'H10', + 'A11', 'B11', 'C11', 'D11', 'E11', 'F11', 'G11', 'H11', + 'A12', 'B12', 'C12', 'D12', 'E12', 'F12', 'G12', 'H12' + ] + + if one_based: + return wells.index(well) + 1 + else: + return wells.index(well) From 009a6ea608b426fd9f0fb49eaf84381c4c6fe7ee Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 8 Nov 2022 12:45:29 +0100 Subject: [PATCH 16/41] Fix trio parsing --- clarity_epp/placement/artifact.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/clarity_epp/placement/artifact.py b/clarity_epp/placement/artifact.py index fb028a7..8963ea7 100644 --- a/clarity_epp/placement/artifact.py +++ b/clarity_epp/placement/artifact.py @@ -54,12 +54,25 @@ def route_to_workflow(lims, process_id, workflow): # Remove research artifacts if sample.udf['Dx Stoftest code'] != config.stoftestcode_research: - # Find trio - if( - sample.udf['Dx Familie status'] == 'Ouder' - or ('Dx Gerelateerde onderzoeken' in sample.udf and sample.udf['Dx Gerelateerde onderzoeken']) + # Lookup trio samples + # if parent check family members if parent belongs to trio + if sample.udf['Dx Familie status'] == 'Ouder': + parent_status = 'single' + for family_sample in lims.get_samples(udf={'Dx Familienummer': sample.udf['Dx Familienummer']}): + if( + 'Dx Gerelateerde onderzoeken' in family_sample.udf + and sample.udf['Dx Onderzoeknummer'] in family_sample.udf['Dx Gerelateerde onderzoeken'] + and len(family_sample.udf['Dx Gerelateerde onderzoeken'].split(';')) >= 2 + ): + parent_status = 'trio' + stoftest_artifacts[sample.udf['Dx Stoftest code']][parent_status].append(artifact) + # If child check if part of trio + elif( + 'Dx Gerelateerde onderzoeken' in sample.udf + and len(sample.udf['Dx Gerelateerde onderzoeken'].split(';')) >= 2 ): stoftest_artifacts[sample.udf['Dx Stoftest code']]['trio'].append(artifact) + # Else not trio else: stoftest_artifacts[sample.udf['Dx Stoftest code']]['single'].append(artifact) From 4cc9735ffc8f9b14e5baf4fcfa3d5f1ed07385fe Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 8 Nov 2022 12:53:09 +0100 Subject: [PATCH 17/41] Sort magnis pools by id --- clarity_epp/export/manual_pipetting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clarity_epp/export/manual_pipetting.py b/clarity_epp/export/manual_pipetting.py index 6bba8c5..2ca0b0f 100755 --- a/clarity_epp/export/manual_pipetting.py +++ b/clarity_epp/export/manual_pipetting.py @@ -668,7 +668,7 @@ def samplesheet_pool_magnis_pools(lims, process_id, output_file): output_file.write('Pool\tContainer\tSample count\tVolume (ul)\n') # Get input pools, sort by name and print volume - for input_artifact in sorted(process.all_inputs(resolve=True), key=lambda artifact: artifact.name): + for input_artifact in sorted(process.all_inputs(resolve=True), key=lambda artifact: artifact.id): sample_count = 0 for sample in input_artifact.samples: if 'Dx Exoomequivalent' in sample.udf: From 64e25f546193b201f29200aab0354f27640e76f6 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Thu, 24 Nov 2022 11:37:54 +0100 Subject: [PATCH 18/41] Fix samplesheet --- clarity_epp/export/tecan.py | 1 + 1 file changed, 1 insertion(+) diff --git a/clarity_epp/export/tecan.py b/clarity_epp/export/tecan.py index 54bc0de..c9c3c41 100755 --- a/clarity_epp/export/tecan.py +++ b/clarity_epp/export/tecan.py @@ -32,6 +32,7 @@ def samplesheet(lims, process_id, type, output_file): elif type == 'purify_normalise': output_file.write('SourceTubeID\tPositionID\tPositionIndex\n') for well in clarity_epp.export.utils.sort_96_well_plate(well_plate.keys()): + artifact = well_plate[well] sample = artifact.samples[0] # assume one sample per tube output_file.write('{sample}\t{well}\t{index}\n'.format( sample=sample.udf['Dx Fractienummer'], From 8149a488c37e2de5c87f737a24cd99df99d69034 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Thu, 24 Nov 2022 13:44:03 +0100 Subject: [PATCH 19/41] Add results_purify_normalise --- clarity_epp.py | 6 +++++- clarity_epp/upload/samples.py | 2 +- clarity_epp/upload/tecan.py | 30 +++++++++++++++++++++++++++++- clarity_epp/upload/utils.py | 12 ++++++++---- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/clarity_epp.py b/clarity_epp.py index 6f80200..dfc4ee6 100755 --- a/clarity_epp.py +++ b/clarity_epp.py @@ -147,7 +147,10 @@ def upload_samples(args): def upload_tecan_results(args): """Upload tecan results.""" - clarity_epp.upload.tecan.results(lims, args.process_id) + if args.type == 'qc': + clarity_epp.upload.tecan.results_qc(lims, args.process_id) + elif args.type == 'purify_normalise': + clarity_epp.upload.tecan.results_purify_normalise(lims, args.process_id) def upload_tapestation_results(args): @@ -363,6 +366,7 @@ def placement_tecan(args): parser_upload_tecan = subparser_upload.add_parser('tecan', help='Upload tecan results') parser_upload_tecan.add_argument('process_id', help='Clarity lims process id') + parser_upload_tecan.add_argument('type', choices=['qc', 'purify_normalise'], help='Tecan process type') parser_upload_tecan.set_defaults(func=upload_tecan_results) parser_upload_magnis = subparser_upload.add_parser('magnis', help='Upload magnis results') diff --git a/clarity_epp/upload/samples.py b/clarity_epp/upload/samples.py index 48c7ceb..ae42af0 100644 --- a/clarity_epp/upload/samples.py +++ b/clarity_epp/upload/samples.py @@ -91,7 +91,7 @@ def from_helix(lims, email_settings, input_file): for udf in udf_column: # Transform specific udf if udf in ['Dx Overleden', 'Dx Spoed', 'Dx NICU Spoed']: - udf_data[udf] = clarity_epp.upload.utils.char_to_bool(data[udf_column[udf]['index']]) + udf_data[udf] = clarity_epp.upload.utils.txt_to_bool(data[udf_column[udf]['index']]) elif udf in ['Dx Geslacht', 'Dx Foetus geslacht']: udf_data[udf] = clarity_epp.upload.utils.transform_sex(data[udf_column[udf]['index']]) elif udf == 'Dx Foetus': diff --git a/clarity_epp/upload/tecan.py b/clarity_epp/upload/tecan.py index 4ab8222..712105d 100644 --- a/clarity_epp/upload/tecan.py +++ b/clarity_epp/upload/tecan.py @@ -4,8 +4,10 @@ from genologics.entities import Process +from clarity_epp.upload.utils import txt_to_bool -def results(lims, process_id): + +def results_qc(lims, process_id): """Upload tecan results to artifacts.""" process = Process(lims, id=process_id) concentration_range = map(float, re.findall('[\d\.]+', process.udf['Concentratiebereik (ng/ul)'])) @@ -108,3 +110,29 @@ def results(lims, process_id): artifact.qc_flag = 'FAILED' artifact.put() + + +def results_purify_normalise(lims, process_id): + """Upload tecan results to artifacts.""" + process = Process(lims, id=process_id) + + # Find and parse Tecan Fluent 480 Output + tecan_result = {} + for result_file in process.result_files(): + if result_file.name == 'Tecan Fluent 480 Output': + file_data = lims.get_file_contents(result_file.files[0].id).split('\n') + header = file_data[0].rstrip().split(',') + for line in file_data[1:]: + data = line.rstrip().split(',') + tecan_result[data[header.index('SampleID')]] = { + 'conc': float(data[header.index('Concentratie')]), + 'norm': txt_to_bool(data[header.index('Normalisatie')]) + } + break # File found exit loop + + # Set concentration values on artifacts + for artifact in process.analytes()[0]: + sample = artifact.samples[0] # assume one sample per artifact + artifact.udf['Dx Concentratie fluorescentie (ng/ul)'] = tecan_result[sample.udf['Dx Fractienummer']]['conc'] + artifact.udf['Dx QC status'] = tecan_result[sample.udf['Dx Fractienummer']]['norm'] + artifact.put() diff --git a/clarity_epp/upload/utils.py b/clarity_epp/upload/utils.py index 6b2078b..cb35aa3 100644 --- a/clarity_epp/upload/utils.py +++ b/clarity_epp/upload/utils.py @@ -4,14 +4,18 @@ import config -def char_to_bool(letter): +def txt_to_bool(txt): """Transform character (J/N) to Bool.""" - if letter.upper() == 'J': + if txt.upper() == 'J': return True - elif letter.upper() == 'N': + elif txt.upper() == 'N': + return False + elif txt.upper() == "TRUE": + return True + elif txt.upper() == "FALSE": return False else: - raise ValueError('Invalid character, only J or N allowed.') + raise ValueError('Invalid text, only J, N, TRUE or FALSE allowed.') def transform_sex(value): From 0ca569dda2cea9e5a8884b8adb0034442aee0dde Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Thu, 24 Nov 2022 13:55:13 +0100 Subject: [PATCH 20/41] pep8 --- clarity_epp/export/tecan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clarity_epp/export/tecan.py b/clarity_epp/export/tecan.py index c9c3c41..ccc9d34 100755 --- a/clarity_epp/export/tecan.py +++ b/clarity_epp/export/tecan.py @@ -38,4 +38,4 @@ def samplesheet(lims, process_id, type, output_file): sample=sample.udf['Dx Fractienummer'], well=well, index=clarity_epp.export.utils.get_well_index(well, one_based=True) - )) \ No newline at end of file + )) From cf8581d5e88e73c5a43a0f933a1a5c78756534d8 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Thu, 24 Nov 2022 14:54:33 +0100 Subject: [PATCH 21/41] Change seperator --- clarity_epp/upload/tecan.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clarity_epp/upload/tecan.py b/clarity_epp/upload/tecan.py index 712105d..a10db71 100644 --- a/clarity_epp/upload/tecan.py +++ b/clarity_epp/upload/tecan.py @@ -121,9 +121,9 @@ def results_purify_normalise(lims, process_id): for result_file in process.result_files(): if result_file.name == 'Tecan Fluent 480 Output': file_data = lims.get_file_contents(result_file.files[0].id).split('\n') - header = file_data[0].rstrip().split(',') + header = file_data[0].rstrip().split(';') for line in file_data[1:]: - data = line.rstrip().split(',') + data = line.rstrip().split(';') tecan_result[data[header.index('SampleID')]] = { 'conc': float(data[header.index('Concentratie')]), 'norm': txt_to_bool(data[header.index('Normalisatie')]) From f685524f67c0a90ee514861d7e59c1b7d9f4f91d Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Thu, 24 Nov 2022 16:04:05 +0100 Subject: [PATCH 22/41] Add tests for utils --- .github/workflows/python.yml | 44 ++++++++++++++++++++++++++++++++++++ tests/__init__.py | 0 tests/test_export_utils.py | 23 +++++++++++++++++++ tests/test_upload_utils.py | 18 +++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 .github/workflows/python.yml create mode 100644 tests/__init__.py create mode 100644 tests/test_export_utils.py create mode 100644 tests/test_upload_utils.py diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml new file mode 100644 index 0000000..227ceca --- /dev/null +++ b/.github/workflows/python.yml @@ -0,0 +1,44 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python (flake8, pytest) + +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [3.6] + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: "Install Apache package" + run: sudo apt install -y apache2-dev + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_export_utils.py b/tests/test_export_utils.py new file mode 100644 index 0000000..70bfea8 --- /dev/null +++ b/tests/test_export_utils.py @@ -0,0 +1,23 @@ +from genologics.lims import Lims +from genologics.entities import Artifact + +from clarity_epp.export import utils + + +def test_sort_96_well_plate(): + assert utils.sort_96_well_plate(['B2', 'A1', 'E1']) == ['A1', 'E1', 'B2'] + + +def test_reverse_complement(): + assert utils.reverse_complement('CGTA') == 'TACG' + + +def test_sort_artifact_list(): + lims = Lims('url', username='test', password='password') + artifact = Artifact(lims, id='12-456') + assert utils.sort_artifact_list(artifact) == 456 + + +def test_get_well_index(): + assert utils.get_well_index('A1') == 0 + assert utils.get_well_index('A1', one_based=True) == 1 diff --git a/tests/test_upload_utils.py b/tests/test_upload_utils.py new file mode 100644 index 0000000..f816eec --- /dev/null +++ b/tests/test_upload_utils.py @@ -0,0 +1,18 @@ +from clarity_epp.upload import utils + + +def test_txt_to_bool(): + assert utils.txt_to_bool('J') + assert not utils.txt_to_bool('N') + assert utils.txt_to_bool('TRUE') + assert not utils.txt_to_bool('FALSE') + + +def test_transform_sex(): + assert utils.transform_sex('M') == 'Man' + assert utils.transform_sex('V') == 'Vrouw' + assert utils.transform_sex('O') == 'Onbekend' + + +def test_transform_sample_name(): + assert utils.transform_sample_name('D01/2016') == 'D012016' From 91ce163218db48045aedace5c0d854b31836053d Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 17 Jan 2023 11:18:41 +0100 Subject: [PATCH 23/41] Replace special chars with '-' --- templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv | 2 +- templates/NovaSeq_BCL2FASTQ_Samplesheet.csv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv b/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv index e0eb5a8..67ca2ff 100644 --- a/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv +++ b/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv @@ -57,7 +57,7 @@ if (index > 0) { } ${SAMPLE.NAME##NoSpecialCharacters} -return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") +return token.replaceAll(\"[^a-zA-Z0-9\\_]\", \"-\") ${SAMPLE.PROJECT.NAME##NoSpecialCharacters} return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") diff --git a/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv b/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv index cf86d3d..f7f1936 100644 --- a/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv +++ b/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv @@ -50,7 +50,7 @@ if (index >= 0) { } ${SAMPLE.NAME##NoSpecialCharacters} -return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") +return token.replaceAll(\"[^a-zA-Z0-9\\_]\", \"-\") ${SAMPLE.PROJECT.NAME##NoSpecialCharacters} return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") From 4f6b4d624ae694fce93c40ecea481c9776896089 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 17 Jan 2023 11:23:58 +0100 Subject: [PATCH 24/41] Replace special chars with '-' --- templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv | 2 +- templates/NovaSeq_BCL2FASTQ_Samplesheet.csv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv b/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv index 67ca2ff..f2daab9 100644 --- a/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv +++ b/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv @@ -57,7 +57,7 @@ if (index > 0) { } ${SAMPLE.NAME##NoSpecialCharacters} -return token.replaceAll(\"[^a-zA-Z0-9\\_]\", \"-\") +return token.replaceAll(\"[^a-zA-Z0-9\\-]\", \"-\") ${SAMPLE.PROJECT.NAME##NoSpecialCharacters} return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") diff --git a/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv b/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv index f7f1936..49ab47e 100644 --- a/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv +++ b/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv @@ -50,7 +50,7 @@ if (index >= 0) { } ${SAMPLE.NAME##NoSpecialCharacters} -return token.replaceAll(\"[^a-zA-Z0-9\\_]\", \"-\") +return token.replaceAll(\"[^a-zA-Z0-9\\-]\", \"-\") ${SAMPLE.PROJECT.NAME##NoSpecialCharacters} return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") From e731b58fd2780cc4550578dbd0ae333d2e6a0985 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 17 Jan 2023 11:27:52 +0100 Subject: [PATCH 25/41] Replace special chars with '-' --- templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv | 2 +- templates/NovaSeq_BCL2FASTQ_Samplesheet.csv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv b/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv index f2daab9..cd08a8e 100644 --- a/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv +++ b/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv @@ -57,7 +57,7 @@ if (index > 0) { } ${SAMPLE.NAME##NoSpecialCharacters} -return token.replaceAll(\"[^a-zA-Z0-9\\-]\", \"-\") +return token.replaceAll(\"[^a-zA-Z0-9-]\", \"-\") ${SAMPLE.PROJECT.NAME##NoSpecialCharacters} return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") diff --git a/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv b/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv index 49ab47e..cc02f7f 100644 --- a/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv +++ b/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv @@ -50,7 +50,7 @@ if (index >= 0) { } ${SAMPLE.NAME##NoSpecialCharacters} -return token.replaceAll(\"[^a-zA-Z0-9\\-]\", \"-\") +return token.replaceAll(\"[^a-zA-Z0-9-]\", \"-\") ${SAMPLE.PROJECT.NAME##NoSpecialCharacters} return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") From 6b3274b03648b80eba94a08e822d93527ebd9ecc Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 17 Jan 2023 12:07:47 +0100 Subject: [PATCH 26/41] Fallback on previous process if qc process not found --- clarity_epp/export/manual_pipetting.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/clarity_epp/export/manual_pipetting.py b/clarity_epp/export/manual_pipetting.py index 2ca0b0f..d9a1346 100755 --- a/clarity_epp/export/manual_pipetting.py +++ b/clarity_epp/export/manual_pipetting.py @@ -364,13 +364,19 @@ def samplesheet_normalization(lims, process_id, output_file): sample = input_artifact.samples[0] # asume one sample per input artifact # Find last qc process for artifact - qc_process = sorted( - lims.get_processes(type=qc_process_types, inputartifactlimsid=input_artifact.id), - key=lambda process: int(process.id.split('-')[-1]) - )[-1] + qc_process = lims.get_processes(type=qc_process_types, inputartifactlimsid=input_artifact.id) + if qc_process: + qc_process = sorted( + lims.get_processes(type=qc_process_types, inputartifactlimsid=input_artifact.id), + key=lambda process: int(process.id.split('-')[-1]) + )[-1] + qc_artifacts = qc_process.outputs_per_input(input_artifact.id) + else: # Fallback on previous process if qc process not found. + qc_process = input_artifact.parent_process + qc_artifacts = qc_process.all_outputs() # Find concentration measurement - for qc_artifact in qc_process.outputs_per_input(input_artifact.id): + for qc_artifact in qc_artifacts: if qc_artifact.name.split(' ')[0] == artifact.name: concentration = float(qc_artifact.udf['Dx Concentratie fluorescentie (ng/ul)']) @@ -378,6 +384,7 @@ def samplesheet_normalization(lims, process_id, output_file): input_ng = float(artifact.udf['Dx Input (ng)']) if 'Dx pipetteervolume (ul)' in artifact.udf: input_ng = concentration * float(artifact.udf['Dx pipetteervolume (ul)']) + sample_volume = input_ng / concentration water_volume = final_volume - sample_volume evaporate = 'N' From aa8ca48cd753a83328648e3f878d283d9878019e Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 17 Jan 2023 15:26:26 +0100 Subject: [PATCH 27/41] Change output to csv --- clarity_epp/export/tecan.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clarity_epp/export/tecan.py b/clarity_epp/export/tecan.py index ccc9d34..1b61de0 100755 --- a/clarity_epp/export/tecan.py +++ b/clarity_epp/export/tecan.py @@ -30,11 +30,11 @@ def samplesheet(lims, process_id, type, output_file): )) elif type == 'purify_normalise': - output_file.write('SourceTubeID\tPositionID\tPositionIndex\n') + output_file.write('SourceTubeID,PositionID,PositionIndex\n') for well in clarity_epp.export.utils.sort_96_well_plate(well_plate.keys()): artifact = well_plate[well] sample = artifact.samples[0] # assume one sample per tube - output_file.write('{sample}\t{well}\t{index}\n'.format( + output_file.write('{sample},{well},{index}\n'.format( sample=sample.udf['Dx Fractienummer'], well=well, index=clarity_epp.export.utils.get_well_index(well, one_based=True) From d87f019b48c2c07d1ae78df9f24ebaab917e561f Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 17 Jan 2023 15:34:30 +0100 Subject: [PATCH 28/41] Skip empty lines --- clarity_epp/upload/tecan.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clarity_epp/upload/tecan.py b/clarity_epp/upload/tecan.py index a10db71..509a616 100644 --- a/clarity_epp/upload/tecan.py +++ b/clarity_epp/upload/tecan.py @@ -123,11 +123,12 @@ def results_purify_normalise(lims, process_id): file_data = lims.get_file_contents(result_file.files[0].id).split('\n') header = file_data[0].rstrip().split(';') for line in file_data[1:]: - data = line.rstrip().split(';') - tecan_result[data[header.index('SampleID')]] = { - 'conc': float(data[header.index('Concentratie')]), - 'norm': txt_to_bool(data[header.index('Normalisatie')]) - } + if line.rstrip(): + data = line.rstrip().split(';') + tecan_result[data[header.index('SampleID')]] = { + 'conc': float(data[header.index('Concentratie')]), + 'norm': txt_to_bool(data[header.index('Normalisatie')]) + } break # File found exit loop # Set concentration values on artifacts From 763ce2d28b284360619e5bbf33e61b6e8ae09347 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 17 Jan 2023 16:21:09 +0100 Subject: [PATCH 29/41] Change ',' to ';' --- clarity_epp/export/tecan.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clarity_epp/export/tecan.py b/clarity_epp/export/tecan.py index 1b61de0..2708dc7 100755 --- a/clarity_epp/export/tecan.py +++ b/clarity_epp/export/tecan.py @@ -30,11 +30,11 @@ def samplesheet(lims, process_id, type, output_file): )) elif type == 'purify_normalise': - output_file.write('SourceTubeID,PositionID,PositionIndex\n') + output_file.write('SourceTubeID;PositionID;PositionIndex\n') for well in clarity_epp.export.utils.sort_96_well_plate(well_plate.keys()): artifact = well_plate[well] sample = artifact.samples[0] # assume one sample per tube - output_file.write('{sample},{well},{index}\n'.format( + output_file.write('{sample};{well};{index}\n'.format( sample=sample.udf['Dx Fractienummer'], well=well, index=clarity_epp.export.utils.get_well_index(well, one_based=True) From df9ad23bb09014c85f79ec92deb8da2d5d420322 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Wed, 18 Jan 2023 13:23:31 +0100 Subject: [PATCH 30/41] Update header --- clarity_epp/upload/tecan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clarity_epp/upload/tecan.py b/clarity_epp/upload/tecan.py index 509a616..20a4598 100644 --- a/clarity_epp/upload/tecan.py +++ b/clarity_epp/upload/tecan.py @@ -126,7 +126,7 @@ def results_purify_normalise(lims, process_id): if line.rstrip(): data = line.rstrip().split(';') tecan_result[data[header.index('SampleID')]] = { - 'conc': float(data[header.index('Concentratie')]), + 'conc': float(data[header.index('Concentratie(ng/ul)')]), 'norm': txt_to_bool(data[header.index('Normalisatie')]) } break # File found exit loop From 49df70cf9cd84e0025f7c4c352fa5a3403f8d470 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 24 Jan 2023 17:37:51 +0100 Subject: [PATCH 31/41] Update workflow --- config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.py b/config.py index 8c40f48..14436aa 100755 --- a/config.py +++ b/config.py @@ -23,8 +23,8 @@ stoftestcode_research = 'NGS_023' stoftestcode_workflow = { - stoftestcode_wes: '1106', # DEV Dx smMIP Fingerprint v1.2 - stoftestcode_mip: '1201', # DEV Dx Exoom Magnis v1.0 + stoftestcode_wes: '1654', # DEV Dx Exoom Magnis v1.2 + stoftestcode_mip: '1651', # DEV Dx smMIP v1.2 } # Export meetw protocol steps WES @@ -75,7 +75,7 @@ ] # Post sequencing workflow -sequencing_workflow = '1301' # DEV Dx Illumina Sequencing v1.0 +sequencing_workflow = '1653' # DEV Dx Illumina Sequencing v1.1 post_sequencing_workflow = '902' # DEV Dx Bioinformatica analyses v1.0 post_bioinf_workflow = { # Contains workflow and workflow stage (number) for single or trio samples # WES : DEV Dx NGS WES onderzoeken afronden v1.1 From 6a2b00b04b3d8c0ca061456df2c244006b2826d0 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 31 Jan 2023 15:59:08 +0100 Subject: [PATCH 32/41] Add support for tube output --- clarity_epp/export/manual_pipetting.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clarity_epp/export/manual_pipetting.py b/clarity_epp/export/manual_pipetting.py index d9a1346..c18f24d 100755 --- a/clarity_epp/export/manual_pipetting.py +++ b/clarity_epp/export/manual_pipetting.py @@ -398,7 +398,7 @@ def samplesheet_normalization(lims, process_id, output_file): # Save output under container location (well) well = ''.join(artifact.location[1].split(':')) - output[well] = ( + output_data = ( '{sample}\t{concentration:.1f}\t{sample_volume:.1f}\t{water_volume:.1f}\t' '{output:.1f}\t{evaporate}\t{container}\t{well}\n' ).format( @@ -411,6 +411,10 @@ def samplesheet_normalization(lims, process_id, output_file): container=artifact.location[0].name, well=well ) + if well == '11': # Tube + output_file.write(output_data) + else: # plate + output[well] = output_data for well in clarity_epp.export.utils.sort_96_well_plate(output.keys()): output_file.write(output[well]) From adbe48f90f1538b418c25a4b7f2c1c29c6af90b3 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 14 Feb 2023 13:12:12 +0100 Subject: [PATCH 33/41] Only unpool complete sequencing runs. --- clarity_epp/placement/pool.py | 83 ++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/clarity_epp/placement/pool.py b/clarity_epp/placement/pool.py index de669a2..5f8b86a 100644 --- a/clarity_epp/placement/pool.py +++ b/clarity_epp/placement/pool.py @@ -9,44 +9,45 @@ def unpooling(lims, process_id): """Unpool samples after sequencing.""" process = Process(lims, id=process_id) - pool_artifact = process.all_inputs()[0] - pool_artifact_parent_process = pool_artifact.parent_process - pool_artifact_demux = lims.get(pool_artifact.uri + '/demux') - - run_id = pool_artifact.name # Assume run id is set as pool name using placement/artifact/set_runid_name - sample_artifacts = [] # sample artifacts before pooling - sample_projects = {} - - for artifact in pool_artifact_parent_process.result_files(): - if (artifact.name == 'SampleSheet csv' or artifact.name == 'Sample Sheet') and artifact.files: - file_id = artifact.files[0].id - sample_sheet = lims.get_file_contents(id=file_id) - project_index = None - sample_index = None - for line in sample_sheet.split('\n'): - data = line.rstrip().split(',') - - if 'Sample_Project' in data and 'Sample_ID' in data: - project_index = data.index('Sample_Project') - sample_index = data.index('Sample_ID') - elif project_index and len(data) >= project_index: - sample_projects[data[sample_index]] = data[project_index] - - for node in pool_artifact_demux.getiterator('artifact'): - if node.find('samples'): - if len(node.find('samples').findall('sample')) == 1: - sample_artifact = Artifact(lims, uri=node.attrib['uri']) - sample = sample_artifact.samples[0] # 1 sample per artifact. - - # Get sample sequencing run and project from samplesheet - sample_artifact.udf['Dx Sequencing Run ID'] = run_id - if 'Sample Type' in sample.udf and 'library' in sample.udf['Sample Type']: # Use sample.name for external (clarity_portal) samples - sample_artifact.udf['Dx Sequencing Run Project'] = sample_projects[sample.name] - else: # Use sample_artifact.name for Dx samples (upload via Helix) - sample_artifact.udf['Dx Sequencing Run Project'] = sample_projects[sample_artifact.name] - sample_artifact.put() - - if sample_artifact.samples[0].project and sample_artifact.samples[0].project.udf['Application'] == 'DX': # Only move DX production samples to post sequencing workflow - sample_artifacts.append(sample_artifact) - - lims.route_artifacts(sample_artifacts, workflow_uri=Workflow(lims, id=config.post_sequencing_workflow).uri) + if process.step.actions.next_actions[0]['action'] == 'complete': # Only unpool complete sequencing runs. + pool_artifact = process.all_inputs()[0] + pool_artifact_parent_process = pool_artifact.parent_process + pool_artifact_demux = lims.get(pool_artifact.uri + '/demux') + + run_id = pool_artifact.name # Assume run id is set as pool name using placement/artifact/set_runid_name + sample_artifacts = [] # sample artifacts before pooling + sample_projects = {} + + for artifact in pool_artifact_parent_process.result_files(): + if (artifact.name == 'SampleSheet csv' or artifact.name == 'Sample Sheet') and artifact.files: + file_id = artifact.files[0].id + sample_sheet = lims.get_file_contents(id=file_id) + project_index = None + sample_index = None + for line in sample_sheet.split('\n'): + data = line.rstrip().split(',') + + if 'Sample_Project' in data and 'Sample_ID' in data: + project_index = data.index('Sample_Project') + sample_index = data.index('Sample_ID') + elif project_index and len(data) >= project_index: + sample_projects[data[sample_index]] = data[project_index] + + for node in pool_artifact_demux.getiterator('artifact'): + if node.find('samples'): + if len(node.find('samples').findall('sample')) == 1: + sample_artifact = Artifact(lims, uri=node.attrib['uri']) + sample = sample_artifact.samples[0] # 1 sample per artifact. + + # Get sample sequencing run and project from samplesheet + sample_artifact.udf['Dx Sequencing Run ID'] = run_id + if 'Sample Type' in sample.udf and 'library' in sample.udf['Sample Type']: # Use sample.name for external (clarity_portal) samples + sample_artifact.udf['Dx Sequencing Run Project'] = sample_projects[sample.name] + else: # Use sample_artifact.name for Dx samples (upload via Helix) + sample_artifact.udf['Dx Sequencing Run Project'] = sample_projects[sample_artifact.name] + sample_artifact.put() + + if sample_artifact.samples[0].project and sample_artifact.samples[0].project.udf['Application'] == 'DX': # Only move DX production samples to post sequencing workflow + sample_artifacts.append(sample_artifact) + + lims.route_artifacts(sample_artifacts, workflow_uri=Workflow(lims, id=config.post_sequencing_workflow).uri) From 9c884c482a6f5499f5c3ffe8a2b90f9a70df0dcd Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Thu, 16 Feb 2023 12:38:17 +0100 Subject: [PATCH 34/41] Update workflow id --- config.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/config.py b/config.py index 14436aa..c4428f7 100755 --- a/config.py +++ b/config.py @@ -1,19 +1,21 @@ """Clarity epp configuration.""" # Genologics -baseuri = 'https://change_this_lims.uri' -username = 'change_this' -password = 'change_this' +baseuri = 'https://usf-lims-test.op.umcutrecht.nl' +# baseuri = 'https://usf-lims.umcutrecht.nl' +username = 'DX_EPP' +password = 'rVz2REm4tnu7' # Email settings email = { - 'server': 'smtp.server.nl', - 'from': 'from@email.nl', + 'server': 'pim.umcutrecht.nl', + 'from': 'r.f.ernst-3@umcutrecht.nl', 'to_import_helix': [ - 'to_1@mail.nl', + 'r.f.ernst-3@umcutrecht.nl', + 'e.janson@umcutrecht.nl', ], 'to_sequencing_run_complete': [ - 'to_1@mail.nl', + 'r.f.ernst-3@umcutrecht.nl', ] } @@ -75,7 +77,7 @@ ] # Post sequencing workflow -sequencing_workflow = '1653' # DEV Dx Illumina Sequencing v1.1 +sequencing_workflow = '1701' # DEV Dx Illumina Sequencing v1.2 post_sequencing_workflow = '902' # DEV Dx Bioinformatica analyses v1.0 post_bioinf_workflow = { # Contains workflow and workflow stage (number) for single or trio samples # WES : DEV Dx NGS WES onderzoeken afronden v1.1 From 9df9f5b52ff6dfc25145a6efa3bf63a2d9ec3865 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Tue, 21 Feb 2023 10:54:23 +0100 Subject: [PATCH 35/41] Remove transform NoSpecialCharacters on sample name. Is managed on different location. --- .../NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv | 5 +---- templates/NovaSeq_BCL2FASTQ_Samplesheet.csv | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv b/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv index cd08a8e..76622f2 100644 --- a/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv +++ b/templates/NovaSeq_BCL2FASTQ_Reverse_Complement_Samplesheet.csv @@ -29,7 +29,7 @@ Read2StartFromCycle,${PROCESS.UDF.UMI - Read 2 Start From Cycle} Sample_ID,Sample_Name,Sample_Plate,Sample_Well,index,index2,Sample_Project,Description -${INPUT.LIMSID},${SAMPLE.NAME##NoSpecialCharacters},${INPUT.CONTAINER.NAME},${INPUT.CONTAINER.PLACEMENT},${INPUT.REAGENT.SEQUENCE##Single},${INPUT.REAGENT.SEQUENCE##Index2RC},${SAMPLE.PROJECT.NAME##NoSpecialCharacters}, +${INPUT.LIMSID},${SAMPLE.NAME},${INPUT.CONTAINER.NAME},${INPUT.CONTAINER.PLACEMENT},${INPUT.REAGENT.SEQUENCE##Single},${INPUT.REAGENT.SEQUENCE##Index2RC},${SAMPLE.PROJECT.NAME##NoSpecialCharacters}, ${INPUT.REAGENT.SEQUENCE##Single} @@ -56,9 +56,6 @@ if (index > 0) { return '' } -${SAMPLE.NAME##NoSpecialCharacters} -return token.replaceAll(\"[^a-zA-Z0-9-]\", \"-\") - ${SAMPLE.PROJECT.NAME##NoSpecialCharacters} return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") diff --git a/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv b/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv index cc02f7f..7d9a6b2 100644 --- a/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv +++ b/templates/NovaSeq_BCL2FASTQ_Samplesheet.csv @@ -30,7 +30,7 @@ Read2StartFromCycle,${PROCESS.UDF.UMI - Read 2 Start From Cycle} Sample_ID,Sample_Name,Sample_Plate,Sample_Well,index,index2,Sample_Project,Description -${INPUT.LIMSID},${SAMPLE.NAME##NoSpecialCharacters},${INPUT.CONTAINER.NAME},${INPUT.CONTAINER.PLACEMENT},${INPUT.REAGENT.SEQUENCE##Single},${INPUT.REAGENT.SEQUENCE##Dual},${SAMPLE.PROJECT.NAME##NoSpecialCharacters}, +${INPUT.LIMSID},${SAMPLE.NAME},${INPUT.CONTAINER.NAME},${INPUT.CONTAINER.PLACEMENT},${INPUT.REAGENT.SEQUENCE##Single},${INPUT.REAGENT.SEQUENCE##Dual},${SAMPLE.PROJECT.NAME##NoSpecialCharacters}, ${INPUT.REAGENT.SEQUENCE##Single} @@ -49,9 +49,6 @@ if (index >= 0) { return null } -${SAMPLE.NAME##NoSpecialCharacters} -return token.replaceAll(\"[^a-zA-Z0-9-]\", \"-\") - ${SAMPLE.PROJECT.NAME##NoSpecialCharacters} return token.replaceAll(\"[^a-zA-Z0-9_]\", \"_\") From 2ec058ab9995d6c6b65aef529fdc18e8288a067d Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Fri, 24 Feb 2023 10:50:06 +0100 Subject: [PATCH 36/41] Update config --- config.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/config.py b/config.py index c4428f7..832b6a3 100755 --- a/config.py +++ b/config.py @@ -1,21 +1,19 @@ """Clarity epp configuration.""" # Genologics -baseuri = 'https://usf-lims-test.op.umcutrecht.nl' -# baseuri = 'https://usf-lims.umcutrecht.nl' -username = 'DX_EPP' -password = 'rVz2REm4tnu7' +baseuri = 'https://change_this_lims.uri' +username = 'change_this' +password = 'change_this' # Email settings email = { - 'server': 'pim.umcutrecht.nl', - 'from': 'r.f.ernst-3@umcutrecht.nl', + 'server': 'smtp.server.nl', + 'from': 'from@email.nl', 'to_import_helix': [ - 'r.f.ernst-3@umcutrecht.nl', - 'e.janson@umcutrecht.nl', + 'to_1@mail.nl', ], 'to_sequencing_run_complete': [ - 'r.f.ernst-3@umcutrecht.nl', + 'to_1@mail.nl', ] } From 960912c6fdca1be89c359bb6ee77456d85f47d10 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Fri, 24 Feb 2023 10:51:58 +0100 Subject: [PATCH 37/41] Update meetw config --- config.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/config.py b/config.py index 832b6a3..9a0eda1 100755 --- a/config.py +++ b/config.py @@ -35,17 +35,23 @@ 'Dx Zuiveren gDNA manueel v1.1', 'Dx manueel gezuiverd placement v1.2', 'Dx gDNA Normalisatie Caliper v1.1', - 'Dx Fragmenteren v1.0' + 'Dx Uitvullen en zuiveren (Fluent 480) v1.0', + 'Dx Normaliseren (Fluent 480) v1.0', + 'Dx gDNA handmatige normalisatie WES v1.0' ] -meetw_sampleprep_wes_processes = ['Dx Library Prep & Target Enrichment Magnis v1.0'] +meetw_sampleprep_wes_processes = [ + 'Dx Fragmenteren v1.0' + 'Dx Library Prep & Target Enrichment Magnis v1.0' + ] meetw_seq_wes_processes = [ 'Dx Multiplexen Enrichment pools Magnis v1.0', 'Dx Multiplexen sequence pool v1.2', 'Dx Library pool denatureren en laden (NovaSeq) v1.3', 'AUTOMATED - NovaSeq Run (NovaSeq 6000 v3.1)', - 'Dx QC controle Lab sequencen v1.1' + 'Dx QC controle Lab sequencen v1.1', + 'Dx NovaSeq QC controle Lab sequencen v1.3' ] # Export meetw protocol steps MIP From f9d51c87cf7445308618ce78679ad8ab7c2e3271 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Fri, 24 Feb 2023 11:08:50 +0100 Subject: [PATCH 38/41] Fix python test? --- .github/workflows/python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 227ceca..6f567d9 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -12,7 +12,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: From 5a8b86f88904d17d849ba7425a85966b2ce3682b Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Fri, 24 Feb 2023 11:11:59 +0100 Subject: [PATCH 39/41] Fix python test? --- scripts/move_samples_to_new_workflow.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/move_samples_to_new_workflow.py b/scripts/move_samples_to_new_workflow.py index f0e76e6..932d573 100644 --- a/scripts/move_samples_to_new_workflow.py +++ b/scripts/move_samples_to_new_workflow.py @@ -15,23 +15,23 @@ skip_artifacts = [''] # Add samples that should not be moved to new workflow artifacts = [] -print '# Old queue:', len(old_queue.artifacts) +print('# Old queue:', len(old_queue.artifacts)) for artifact in old_queue.artifacts: if artifact.name not in skip_artifacts: - print 'Move:', artifact.name + print('Move:', artifact.name) artifacts.append(artifact) else: - print 'Keep:', artifact.name + print('Keep:', artifact.name) -print '# Move to new workflow:', len(artifacts) +print('# Move to new workflow:', len(artifacts)) # Move things to new workflow, uncomment to enable. # lims.route_artifacts(artifacts, stage_uri=old_stage.uri, unassign=True) # remove from old stage # lims.route_artifacts(artifacts, workflow_uri=new_workflow.uri) # add to new workflow old_queue = Queue(lims, id='') # Example: Dx Sample registratie zuivering v1.0 = 1142 (same as step id) -print '# Old queue:', len(old_queue.artifacts) +print('# Old queue:', len(old_queue.artifacts)) new_queue = Queue(lims, id='') # Example: Dx Sample registratie zuivering v1.1 = 1342 (same as step id) -print '# New queue:', len(new_queue.artifacts) +print('# New queue:', len(new_queue.artifacts)) From 10ef657edd11826617f50509661187b5eaba7045 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Wed, 8 Mar 2023 13:45:55 +0100 Subject: [PATCH 40/41] Add qc process concentration --- clarity_epp/export/manual_pipetting.py | 28 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/clarity_epp/export/manual_pipetting.py b/clarity_epp/export/manual_pipetting.py index c18f24d..a8e249d 100755 --- a/clarity_epp/export/manual_pipetting.py +++ b/clarity_epp/export/manual_pipetting.py @@ -10,24 +10,38 @@ def samplesheet_purify(lims, process_id, output_file): """Create manual pipetting samplesheet for purifying samples.""" output_file.write('Fractienummer\tConcentration(ng/ul)\taantal ng te isoleren\tul gDNA\tul Water\n') process = Process(lims, id=process_id) + # Find all QC process types + qc_process_types = clarity_epp.export.utils.get_process_types(lims, ['Dx Qubit QC', 'Dx Tecan Spark 10M QC']) for container in process.output_containers(): artifact = container.placements['1:1'] # asume tubes input_artifact = artifact.input_artifact_list()[0] # asume one input artifact sample = artifact.samples[0] # asume one sample per tube + # Find last qc process for artifact + qc_process = lims.get_processes(type=qc_process_types, inputartifactlimsid=input_artifact.id) + if qc_process: + qc_process = sorted( + lims.get_processes(type=qc_process_types, inputartifactlimsid=input_artifact.id), + key=lambda process: int(process.id.split('-')[-1]) + )[-1] + for qc_artifact in qc_process.outputs_per_input(input_artifact.id): + if qc_artifact.name.split(' ')[0] == artifact.name: + concentration = float(qc_artifact.udf['Dx Concentratie fluorescentie (ng/ul)']) + + else: # Fallback on previous process if qc process not found. + if 'Dx Concentratie fluorescentie (ng/ul)' in input_artifact.udf: + concentration = float(input_artifact.udf['Dx Concentratie fluorescentie (ng/ul)']) + elif 'Dx Concentratie OD (ng/ul)' in input_artifact.udf: + concentration = float(input_artifact.udf['Dx Concentratie OD (ng/ul)']) + elif 'Dx Concentratie (ng/ul)' in sample.udf: + concentration = float(sample.udf['Dx Concentratie (ng/ul)']) + if 'Dx Fractienummer' in sample.udf: fractienummer = sample.udf['Dx Fractienummer'] else: # giab fractienummer = sample.name - if 'Dx Concentratie fluorescentie (ng/ul)' in input_artifact.udf: - concentration = float(input_artifact.udf['Dx Concentratie fluorescentie (ng/ul)']) - elif 'Dx Concentratie OD (ng/ul)' in input_artifact.udf: - concentration = float(input_artifact.udf['Dx Concentratie OD (ng/ul)']) - elif 'Dx Concentratie (ng/ul)' in sample.udf: - concentration = float(sample.udf['Dx Concentratie (ng/ul)']) - input_gdna_ng = float(artifact.udf['Dx input hoeveelheid (ng)']) ul_gdna = input_gdna_ng/concentration ul_water = 200 - ul_gdna From 8e84f3396d6a876cb0f18a80faed9dd6b04ff8e6 Mon Sep 17 00:00:00 2001 From: Robert Ernst Date: Thu, 16 Mar 2023 15:38:11 +0100 Subject: [PATCH 41/41] Fix config, add mising ',' --- config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.py b/config.py index 9a0eda1..6e5a22a 100755 --- a/config.py +++ b/config.py @@ -41,7 +41,7 @@ ] meetw_sampleprep_wes_processes = [ - 'Dx Fragmenteren v1.0' + 'Dx Fragmenteren v1.0', 'Dx Library Prep & Target Enrichment Magnis v1.0' ]