diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index dbd52d5..392ddef 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -35,6 +35,7 @@ jobs: - name: Install Nextflow uses: nf-core/setup-nextflow@v2 + version: 25.10 - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 with: diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml index 95b6b6a..42e519b 100644 --- a/.github/workflows/linting_comment.yml +++ b/.github/workflows/linting_comment.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download lint results - uses: dawidd6/action-download-artifact@20319c5641d495c8a52e688b7dc5fada6c3a9fbc # v8 + uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6 with: workflow: linting.yml workflow_conclusion: completed diff --git a/bin/parse_sequenceQC.py b/bin/parse_sequenceQC.py index b98184c..0f6164c 100755 --- a/bin/parse_sequenceQC.py +++ b/bin/parse_sequenceQC.py @@ -48,9 +48,12 @@ def load_json(path): "n50_value", "nr_contigs", "length", + "wgmlst_loci_count", } -CHECKM_TEST = "checkm_contamination" +CHECKM_TEST = "checkm2_contamination" + +WGMLST_TEST = "wgmlst_loci_count" PNC_FAIL_MESSAGE = ( "[SEQ_FAIL] Resequencing is recommended. QUALITY_METRICS did not meet PNC requirements." @@ -96,6 +99,8 @@ def build_typingQC_message(sample_data, species, failed_tests): base_message = CHECKM_FAIL_MESSAGE elif failed_tests.intersection(ABSOLUTE_FAIL_TESTS): base_message = PNC_FAIL_MESSAGE + elif WGMLST_TEST in failed_tests: + base_message = PNC_FAIL_MESSAGE elif failed_tests.intersection(WARNING_TESTS): base_message = WARNING_MESSAGE else: diff --git a/bin/parse_sistrQC.py b/bin/parse_sistrQC.py index e216ddb..f5bd108 100755 --- a/bin/parse_sistrQC.py +++ b/bin/parse_sistrQC.py @@ -3,6 +3,7 @@ import json import csv import argparse +import re from pathlib import Path import gzip @@ -56,6 +57,29 @@ def load_reportable_serovars(reportable_file): SEROVAR_KEY = f"{SISTR_PREFIX}serovar" SEROVAR_CGMLST = f"{SISTR_PREFIX}serovar_cgmlst" + +#QC_MESSAGES Updates +#Matches the non-actionable cgMLST loci found INFO message and strips it from qc_messages +CGMLST_LOCI_INFO_PATTERN = re.compile(r"INFO: Number of cgMLST\d+ loci found \(n=\d+\)") +def filter_qc_messages(qc_messages): + if not qc_messages: + return qc_messages + cleaned = CGMLST_LOCI_INFO_PATTERN.sub("", qc_messages) + # Collapse leftover separators/whitespace left behind by the removal + cleaned = re.sub(r"\s*\|\s*", " | ", cleaned) + cleaned = re.sub(r"^\s*\|\s*|\s*\|\s*$", "", cleaned) + cleaned = re.sub(r"\n\s*\n", "\n", cleaned) + return cleaned.strip() + +WZX_WZY_PATTERN = "Wzx/Wzy genes missing" +WZX_WZY_WARNING_MESSAGE = "WARNING: Wzx/Wzy genes missing. Cannot determine O-antigen serogroup." + +def wzx_wzy_only_failure(qc_messages): + #Checks if a SISTR FAIL is solely due to missing Wzx/Wzy genes: does not affect serovar prediction and should not result in FAIL for typingQC + if not qc_messages: + return False + return WZX_WZY_PATTERN in qc_messages + def H1_warning(qc_messages): # Check if SISTR WARNING contains identification of the inability to identify H1 antigens, and therefore, unable to predict serovar repliably if not qc_messages: @@ -70,12 +94,16 @@ def H1_warning(qc_messages): def extract_sistr_qc(sample_data): qc_status = sample_data.get(QC_STATUS_KEY, "Unknown") - qc_messages = sample_data.get(QC_MESSAGES_KEY, "") + qc_messages = filter_qc_messages(sample_data.get(QC_MESSAGES_KEY, "")) if qc_status.upper() == "PASS": # For PASS samples, leave QUALITY_ANALYSIS column blank return "" + if qc_status.upper() == "FAIL" and wzx_wzy_only_failure(qc_messages): + # O-antigen serogroup couldn't be determined, but this doesn't block typingQC and reports it as a warning rather than the raw FAIL message. + return WZX_WZY_WARNING_MESSAGE + elif qc_status.upper() == "WARNING": # If sample raises a WARNING in qc_status record the QC_message return qc_messages if qc_messages else "SISTR analysis completed with warnings. Please review results manually." @@ -86,13 +114,16 @@ def extract_sistr_qc(sample_data): def build_typingQC_message(sample_data, reportable_serovars): qc_status = sample_data.get(QC_STATUS_KEY, "Unknown") - qc_messages = sample_data.get(QC_MESSAGES_KEY, "") + qc_messages = filter_qc_messages(sample_data.get(QC_MESSAGES_KEY, "")) # Check for H1 antigen warning from SISTR and treat it as an RDS [FAIL] if qc_status.upper() == "WARNING" and H1_warning(qc_messages): return "[SISTR_FAIL] Serotyping unsuccessful. RESEQUENCING or TRADITIONAL SEROTYPING is advised." - if qc_status.upper() in ["PASS", "WARNING"]: + # A FAIL solely due to missing Wzx/Wzy genes: fall through to the serovar reportability check below and prepend a warning instead of SISTR_FAIL + is_wzx_wzy_fail = qc_status.upper() == "FAIL" and wzx_wzy_only_failure(qc_messages) + + if qc_status.upper() in ["PASS", "WARNING"] or is_wzx_wzy_fail: # Extract serovar predictions serovar = sample_data.get(SEROVAR_KEY, "") serovar_cgmlst = sample_data.get(SEROVAR_CGMLST, "") diff --git a/bin/validate_serotypes.py b/bin/validate_serotypes.py index 9880265..6200c50 100755 --- a/bin/validate_serotypes.py +++ b/bin/validate_serotypes.py @@ -39,28 +39,58 @@ def create_serotype_lookup(sample_data_list): return serotype_lookup -def determine_validated_serotype(typingqc_message, sample_serotype, approve_verification=False): -# Determine the validated serotype based on typingQC message and sample serotype. +# Serovar rename mappings: predicted serovar -> validated reportable name (CDC) +# Add new entried here as nomenclature changes are required +SEROVAR_RENAME_MAP = { + "Panama": "Panama/Houston", + "Sendai": "Miami" +} + +# Quality metrics warnings to append when a rename is applied +SEROVAR_RENAME_WARNINGS = { + "Sendai": "WARNING: Predicted serovar Sendai has been reported as Miami to conform with current CDC serovar nomenclature." +} + +def apply_serovar_rename(serotype, quality_metrics): +# If serotype matched a knoen rename mappung, return the renamed validated serotype and updated quality_metrics string. Otherwsie return the inputs unchanged. + if serotype not in SEROVAR_RENAME_MAP: + return serotype, quality_metrics + + renamed = SEROVAR_RENAME_MAP[serotype] + warning = SEROVAR_RENAME_WARNINGS.get(serotype) + + if warning: + #Append warning to existing quality_metics content if present + updated_metrics = f"{quality_metrics}; {warning}" if quality_metrics.strip() else warning + else: + updated_metrics = quality_metrics + + return renamed, updated_metrics + +def determine_validated_serotype(typingqc_message, sample_serotype, quality_metrics, approve_verification=False): +# Determine the validated serotype based on typingQC message and sample serotype. Returns validated_serotype, updated_quality_metrics typingqc_upper = str(typingqc_message).upper() if 'FAIL' in typingqc_upper: - return 'pending' + return 'pending', quality_metrics + elif 'WARNING' in typingqc_upper: if approve_verification: # If approving verification, treat like PASS if not sample_serotype or sample_serotype.strip() == '': - return '' - return sample_serotype + return '', quality_metrics + return apply_serovar_rename(sample_serotype, quality_metrics) else: # Default behavior for warnings - return 'verification needed' + return 'verification needed', quality_metrics + elif 'PASS' in typingqc_upper: # If no serotype provided, leave blank if not sample_serotype or sample_serotype.strip() == '': - return '' - return sample_serotype + return '', quality_metrics + return apply_serovar_rename(sample_serotype, quality_metrics) else: - return 'unknown' + return 'unknown', quality_metrics def find_column_indices(header): # Find the indices of important columns in the CSV header. @@ -68,6 +98,7 @@ def find_column_indices(header): 'sample': None, 'sample_name': None, 'typingqc_message': None, + 'quality_metrics': None, 'validated_serotype': None } @@ -79,13 +110,15 @@ def find_column_indices(header): indices['sample_name'] = i elif col_lower == 'typingqc_message': indices['typingqc_message'] = i + elif col_lower == 'quality_metrics': + indices['quality_metrics'] = i elif col_lower == 'validated_serotype': indices['validated_serotype'] = i return indices def process_csv_file(input_path, serotype_lookup, output_path, approve_verification=False): -# Process the CSV file and add validated serotype column. + # Process the CSV file and add validated serotype column. rows = [] with input_path.open('r', newline='', encoding='utf-8') as csvfile: @@ -123,19 +156,27 @@ def process_csv_file(input_path, serotype_lookup, output_path, approve_verificat if col_indices['typingqc_message'] is not None and len(row) > col_indices['typingqc_message']: typingqc_message = row[col_indices['typingqc_message']] + # Get existing quality_metrics value + quality_metrics = '' + if col_indices['quality_metrics'] is not None and len(row) > col_indices['quality_metrics']: + quality_metrics = row[col_indices['quality_metrics']] + # Get the serotype for this sample sample_serotype = serotype_lookup.get(sample_id, '') - # Determine validated serotype - validated_serotype = determine_validated_serotype( + # Determine validated serotype and updated quality_metrics + validated_serotype, updated_quality_metrics = determine_validated_serotype( typingqc_message, sample_serotype, - approve_verification + quality_metrics, + approve_verification, ) - # Set the validated serotype in the appropriate column + # Write validated serotype and (possibly updated) quality_metrics back to row if col_indices['validated_serotype'] is not None: row[col_indices['validated_serotype']] = validated_serotype + if col_indices['quality_metrics'] is not None: + row[col_indices['quality_metrics']] = updated_quality_metrics rows.append(row) diff --git a/tests/data/CAMP001.flat_sample.json.gz b/tests/data/CAMP001.flat_sample.json.gz index d672733..5c83cf0 100644 Binary files a/tests/data/CAMP001.flat_sample.json.gz and b/tests/data/CAMP001.flat_sample.json.gz differ diff --git a/tests/data/EA001.flat_sample.json.gz b/tests/data/EA001.flat_sample.json.gz index c9db6c0..26b9fe7 100644 Binary files a/tests/data/EA001.flat_sample.json.gz and b/tests/data/EA001.flat_sample.json.gz differ diff --git a/tests/data/EC001.flat_sample.json.gz b/tests/data/EC001.flat_sample.json.gz index 7e16674..c632695 100644 Binary files a/tests/data/EC001.flat_sample.json.gz and b/tests/data/EC001.flat_sample.json.gz differ diff --git a/tests/data/EC002.flat_sample.json.gz b/tests/data/EC002.flat_sample.json.gz index 1a0d5ce..b0dc1c7 100644 Binary files a/tests/data/EC002.flat_sample.json.gz and b/tests/data/EC002.flat_sample.json.gz differ diff --git a/tests/data/EC004.flat_sample.json.gz b/tests/data/EC004.flat_sample.json.gz index efbd668..da1d4c9 100644 Binary files a/tests/data/EC004.flat_sample.json.gz and b/tests/data/EC004.flat_sample.json.gz differ diff --git a/tests/data/EC005.flat_sample.json.gz b/tests/data/EC005.flat_sample.json.gz index ef66afb..330f109 100644 Binary files a/tests/data/EC005.flat_sample.json.gz and b/tests/data/EC005.flat_sample.json.gz differ diff --git a/tests/data/EC006.flat_sample.json.gz b/tests/data/EC006.flat_sample.json.gz index 13d262a..ff6d24c 100644 Binary files a/tests/data/EC006.flat_sample.json.gz and b/tests/data/EC006.flat_sample.json.gz differ diff --git a/tests/data/EC007.flat_sample.json.gz b/tests/data/EC007.flat_sample.json.gz index acc4142..e381c1c 100644 Binary files a/tests/data/EC007.flat_sample.json.gz and b/tests/data/EC007.flat_sample.json.gz differ diff --git a/tests/data/LIST001.flat_sample.json.gz b/tests/data/LIST001.flat_sample.json.gz index c898be9..f81985a 100644 Binary files a/tests/data/LIST001.flat_sample.json.gz and b/tests/data/LIST001.flat_sample.json.gz differ diff --git a/tests/data/SALM001.flat_sample.json.gz b/tests/data/SALM001.flat_sample.json.gz index 2823d99..5a2603b 100644 Binary files a/tests/data/SALM001.flat_sample.json.gz and b/tests/data/SALM001.flat_sample.json.gz differ diff --git a/tests/data/SALM002.flat_sample.json.gz b/tests/data/SALM002.flat_sample.json.gz index e779a3d..81ca2d7 100644 Binary files a/tests/data/SALM002.flat_sample.json.gz and b/tests/data/SALM002.flat_sample.json.gz differ diff --git a/tests/data/SALM003.flat_sample.json.gz b/tests/data/SALM003.flat_sample.json.gz index b5fb15b..bfc6cf5 100644 Binary files a/tests/data/SALM003.flat_sample.json.gz and b/tests/data/SALM003.flat_sample.json.gz differ diff --git a/tests/data/SALM004.flat_sample.json.gz b/tests/data/SALM004.flat_sample.json.gz index fbfd51d..dc500a6 100644 Binary files a/tests/data/SALM004.flat_sample.json.gz and b/tests/data/SALM004.flat_sample.json.gz differ diff --git a/tests/data/SALM005.flat_sample.json.gz b/tests/data/SALM005.flat_sample.json.gz index 35947d5..f2afbf8 100644 Binary files a/tests/data/SALM005.flat_sample.json.gz and b/tests/data/SALM005.flat_sample.json.gz differ diff --git a/tests/data/SALM007.flat_sample.json.gz b/tests/data/SALM007.flat_sample.json.gz index a187676..c711a19 100644 Binary files a/tests/data/SALM007.flat_sample.json.gz and b/tests/data/SALM007.flat_sample.json.gz differ diff --git a/tests/data/SALM008.flat_sample.json.gz b/tests/data/SALM008.flat_sample.json.gz index 7c5e090..415fffe 100644 Binary files a/tests/data/SALM008.flat_sample.json.gz and b/tests/data/SALM008.flat_sample.json.gz differ diff --git a/tests/data/SALM009.flat_sample.json.gz b/tests/data/SALM009.flat_sample.json.gz index db0438a..f81819b 100644 Binary files a/tests/data/SALM009.flat_sample.json.gz and b/tests/data/SALM009.flat_sample.json.gz differ diff --git a/tests/data/SALM010.flat_sample.json.gz b/tests/data/SALM010.flat_sample.json.gz index e5f6dca..291094a 100644 Binary files a/tests/data/SALM010.flat_sample.json.gz and b/tests/data/SALM010.flat_sample.json.gz differ diff --git a/tests/data/SALM011.flat_sample.json.gz b/tests/data/SALM011.flat_sample.json.gz index 58c4a57..1524f95 100644 Binary files a/tests/data/SALM011.flat_sample.json.gz and b/tests/data/SALM011.flat_sample.json.gz differ diff --git a/tests/data/SALM012.flat_sample.json.gz b/tests/data/SALM012.flat_sample.json.gz index 3e7bd95..5f8fdf5 100644 Binary files a/tests/data/SALM012.flat_sample.json.gz and b/tests/data/SALM012.flat_sample.json.gz differ diff --git a/tests/data/SALM013.flat_sample.json.gz b/tests/data/SALM013.flat_sample.json.gz new file mode 100644 index 0000000..983e6ca Binary files /dev/null and b/tests/data/SALM013.flat_sample.json.gz differ diff --git a/tests/data/SALM014.flat_sample.json.gz b/tests/data/SALM014.flat_sample.json.gz new file mode 100644 index 0000000..d3a3377 Binary files /dev/null and b/tests/data/SALM014.flat_sample.json.gz differ diff --git a/tests/data/samplesheets/samplesheet1.csv b/tests/data/samplesheets/samplesheet1.csv index c89375f..8562f92 100644 --- a/tests/data/samplesheets/samplesheet1.csv +++ b/tests/data/samplesheets/samplesheet1.csv @@ -1,8 +1,8 @@ sample,sample_name,mikrokondo_data,predicted_identification_name,qc_status_overall,predicted_primary_type_name -SAMPLE1,EC001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EC001.flat_sample.json.gz,Escherichia coli,PASSED,O157:H7 -SAMPLE2,EC002,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EC002.flat_sample.json.gz,Escherichia coli,PASSED,O55:H7 -SAMPLE3,SALM001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM001.flat_sample.json.gz,Salmonella houtenae,PASSED,IV Y:gz51:- -SAMPLE4,SALM004,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM004.flat_sample.json.gz,Salmonella enterica,PASSED,Gallinarum -SAMPLE5,SALM003,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM003.flat_sample.json.gz,Salmonella enterica,FAILED,Kentucky -SAMPLE6,LIST001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/LIST001.flat_sample.json.gz,Listeria monocytogenes,PASSED, -SAMPLE7,LIST001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/LIST001.flat_sample.json.gz,Listeria monocytogenes,PASSED, +SAMPLE1,EC001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EC001.flat_sample.json.gz,Escherichia coli,PASSED,O157:H7 +SAMPLE2,EC002,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EC002.flat_sample.json.gz,Escherichia coli,PASSED,O55:H7 +SAMPLE3,SALM001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM001.flat_sample.json.gz,Salmonella houtenae,PASSED,IV Y:gz51:- +SAMPLE4,SALM004,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM004.flat_sample.json.gz,Salmonella enterica,PASSED,Gallinarum +SAMPLE5,SALM003,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM003.flat_sample.json.gz,Salmonella enterica,FAILED,Kentucky +SAMPLE6,LIST001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/LIST001.flat_sample.json.gz,Listeria monocytogenes,PASSED, +SAMPLE7,LIST001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/LIST001.flat_sample.json.gz,Listeria monocytogenes,PASSED, diff --git a/tests/data/samplesheets/samplesheet_ectyper.csv b/tests/data/samplesheets/samplesheet_ectyper.csv index 20ea5f1..12e5c6e 100644 --- a/tests/data/samplesheets/samplesheet_ectyper.csv +++ b/tests/data/samplesheets/samplesheet_ectyper.csv @@ -1,8 +1,8 @@ sample,sample_name,mikrokondo_data,predicted_identification_name,qc_status_overall,predicted_primary_type_name -SAMPLE1,EC001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EC001.flat_sample.json.gz,Escherichia coli,PASSED,O157:H7 -SAMPLE2,EC002,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EC002.flat_sample.json.gz,Escherichia coli,PASSED,O55:H7 -SAMPLE3,EC004,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EC004.flat_sample.json.gz,Escherichia coli,FAILED,O103:H2 -SAMPLE4,EC005,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EC005.flat_sample.json.gz,Escherichia coli,PASSED,O2/O137:H41 -SAMPLE5,EC006,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EC006.flat_sample.json.gz,Escherichia coli,PASSED,-:H21 -SAMPLE6,EC007,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EC007.flat_sample.json.gz,Escherichia coli,PASSED,O111:H8 -SAMPLE8,EA001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EA001.flat_sample.json.gz,Escherichia coli,PASSED, +SAMPLE1,EC001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EC001.flat_sample.json.gz,Escherichia coli,PASSED,O157:H7 +SAMPLE2,EC002,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EC002.flat_sample.json.gz,Escherichia coli,PASSED,O55:H7 +SAMPLE3,EC004,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EC004.flat_sample.json.gz,Escherichia coli,FAILED,O103:H2 +SAMPLE4,EC005,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EC005.flat_sample.json.gz,Escherichia coli,PASSED,O2/O137:H41 +SAMPLE5,EC006,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EC006.flat_sample.json.gz,Escherichia coli,PASSED,-:H21 +SAMPLE6,EC007,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EC007.flat_sample.json.gz,Escherichia coli,PASSED,O111:H8 +SAMPLE8,EA001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EA001.flat_sample.json.gz,Escherichia coli,PASSED, diff --git a/tests/data/samplesheets/samplesheet_exclusions.csv b/tests/data/samplesheets/samplesheet_exclusions.csv index 1073149..d9b34ee 100644 --- a/tests/data/samplesheets/samplesheet_exclusions.csv +++ b/tests/data/samplesheets/samplesheet_exclusions.csv @@ -1,5 +1,5 @@ sample,sample_name,mikrokondo_data,predicted_identification_name,qc_status_overall,predicted_primary_type_name -SAMPLE1,SALM001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM001.flat_sample.json.gz,Salmonella houtenae,PASSED,"IV Y:g,z51:-" -SAMPLE2,SALM004,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM004.flat_sample.json.gz,Salmonella enterica,PASSED,Gallinarum -SAMPLE4,LIST001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/LIST001.flat_sample.json.gz,Listeria monocytogenes,PASSED, -SAMPLE5,CAMP001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/CAMP001.flat_sample.json.gz,Campylobacter_coli,FAILED, +SAMPLE1,SALM001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM001.flat_sample.json.gz,Salmonella houtenae,PASSED,"IV Y:g,z51:-" +SAMPLE2,SALM004,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM004.flat_sample.json.gz,Salmonella enterica,PASSED,Gallinarum +SAMPLE4,LIST001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/LIST001.flat_sample.json.gz,Listeria monocytogenes,PASSED, +SAMPLE5,CAMP001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/CAMP001.flat_sample.json.gz,Campylobacter_coli,FAILED, diff --git a/tests/data/samplesheets/samplesheet_incorrectJSON.csv b/tests/data/samplesheets/samplesheet_incorrectJSON.csv index 1265cf8..8ad83b9 100644 --- a/tests/data/samplesheets/samplesheet_incorrectJSON.csv +++ b/tests/data/samplesheets/samplesheet_incorrectJSON.csv @@ -1,2 +1,2 @@ sample,sample_name,mikrokondo_data,predicted_identification_name,qc_status_overall,predicted_primary_type_name -SAMPLE1,SALM002,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM001.flat_sample.json.gz,Salmonella_houtenae,PASSED,Souza|Madjorio|Liverpool +SAMPLE1,SALM002,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM001.flat_sample.json.gz,Salmonella_houtenae,PASSED,Souza|Madjorio|Liverpool diff --git a/tests/data/samplesheets/samplesheet_sequence.csv b/tests/data/samplesheets/samplesheet_sequence.csv index 145849d..fd55b6f 100644 --- a/tests/data/samplesheets/samplesheet_sequence.csv +++ b/tests/data/samplesheets/samplesheet_sequence.csv @@ -1,6 +1,6 @@ sample,sample_name,mikrokondo_data,predicted_identification_name,qc_status_overall,predicted_primary_type_name -SAMPLE1,SALM001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM001.flat_sample.json.gz,Salmonella_houtenae,PASSED,"IV Y:g,z51:-" -SAMPLE2,SALM002,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM002.flat_sample.json.gz,Salmonella_enterica,FAILED,Souza|Madjorio|Liverpool -SAMPLE4,SALM005,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM005.flat_sample.json.gz,Salmonella_enterica,PASSED,Paratyphi A -SAMPLE6,CAMP001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/CAMP001.flat_sample.json.gz,Campylobacter coli,FAILED, -SAMPLE7,EC004,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/EC004.flat_sample.json.gz,Escherichia coli,FAILED,O103:H2 +SAMPLE1,SALM001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM001.flat_sample.json.gz,Salmonella_houtenae,PASSED,"IV Y:g,z51:-" +SAMPLE2,SALM002,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM002.flat_sample.json.gz,Salmonella_diarizonae,FAILED,"IIIb T:z35:z35" +SAMPLE4,SALM005,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM005.flat_sample.json.gz,Salmonella_enterica,PASSED,Paratyphi A +SAMPLE6,CAMP001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/CAMP001.flat_sample.json.gz,Campylobacter coli,FAILED, +SAMPLE7,EC004,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/EC004.flat_sample.json.gz,Escherichia coli,FAILED,O103:H2 diff --git a/tests/data/samplesheets/samplesheet_sistr.csv b/tests/data/samplesheets/samplesheet_sistr.csv index c6fd300..3f78501 100644 --- a/tests/data/samplesheets/samplesheet_sistr.csv +++ b/tests/data/samplesheets/samplesheet_sistr.csv @@ -1,10 +1,12 @@ sample,sample_name,mikrokondo_data,predicted_identification_name,qc_status_overall,predicted_primary_type_name -SAMPLE1,SALM001,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM001.flat_sample.json.gz,Salmonella_houtenae,PASSED,"IV Y:g,z51:-" -SAMPLE2,SALM002,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM002.flat_sample.json.gz,Salmonella_enterica,FAILED,Souza|Madjorio|Liverpool -SAMPLE3,SALM005,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM005.flat_sample.json.gz,Salmonella_enterica,PASSED,Paratyphi A -SAMPLE4,SALM008,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM008.flat_sample.json.gz,Salmonella enterica,PASSED,IIIb Y:z52:z -SAMPLE5,SALM009,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM009.flat_sample.json.gz,Salmonella_enterica,PASSED,Senftenberg -SAMPLE6,SALM010,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM010.flat_sample.json.gz,Salmonella enterica,PASSED,Umhlali|Adime|Birkenhead|Kivu|Norwich|Kastrup|Menston|Garoli|Daytona|Mkamba|Winston|Nigeria|Oyonnax|Eschweiler|Tienba|Planckendael|Massilia|Wohlen|Brindisi|Adamstua|Heerlen|Sharon|Remete -SAMPLE7,SALM007,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM007.flat_sample.json.gz,Salmonella_enterica,PASSED, -SAMPLE8,SALM011,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM011.flat_sample.json.gz,Salmonella enterica,PASSED,Adelaide|Agodi -SAMPLE9,SALM012,https://raw.githubusercontent.com/phac-nml/typingQC/dev/tests/data/SALM012.flat_sample.json.gz,Salmonella_enterica,PASSED,Ibadan|Mississippi +SAMPLE1,SALM001,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM001.flat_sample.json.gz,Salmonella_houtenae,PASSED,"IV Y:g,z51:-" +SAMPLE2,SALM002,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM002.flat_sample.json.gz,Salmonella_diarizonae,FAILED,"IIIb T:z35:z35" +SAMPLE3,SALM005,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM005.flat_sample.json.gz,Salmonella_enterica,PASSED,Paratyphi A +SAMPLE4,SALM008,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM008.flat_sample.json.gz,Salmonella enterica,PASSED,IIIb Y:z52:z +SAMPLE5,SALM009,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM009.flat_sample.json.gz,Salmonella_enterica,PASSED,Senftenberg +SAMPLE6,SALM010,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM010.flat_sample.json.gz,Salmonella enterica,PASSED,Umhlali|Adime|Birkenhead|Kivu|Norwich|Kastrup|Menston|Garoli|Daytona|Mkamba|Winston|Nigeria|Oyonnax|Eschweiler|Tienba|Planckendael|Massilia|Wohlen|Brindisi|Adamstua|Heerlen|Sharon|Remete +SAMPLE7,SALM007,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM007.flat_sample.json.gz,Salmonella_enterica,PASSED, +SAMPLE8,SALM011,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM011.flat_sample.json.gz,Salmonella enterica,PASSED,Adelaide|Agodi +SAMPLE9,SALM012,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM012.flat_sample.json.gz,Salmonella_enterica,PASSED,Ibadan|Mississippi +SAMPLE10,SALM013,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM013.flat_sample.json.gz,Salmonella enterica,PASSED,Panama +SAMPLE11,SALM014,https://raw.githubusercontent.com/phac-nml/typingQC/update/tests/data/SALM014.flat_sample.json.gz,Salmonella enterica,PASSED,Sendai diff --git a/tests/pipelines/main.nf.test b/tests/pipelines/main.nf.test index 9caf0c1..249a01b 100644 --- a/tests/pipelines/main.nf.test +++ b/tests/pipelines/main.nf.test @@ -92,10 +92,10 @@ nextflow_pipeline { assert values[0] == "SAMPLE2" assert values[1] == "SALM002" assert values[2].contains("[SEQ_FAIL] Sample may be contaminated.") - assert values[3].contains("[FAILED n50_value] 2038") - assert values[3].contains("[FAILED nr_contigs] 1712") - assert values[3].contains("[FAILED length] 3525632") - assert values[3].contains("[FAILED checkm_contamination] 4.2") + assert values[3].contains("[FAILED n50_value] 87033") + assert values[3].contains("[FAILED nr_contigs] 257") + assert values[3].contains("[FAILED length] 6443773") + assert values[3].contains("[FAILED checkm2_contamination] 6.35") def outputFile2 = path("$launchDir/results/sequenceqc/EC004_sequenceQC.csv") assert outputFile2.exists() @@ -181,6 +181,7 @@ nextflow_pipeline { assert path("$launchDir/results/merge/TypingQC_inputs.csv").exists() assert path("$launchDir/results/sequenceqc/SALM002_sequenceQC.csv").exists() assert path("$launchDir/results/sistrqc/SALM012_sistrQC.csv").exists() + assert path("$launchDir/results/sistrqc/SALM014_sistrQC.csv").exists() def outputFile_salm = path("$launchDir/results/sistrqc/SALM001_sistrQC.csv") assert outputFile_salm.exists() @@ -291,9 +292,60 @@ nextflow_pipeline { assert header_salm8 == ["sample", "sample_name", "typingQC_message", "quality_metrics"] assert values_salm8[0] == "SAMPLE2" assert values_salm8[1] == "SALM002" - assert values_salm8[2].contains("[SISTR_FAIL] Serotyping unsuccessful. RESEQUENCING or TRADITIONAL SEROTYPING is advised.") - assert values_salm8[3].contains("FAIL: Large number of cgMLST330 loci missing (n=149 > 30)") - } + assert values_salm8[2].contains("[TYPE_FAIL]") + assert values_salm8[3].contains("WARNING: Input genome size (6443773 bp) not within expected range of 4000000-6000000 (bp) for Salmonella") + + def outputFile_salm9 = path("$launchDir/results/sistrqc/SALM013_sistrQC.csv") + assert outputFile_salm9.exists() + + // Read CSV into rows + def csv_salm9 = outputFile_salm9.readLines() + def header_salm9 = csv_salm9[0].split(",") + def values_salm9 = csv_salm9[1].split(",",4) // Only split first 3 commas (4 columns) + + assert header_salm9 == ["sample", "sample_name", "typingQC_message", "quality_metrics"] + assert values_salm9[0] == "SAMPLE10" + assert values_salm9[1] == "SALM013" + assert values_salm9[2].contains("[SISTR_PASS]") + + def outputFile_salm10 = path("$launchDir/results/sistrqc/SALM014_sistrQC.csv") + assert outputFile_salm10.exists() + + // Read CSV into rows + def csv_salm10 = outputFile_salm10.readLines() + def header_salm10 = csv_salm10[0].split(",") + def values_salm10 = csv_salm10[1].split(",",4) // Only split first 3 commas (4 columns) + + assert header_salm10 == ["sample", "sample_name", "typingQC_message", "quality_metrics"] + assert values_salm10[0] == "SAMPLE11" + assert values_salm10[1] == "SALM014" + assert values_salm10[2].contains("[SISTR_PASS]") + assert values_salm10[3].contains("WARNING: Wzx/Wzy genes missing. Cannot determine O-antigen serogroup.") + + // check TypingQC_report csv file to ensure serovar updates are successful for sistrQC + + def outputFileQC = path("$launchDir/results/serotype/TypingQC_report.csv") + assert outputFileQC.exists() + + // Read CSV into rows + def csvQC = outputFileQC.readLines() + def headerQC = csvQC[0].split(",") + def valuesQC = csvQC[2].split(",", 7) + def valuesQC2 = csvQC[3].split(",", 7) + + assert headerQC == ["sample", "sample_name", "typingQC_message", "quality_metrics", "Validated_Toxins", "Validated_STXSubtypes", "Validated_Serotype"] + assert valuesQC[0] == "SAMPLE10" + assert valuesQC[1] == "SALM013" + assert valuesQC[2].contains("[SISTR_PASS]") + assert valuesQC[3].isEmpty() + assert valuesQC[6].contains("Panama/Houston") + assert valuesQC2[0] == "SAMPLE11" + assert valuesQC2[1] == "SALM014" + assert valuesQC2[2].contains("[SISTR_PASS]") + assert valuesQC2[3].contains("WARNING: Wzx/Wzy genes missing. Cannot determine O-antigen serogroup.; WARNING: Predicted serovar Sendai has been reported as Miami to conform with current CDC serovar nomenclature.") + assert valuesQC2[4].isEmpty() + assert valuesQC2[6].contains("Miami") + } } test("SISTR module without reportable serovar input"){