Skip to content

Commit

Permalink
Merge pull request #18 from UMCUGenetics/develop
Browse files Browse the repository at this point in the history
v1.2.0
  • Loading branch information
rernst authored Oct 13, 2020
2 parents 5e2bbd8 + ca653ea commit 6cce3ac
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 152 deletions.
105 changes: 62 additions & 43 deletions clarity_epp.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ def export_caliper(args):
clarity_epp.export.caliper.samplesheet_normalise(lims, args.process_id, args.output_file)


def export_email(args):
"""Export emails"""
if args.type == 'sequencing_run':
clarity_epp.export.email.sequencing_run(lims, config.email, args.process_id)


def export_hamilton(args):
"""Export samplesheets for hamilton machine."""
if args.type == 'filling_out':
Expand All @@ -48,7 +54,7 @@ def export_labels(args):
if args.type == 'container':
clarity_epp.export.labels.container(lims, args.process_id, args.output_file, args.description)
elif args.type == 'container_sample':
clarity_epp.export.labels.container_sample(lims, args.process_id, args.output_file)
clarity_epp.export.labels.container_sample(lims, args.process_id, args.output_file, args.description)
elif args.type == 'storage_location':
clarity_epp.export.labels.storage_location(lims, args.process_id, args.output_file)

Expand Down Expand Up @@ -149,6 +155,11 @@ def placement_artifact_set_name(args):
clarity_epp.placement.artifact.set_runid_name(lims, args.process_id)


def placement_route_artifact(args):
"""Route artifacts to a workflow"""
clarity_epp.placement.artifact.route_to_workflow(lims, args.process_id)


def placement_barcode(args):
"""Check barcodes."""
if args.type == 'check_family':
Expand Down Expand Up @@ -176,80 +187,84 @@ def placement_complete_step(args):
parser_export = subparser.add_parser('export', help='Export from lims.')
subparser_export = parser_export.add_subparsers()

parser_export_hamilton = subparser_export.add_parser('hamilton', help='Create hamilton samplesheets', parents=[output_parser])
parser_export_hamilton.add_argument('type', choices=['filling_out', 'purify'], help='Samplesheet type')
parser_export_hamilton.add_argument('process_id', help='Clarity lims process id')
parser_export_hamilton.set_defaults(func=export_hamilton)

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.set_defaults(func=export_tecan)

parser_export_manual_pipetting = subparser_export.add_parser('manual', help='Create manual pipetting _exports', parents=[output_parser])
parser_export_manual_pipetting.add_argument('type', choices=['purify', 'dilute_library_pool', 'multiplex_library_pool', 'multiplex_sequence_pool'], help='Samplesheet type')
parser_export_manual_pipetting.add_argument('process_id', help='Clarity lims process id')
parser_export_manual_pipetting.set_defaults(func=export_manual_pipetting)
parser_export_bioanalyzer = subparser_export.add_parser('bioanalyzer', help='Create bioanalyzer samplesheets', parents=[output_parser])
parser_export_bioanalyzer.add_argument('process_id', help='Clarity lims process id')
parser_export_bioanalyzer.set_defaults(func=export_bioanalyzer)

parser_export_caliper = subparser_export.add_parser('caliper', help='Create caliper samplesheets', parents=[output_parser])
parser_export_caliper.add_argument('type', choices=['normalise'], help='Samplesheet type')
parser_export_caliper.add_argument('process_id', help='Clarity lims process id')
parser_export_caliper.set_defaults(func=export_caliper)

parser_export_tapestation = subparser_export.add_parser('tapestation', help='Create tapestation samplesheets', parents=[output_parser])
parser_export_tapestation.add_argument('process_id', help='Clarity lims process id')
parser_export_tapestation.set_defaults(func=export_tapestation)
parser_export_email = subparser_export.add_parser('email', help='Send emails', parents=[output_parser])
parser_export_email.add_argument('type', choices=['sequencing_run'], help='Email type')
parser_export_email.add_argument('process_id', help='Clarity lims process id')
parser_export_email.set_defaults(func=export_email)

parser_export_bioanalyzer = subparser_export.add_parser('bioanalyzer', help='Create bioanalyzer samplesheets', parents=[output_parser])
parser_export_bioanalyzer.add_argument('process_id', help='Clarity lims process id')
parser_export_bioanalyzer.set_defaults(func=export_bioanalyzer)
parser_export_hamilton = subparser_export.add_parser('hamilton', help='Create hamilton samplesheets', parents=[output_parser])
parser_export_hamilton.add_argument('type', choices=['filling_out', 'purify'], help='Samplesheet type')
parser_export_hamilton.add_argument('process_id', help='Clarity lims process id')
parser_export_hamilton.set_defaults(func=export_hamilton)

parser_export_illumina = subparser_export.add_parser('illumina', help='Export updated illumina samplesheet.', parents=[output_parser])
parser_export_illumina.add_argument('process_id', help='Clarity lims process id')
parser_export_illumina.add_argument('artifact_id', help='Clarity lims samplesheet artifact id')
parser_export_illumina.set_defaults(func=export_illumina)

parser_export_labels = subparser_export.add_parser('labels', help='Export container labels.', parents=[output_parser])
parser_export_labels.add_argument('type', choices=['container', 'container_sample', 'storage_location'], help='Label type')
parser_export_labels.add_argument('process_id', help='Clarity lims process id')
parser_export_labels.add_argument('-d', '--description', nargs='?', help='Container name description')

parser_export_labels.set_defaults(func=export_labels)

parser_export_manual_pipetting = subparser_export.add_parser('manual', help='Create manual pipetting _exports', parents=[output_parser])
parser_export_manual_pipetting.add_argument('type', choices=['purify', 'dilute_library_pool', 'multiplex_library_pool', 'multiplex_sequence_pool'], help='Samplesheet type')
parser_export_manual_pipetting.add_argument('process_id', help='Clarity lims process id')
parser_export_manual_pipetting.set_defaults(func=export_manual_pipetting)

parser_export_merge = subparser_export.add_parser('merge', help='Export merge file.', parents=[output_parser])
parser_export_merge.add_argument('process_id', help='Clarity lims process id')
parser_export_merge.set_defaults(func=export_merge_file)

parser_export_ped = subparser_export.add_parser('ped', help='Export ped file.', parents=[output_parser])
parser_export_ped.add_argument('process_id', help='Clarity lims process id')
parser_export_ped.set_defaults(func=export_ped_file)

parser_export_ped = subparser_export.add_parser('merge', help='Export merge file.', parents=[output_parser])
parser_export_ped.add_argument('process_id', help='Clarity lims process id')
parser_export_ped.set_defaults(func=export_merge_file)
parser_export_removed_samples = subparser_export.add_parser('removed_samples', help='Export removed sampels table.', parents=[output_parser])
parser_export_removed_samples.set_defaults(func=export_removed_samples)

parser_export_tapestation = subparser_export.add_parser('tapestation', help='Create tapestation samplesheets', parents=[output_parser])
parser_export_tapestation.add_argument('process_id', help='Clarity lims process id')
parser_export_tapestation.set_defaults(func=export_tapestation)

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.set_defaults(func=export_tecan)

parser_export_workflow = subparser_export.add_parser('workflow', help='Export workflow result file.', parents=[output_parser])
parser_export_workflow.add_argument('type', choices=['lab', 'data_analysis'], help='Workflow type')
parser_export_workflow.add_argument('process_id', help='Clarity lims process id')
parser_export_workflow.set_defaults(func=export_workflow)

parser_export_illumina = subparser_export.add_parser('illumina', help='Export updated illumina samplesheet.', parents=[output_parser])
parser_export_illumina.add_argument('process_id', help='Clarity lims process id')
parser_export_illumina.add_argument('artifact_id', help='Clarity lims samplesheet artifact id')
parser_export_illumina.set_defaults(func=export_illumina)

parser_export_removed_samples = subparser_export.add_parser('removed_samples', help='Export removed sampels table.', parents=[output_parser])
parser_export_removed_samples.set_defaults(func=export_removed_samples)

# Sample upload
parser_upload = subparser.add_parser('upload', help='Upload samples or results to clarity lims')
subparser_upload = parser_upload.add_subparsers()

parser_upload_bioanalyzer = subparser_upload.add_parser('bioanalyzer', help='Upload bioanalyzer results')
parser_upload_bioanalyzer.add_argument('process_id', help='Clarity lims process id')
parser_upload_bioanalyzer.set_defaults(func=upload_bioanalyzer_results)

parser_upload_sample = subparser_upload.add_parser('sample', help='Upload samples from helix export')
parser_upload_sample.add_argument('input_file', type=argparse.FileType('r'), help='Input file path')
parser_upload_sample.set_defaults(func=upload_samples)

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.set_defaults(func=upload_tecan_results)

parser_upload_tapestation = subparser_upload.add_parser('tapestation', help='Upload tapestation results')
parser_upload_tapestation.add_argument('process_id', help='Clarity lims process id')
parser_upload_tapestation.set_defaults(func=upload_tapestation_results)

parser_upload_bioanalyzer = subparser_upload.add_parser('bioanalyzer', help='Upload bioanalyzer results')
parser_upload_bioanalyzer.add_argument('process_id', help='Clarity lims process id')
parser_upload_bioanalyzer.set_defaults(func=upload_bioanalyzer_results)
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.set_defaults(func=upload_tecan_results)

# QC
parser_qc = subparser.add_parser('qc', help='Set QC values/flags.')
Expand Down Expand Up @@ -280,18 +295,22 @@ def placement_complete_step(args):
parser_placement_artifact.add_argument('process_id', help='Clarity lims process id')
parser_placement_artifact.set_defaults(func=placement_artifact_set_name)

parser_placement_route_artifact = subparser_placement.add_parser('route_artifact', help='Route artifact to a workflow.')
parser_placement_route_artifact.add_argument('process_id', help='Clarity lims process id')
parser_placement_route_artifact.set_defaults(func=placement_route_artifact)

parser_placement_barcode = subparser_placement.add_parser('barcode_check', help='Check barcode clarity_epp.placement.')
parser_placement_barcode.add_argument('type', choices=['check_family'], help='Check type')
parser_placement_barcode.add_argument('process_id', help='Clarity lims process id')
parser_placement_barcode.set_defaults(func=placement_barcode)

parser_placement_unpooling = subparser_placement.add_parser('unpooling', help='Unpooling of sequencing pool.')
parser_placement_unpooling.add_argument('process_id', help='Clarity lims process id')
parser_placement_unpooling.set_defaults(func=placement_unpooling)

parser_placement_complete_step = subparser_placement.add_parser('complete_step', help='Complete step Dx Mark protocol complete.')
parser_placement_complete_step.add_argument('process_id', help='Clarity lims process id')
parser_placement_complete_step.set_defaults(func=placement_complete_step)

parser_placement_unpooling = subparser_placement.add_parser('unpooling', help='Unpooling of sequencing pool.')
parser_placement_unpooling.add_argument('process_id', help='Clarity lims process id')
parser_placement_unpooling.set_defaults(func=placement_unpooling)

args = parser.parse_args()
args.func(args)
1 change: 1 addition & 0 deletions clarity_epp/export/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import bioanalyzer
import caliper
import email
import hamilton
import illumina
import labels
Expand Down
29 changes: 29 additions & 0 deletions clarity_epp/export/email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Export email functions."""
from genologics.entities import Process

from .. import send_email


def sequencing_run(lims, email_settings, process_id):
process = Process(lims, id=process_id)
artifact = process.all_inputs()[0]

subject = "LIMS QC Controle - {0}".format(artifact.name)

message = "Sequencing Run: {0}\n".format(artifact.name)
message += "Date: {0}\n".format(process.date_run)
message += "Technician: {0}\n".format(process.technician.name)
message += "LIMS Next Action: {0}\n\n".format(process.step.actions.next_actions[0]['action'])

message += "UDF - Conversie rapport OK?: {0}\n".format(process.udf['Conversie rapport OK?'])
if 'Fouten registratie (uitleg)' in process.udf:
message += "UDF - Fouten registratie (uitleg): {0}\n".format(process.udf['Fouten registratie (uitleg)'])
if 'Fouten registratie (oorzaak)' in process.udf:
message += "UDF - Fouten registratie (oorzaak): {0}\n".format(process.udf['Fouten registratie (uitleg)'])

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['from'], email_settings['to_sequencing_run_complete'], subject, message)
30 changes: 21 additions & 9 deletions clarity_epp/export/illumina.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def get_project(projects, urgent=False):

# Create family if not exist
if family not in families:
families[family] = {'samples': [], 'NICU': False, 'project_type': 'unknown_project', 'split_project_type': False, 'urgent': False}
families[family] = {'samples': [], 'NICU': False, 'project_type': 'unknown_project', 'split_project_type': False, 'urgent': False, 'merge': False}

# Update family information
if sample.udf['Dx Onderzoeksreden'] == 'Research': # Dx research sample
Expand All @@ -54,14 +54,20 @@ def get_project(projects, urgent=False):
project_type = 'CREv2'
families[family]['project_type'] = project_type
families[family]['split_project_type'] = True

# Set urgent / merge status
if 'Dx Spoed' in list(sample.udf) and sample.udf['Dx Spoed']:
families[family]['urgent'] = True
if 'Dx Mergen' in list(sample.udf) and sample.udf['Dx Mergen']:
families[family]['merge'] = True
families[family]['urgent'] = False

else: # Other samples
family = sample.project.name
if 'GIAB' in sample.name.upper() and not sample.project: # GIAB control samples
family = 'GIAB'
else:
family = sample.project.name
if family not in families:
families[family] = {'samples': [], 'NICU': False, 'project_type': family, 'split_project_type': False, 'urgent': False}
families[family] = {'samples': [], 'NICU': False, 'project_type': family, 'split_project_type': False, 'urgent': False, 'merge': False}

# Add sample to family
families[family]['samples'].append(sample)
Expand All @@ -86,16 +92,22 @@ def get_project(projects, urgent=False):
# Set sample projects
sample_projects = {}

# Urgent families / samples
for family in [family for family in families.values() if family['urgent']]:
# Urgent families / samples, skip merge
for family in [family for family in families.values() if family['urgent'] and not family['merge']]:
family_project = get_project(project_types[family['project_type']]['projects'], urgent=True)

for sample in family['samples']:
sample_projects[get_sequence_name(sample)] = family_project
project_types[family['project_type']]['projects'][family_project] += 1

# Merge families / samples
for family in [family for family in families.values() if family['merge']]:
family_project = get_project(project_types[family['project_type']]['projects'])
for sample in family['samples']:
sample_projects[get_sequence_name(sample)] = family_project
project_types[family['project_type']]['projects'][family_project] += 1

# Non urgent families / samples
non_urgent_families = [family for family in families.values() if not family['urgent']]
# Non urgent and non merge families / samples
non_urgent_families = [family for family in families.values() if not family['urgent'] and not family['merge']]
for family in sorted(non_urgent_families, key=lambda fam: (len(fam['samples'])), reverse=True):
family_project = get_project(project_types[family['project_type']]['projects'])
for sample in family['samples']:
Expand Down
26 changes: 14 additions & 12 deletions clarity_epp/export/labels.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
"""Export label functions."""

import re

from genologics.entities import Process


def container(lims, process_id, output_file, description):
def container(lims, process_id, output_file, description=''):
"""Generate container label file."""
process = Process(lims, id=process_id)
for container in process.output_containers():
for index, container in enumerate(sorted(process.output_containers(), key=lambda container: container.id, reverse=True)):
if description:
output_file.write('{description} {container}\t{container}\r\n'.format(description=description, container=container.name))
if ',' in description:
output_file.write('{description}\t{container}\r\n'.format(description=description.split(',')[index], container=container.name))
else:
output_file.write('{description}\t{container}\r\n'.format(description=description, container=container.name))
else:
output_file.write('{container}\r\n'.format(container=container.name))


def container_sample(lims, process_id, output_file):
def container_sample(lims, process_id, output_file, description=''):
"""Generate container & artifact name label file."""
process = Process(lims, id=process_id)
for container in process.output_containers():
for artifact in container.placements.values():
output_file.write('{container}\t{sample}\r\n'.format(container=container.name, sample=artifact.name))
if description:
output_file.write('{description}\t{sample}\t{container}\r\n'.format(description=description, container=container.name, sample=artifact.name))
else:
output_file.write('{sample}\t{container}\r\n'.format(container=container.name, sample=artifact.name))


def storage_location(lims, process_id, output_file):
"""Generate storage location label file."""
process = Process(lims, id=process_id)
for artifact in process.all_outputs():
for artifact in process.analytes()[0]:
storage_location = artifact.samples[0].udf['Dx Opslaglocatie']
m = re.search('\D+(\d+)\w+: (\d+)', storage_location)
output_file.write('{sample}\t{storage_location}\t{tray}\t{tray_position}\n'.format(
output_file.write('{sample}\t{storage_location}\t{birth_date}\n'.format(
sample=artifact.samples[0].name,
storage_location=storage_location,
tray=m.group(1),
tray_position=m.group(2)
birth_date=artifact.samples[0].udf['Dx Geboortejaar']
))
Loading

0 comments on commit 6cce3ac

Please sign in to comment.