diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c99751f6..a8ab801e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # CHANGELOG +## 1.7.9: 2025-01-22 +- GCGI-1461: Fix output paths in calls to get_logger +- GCGI-1462: Extend GSICAPBENCH report to TAR/PWGS +- GCGI-1481: Fix raw coverage auto-population to exclude normal samples before selection in TAR assay +- GCGI-1478: More informative logger name for plugin/helper/merger components +- GCGI-1479: New `--pre-populate` option in `djerba.py` setup mode +- GCGI-1413: Remove failed report plugin and allow summary plugin to handle failed reports +- GCGI-1482: Updated total genome segment length constant in percent genome altered calculation +- GCGI-1480: Updated CGI manager name and email +- GCGI-1490: Remove input paths from pwgs.analysis results +- GCGI-1492: Remove the Sequenza CNV plugin + ## 1.7.8: 2024-12-12 - GCGI-1464: Standalone script to diff two Djerba JSON reports - GCGI-1454: Added OncoKB definitions to WGTS40X and WGS40X assays diff --git a/setup.py b/setup.py index 6a2bf984a..4cab6eb8b 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,8 @@ 'resources/*', 'R/*', 'r/*', - 'Rscripts/*' + 'Rscripts/*', + 'templates/*' ] with open("README.md", "r") as fh: @@ -49,7 +50,10 @@ 'data/20240315-allCuratedGenes.tsv', 'data/OncoTree.json', 'data/NCCN_annotations.txt', - 'data/benchmark_config.ini', + 'data/benchmark_pwgs.ini', + 'data/benchmark_tar.ini', + 'data/benchmark_wgs.ini', + 'data/benchmark_wgts.ini', 'data/benchmark_params.json', 'data/cytoBand.txt', 'data/ensemble_conversion_hg38.txt', diff --git a/src/bin/benchmark.py b/src/bin/benchmark.py index 43a7a0cdc..e3fe07c9e 100755 --- a/src/bin/benchmark.py +++ b/src/bin/benchmark.py @@ -6,7 +6,7 @@ import sys sys.path.pop(0) # do not import from script directory -from djerba.util.benchmark import benchmarker +from djerba.util.benchmark_tools import benchmarker def get_parser(): """Construct the parser for command-line arguments""" @@ -21,7 +21,7 @@ def get_parser(): # operations parser.add_argument('-i', '--input-dir', metavar='DIR', required=True, help='Directory to scan for workflow outputs, eg. ./GSICAPBENCHyymmdd/seqware-results/') parser.add_argument('-o', '--output-dir', metavar='DIR', required=True, help='Directory in which to generate HTML output') - parser.add_argument('-r', '--ref-path', metavar='FILE', required=True, help='Path to JSON file listing reference reports') + parser.add_argument('-r', '--ref-dir', metavar='DIR', required=True, help='Directory with reference index and reports') parser.add_argument('-s', '--sample', metavar='NAME', action='append', help='Sample names for directory scan; may be supplied more than once') parser.add_argument('-w', '--work-dir', metavar='DIR', required=True, help='Working directory in which to generate Djerba reports') cache_group = parser.add_mutually_exclusive_group() diff --git a/src/bin/diff_reports.py b/src/bin/diff_reports.py index 17363701d..51bba630b 100755 --- a/src/bin/diff_reports.py +++ b/src/bin/diff_reports.py @@ -7,7 +7,7 @@ sys.path.pop(0) # do not import from script directory -from djerba.util.benchmark import report_equivalence_tester +from djerba.util.benchmark_tools import report_equivalence_tester from djerba.util.logger import logger from djerba.util.validator import path_validator diff --git a/src/bin/djerba.py b/src/bin/djerba.py index 51dea3376..1865fd892 100755 --- a/src/bin/djerba.py +++ b/src/bin/djerba.py @@ -6,7 +6,7 @@ import sys sys.path.pop(0) # do not import from script directory -from djerba.core.main import main, arg_processor, DjerbaSubcommandError +from djerba.core.main import main, arg_processor, DjerbaInvalidNameError from djerba.version import get_djerba_version import djerba.util.constants as constants @@ -23,9 +23,10 @@ def get_parser(): parser.add_argument('--version', action='store_true', help='Print the version number and exit') subparsers = parser.add_subparsers(title='subcommands', help='sub-command help', dest='subparser_name') setup_parser = subparsers.add_parser(constants.SETUP, help='setup for a Djerba report') - setup_parser.add_argument('-a', '--assay', metavar='NAME', required=True, choices=['WGTS', 'WGS', 'TAR', 'PWGS'], help='Name of assay') + setup_parser.add_argument('-a', '--assay', metavar='NAME', required=True, help='Name of assay (case-insensitive)') setup_parser.add_argument('-i', '--ini', metavar='PATH', help='Output path for INI file; defaults to config.ini in current directory') setup_parser.add_argument('-c', '--compact', action='store_true', help="Output required manual parameters only") + setup_parser.add_argument('-p', '--pre-populate', metavar='PATH', help='INI file with key/value pairs to pre-populate config') config_parser = subparsers.add_parser(constants.CONFIGURE, help='get configuration parameters') config_parser.add_argument('-i', '--ini', metavar='PATH', required=True, help='INI config file with user inputs') config_parser.add_argument('-o', '--ini-out', metavar='PATH', required=True, help='Path for output of fully specified INI config file') @@ -69,7 +70,8 @@ def get_parser(): sys.exit(0) try: ap = arg_processor(args) - except DjerbaSubcommandError as err: + main(ap.get_work_dir(), ap.get_log_level(), ap.get_log_path()).run(args) + except DjerbaInvalidNameError as err: print("{0}".format(err), file=sys.stderr) sys.exit(1) - main(ap.get_work_dir(), ap.get_log_level(), ap.get_log_path()).run(args) + diff --git a/src/lib/djerba/core/configure.py b/src/lib/djerba/core/configure.py index de736991b..98950831e 100644 --- a/src/lib/djerba/core/configure.py +++ b/src/lib/djerba/core/configure.py @@ -43,7 +43,8 @@ def __init__(self, **kwargs): self.module_dir = kwargs[cc.MODULE_DIR] self.log_level = kwargs[cc.LOG_LEVEL] self.log_path = kwargs[cc.LOG_PATH] - self.logger = self.get_logger(self.log_level, __name__, self.log_path) + logger_name = 'djerba:'+self.identifier + self.logger = self.get_logger(self.log_level, logger_name, self.log_path) self.ini_required = set() # names of INI parameters the user must supply self.ini_defaults = {} # names and default values for other INI parameters @@ -373,7 +374,8 @@ def __init__(self, config, identifier, log_level=logging.WARNING, log_path=None) # identifier is the component identifier, used to retrieve INI params self.config = config self.identifier = identifier - self.logger = self.get_logger(log_level, __name__, log_path) + logger_name = 'djerba:'+self.identifier+':config_wrapper' + self.logger = self.get_logger(log_level, logger_name, log_path) def get_config(self): return self.config diff --git a/src/lib/djerba/core/html/clinical_header.html b/src/lib/djerba/core/html/clinical_header.html index 268606e76..3b2f09fa5 100644 --- a/src/lib/djerba/core/html/clinical_header.html +++ b/src/lib/djerba/core/html/clinical_header.html @@ -27,11 +27,11 @@ Main contact: - Alexander Fortuna, MSc + Beatriz Lujan Toro, MSc - Phone: - 416-673-8539 + Email: + gsi@oicr.on.ca Hours of Operation: diff --git a/src/lib/djerba/core/main.py b/src/lib/djerba/core/main.py index a985ba772..78c8fb085 100644 --- a/src/lib/djerba/core/main.py +++ b/src/lib/djerba/core/main.py @@ -437,9 +437,10 @@ def run(self, args): assay = ap.get_assay() compact = ap.get_compact() ini_path = ap.get_ini_path() + pre_populate = ap.get_pre_populate() if ini_path == None: ini_path = os.path.join(os.getcwd(), 'config.ini') - self.setup(assay, ini_path, compact) + self.setup(assay, ini_path, compact, pre_populate) elif mode == constants.CONFIGURE: ini_path = ap.get_ini_path() ini_path_out = ap.get_ini_out_path() # may be None @@ -485,9 +486,9 @@ def run(self, args): self.logger.error(msg) raise RuntimeError(msg) - def setup(self, assay, ini_path, compact): - if assay == 'WGTS': - component_list = [ + def setup(self, assay, ini_path, compact, pre_populate=None): + components_by_assay = { + 'WGTS': [ 'core', 'input_params_helper', 'provenance_helper', @@ -504,9 +505,8 @@ def setup(self, assay, ini_path, compact): 'fusion', 'gene_information_merger', 'supplement.body', - ] - elif assay == 'WGS': - component_list = [ + ], + 'WGS': [ 'core', 'input_params_helper', 'provenance_helper', @@ -521,9 +521,8 @@ def setup(self, assay, ini_path, compact): 'wgts.cnv_purple', 'gene_information_merger', 'supplement.body', - ] - elif assay == 'TAR': - component_list = [ + ], + 'TAR': [ 'core', 'tar_input_params_helper', 'provenance_helper', @@ -537,9 +536,8 @@ def setup(self, assay, ini_path, compact): 'tar.swgs', 'gene_information_merger', 'supplement.body', - ] - elif assay == 'PWGS': - component_list = [ + ], + 'PWGS': [ 'core', 'report_title', 'patient_info', @@ -551,12 +549,20 @@ def setup(self, assay, ini_path, compact): 'pwgs.analysis', 'supplement.body' ] + } + assay = assay.upper() + if assay in components_by_assay: + component_list = components_by_assay[assay] else: - msg = "Invalid assay name '{0}'".format(assay) + names = sorted(list(components_by_assay.keys())) + msg = "Invalid assay name '{0}'. ".format(assay)+\ + "Assay names are not case-sensitive; valid names are {0}".format(names) self.logger.error(msg) - raise ValueError(msg) + raise DjerbaInvalidNameError(msg) generator = ini_generator(self.log_level, self.log_path) generator.write_config(component_list, ini_path, compact) + if pre_populate is not None: + self.write_pre_population(ini_path, pre_populate) self.logger.info("Wrote config for {0} to {1}".format(assay, ini_path)) def update(self, config_path, json_path, out_dir, archive, pdf, summary_only, force): @@ -570,17 +576,22 @@ def update(self, config_path, json_path, out_dir, archive, pdf, summary_only, fo # 1. INI config with core + plugins to update # 2. Text file to update summary only # The 'summary_only' argument controls which one is used + with open(json_path, encoding=cc.TEXT_ENCODING) as in_file: + data = json.loads(in_file.read()) if summary_only: + # get failed/not-failed status from input data + failed = data[cc.PLUGINS]['summary'][cc.RESULTS]['failed'] + failed_opt = 'true' if failed else 'false' + self.logger.debug('Found report failure status: '+failed_opt) # make an appropriate ConfigParser on-the-fly config_in = ConfigParser() config_in.add_section(cc.CORE) config_in.add_section('summary') config_in.set('summary', 'summary_file', config_path) + config_in.set('summary', 'failed', failed_opt) config = self.configure_from_parser(config_in) else: config = self.configure(config_path) - with open(json_path, encoding=cc.TEXT_ENCODING) as in_file: - data = json.loads(in_file.read()) data_new = self.base_extract(config) data = self.update_data_from_file(data_new, json_path, force) if archive: @@ -616,6 +627,24 @@ def upload_archive(self, data): else: self.logger.warning(f"Archiving was NOT successful: {report_id}") + def write_pre_population(self, config_path, prepop_path): + # write pre-population values from one INI into another + # sections in prepop_path not present in config_path are silently ignored + cp_config = ConfigParser() + cp_prepop = ConfigParser() + cp_config.read(config_path) + cp_prepop.read(prepop_path) + total = 0 + for section in cp_config.sections(): + if section in cp_prepop.sections(): + for option in cp_prepop.options(section): + cp_config.set(section, option, cp_prepop.get(section, option)) + total += 1 + with open(config_path, 'w') as config_file: + cp_config.write(config_file) + template = "Pre-populated {0} value(s) in {1} from {2}" + self.logger.debug(template.format(total, config_path, prepop_path)) + class arg_processor(arg_processor_base): # class to process command-line args for creating a main object @@ -632,6 +661,9 @@ def get_ini_path(self): def get_ini_out_path(self): return self._get_arg('ini_out') + def get_pre_populate(self): + return self._get_arg('pre_populate') + def get_summary_path(self): return self._get_arg('summary') @@ -667,6 +699,8 @@ def validate_args(self, args): if args.subparser_name == constants.SETUP: if args.ini!=None: v.validate_output_file(args.ini) + if args.pre_populate!=None: + v.validate_input_file(args.pre_populate) elif args.subparser_name == constants.CONFIGURE: v.validate_input_file(args.ini) v.validate_output_file(args.ini_out) @@ -695,16 +729,16 @@ def validate_args(self, args): v.validate_output_dir(args.work_dir) elif args.subparser_name == None: msg = "No subcommand name given; run with -h/--help for valid names" - raise DjerbaSubcommandError(msg) + raise DjerbaInvalidNameError(msg) else: # shouldn't happen, but handle this case for completeness - raise DjerbaSubcommandError("Unknown subcommand: " + args.subparser_name) + raise DjerbaInvalidNameError("Unknown subcommand: " + args.subparser_name) self.logger.info("Command-line path validation finished.") class DjerbaDependencyError(Exception): pass -class DjerbaSubcommandError(Exception): +class DjerbaInvalidNameError(Exception): pass class DjerbaUpdateKeyError(Exception): diff --git a/src/lib/djerba/data/benchmark_pwgs.ini b/src/lib/djerba/data/benchmark_pwgs.ini new file mode 100644 index 000000000..2e45123f5 --- /dev/null +++ b/src/lib/djerba/data/benchmark_pwgs.ini @@ -0,0 +1,96 @@ +[report_title] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 10 +extract_priority = 10 +render_priority = 10 +failed = False + +[pwgs_provenance_helper] +attributes = +depends_configure = +depends_extract = +configure_priority = 50 +extract_priority = 50 +provenance_input_path = /.mounts/labs/CGI/private/djerba/benchmarking/provenance_subset.tsv.gz +project = GSICAPBENCH +donor = PLACEHOLDER +provenance_id = ${tumour_id} + +[core] +report_id = PWGS_REPORT_ID_PLACEHOLDER +attributes = +depends_configure = +depends_extract = +configure_priority = 100 +extract_priority = 100 +render_priority = 100 +report_version = 1 +archive_name = djerba +input_params = input_params.json +document_config = document_config.json + +[patient_info] + +[pwgs.case_overview] +primary_cancer = PLACEHOLDER +requisition_approved = 2025-01-01 +wgs_report_id = PLACEHOLDER +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 100 +extract_priority = 100 +render_priority = 100 +donor = ${donor} +group_id = PLACEHOLDER +patient_study_id = PLACEHOLDER +study = PLACEHOLDER + +[pwgs.summary] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 130 +extract_priority = 130 +render_priority = 130 +results_file = ${mrdetect_txt} + +[pwgs.sample] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 160 +extract_priority = 160 +render_priority = 160 +qcetl_cache = /scratch2/groups/gsi/production/qcetl_v1 +bamqc_results = ${bamqc_file} +results_file = ${mrdetect_txt} +candidate_snv_count = ${mrdetect_snp} +coverage = 75 +median_insert_size = 165 + +[pwgs.analysis] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 200 +extract_priority = 200 +render_priority = 200 +results_file = ${mrdetect_txt} +vaf_file = ${mrdetect_vaf} +hbc_file = ${mrdetect_hbc} + +[supplement.body] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 1200 +extract_priority = 1200 +render_priority = 1200 +assay = PWGS +clinical_geneticist_name = PLACEHOLDER +clinical_geneticist_licence = XXXXXXX +failed = False + diff --git a/src/lib/djerba/data/benchmark_tar.ini b/src/lib/djerba/data/benchmark_tar.ini new file mode 100644 index 000000000..9d67d3637 --- /dev/null +++ b/src/lib/djerba/data/benchmark_tar.ini @@ -0,0 +1,178 @@ +[tar_input_params_helper] +assay = TAR +cbio_id = PLACEHOLDER +donor = ${donor} +known_variants = None +normal_id = ${normal_id} +oncotree_code = HGSOC +patient_study_id = ${donor}_STUDY_ID +primary_cancer = PLACEHOLDER +project = PLACEHOLDER +requisition_approved = 2024-01-01 +requisition_id = ${donor}_REQ_ID +sample_type = cfDNA +site_of_biopsy = cfDNA +study = PLACEHOLDER +tumour_id = ${tumour_id} +attributes = +depends_configure = +depends_extract = +configure_priority = 10 +extract_priority = 10 + +[report_title] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 10 +extract_priority = 10 +render_priority = 10 +failed = False + +[provenance_helper] +sample_name_normal = ${normal_id} +sample_name_tumour = ${tumour_id} +sample_name_aux = SNWT_PLACEHOLDER +tumour_id = ${tumour_id} +normal_id = ${normal_id} +attributes = +depends_configure = +depends_extract = +configure_priority = 50 +extract_priority = 50 +provenance_input_path = /.mounts/labs/CGI/private/djerba/benchmarking/provenance_subset.tsv.gz +project = REVTAR +donor = ${donor} +assay = TAR + +[core] +attributes = +depends_configure = +depends_extract = +configure_priority = 100 +extract_priority = 100 +render_priority = 100 +author = PLACEHOLDER +report_id = __DJERBA_NULL__ +report_version = 1 +input_params = input_params.json +document_config = document_config.json + +[patient_info] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 100 +extract_priority = 100 +render_priority = 30 +patient_name = LAST, FIRST +patient_dob = YYYY-MM-DD +patient_genetic_sex = SEX +requisitioner_email = NAME@domain.com +physician_licence_number = nnnnnnnn +physician_name = LAST, FIRST +physician_phone_number = nnn-nnn-nnnn +hospital_name_and_address = HOSPITAL NAME AND ADDRESS + +[case_overview] +attributes = clinical +depends_configure = provenance_helper +depends_extract = +configure_priority = 200 +extract_priority = 200 +render_priority = 40 +assay = TAR +assay_description = Targeted Sequencing - REVOLVE Panel - cfDNA and Buffy Coat (v3.0) +site_of_biopsy = cfDNA +donor = __DJERBA_NULL__ +normal_id = ${normal_id} +patient_study_id = __DJERBA_NULL__ +primary_cancer = __DJERBA_NULL__ +report_id = __DJERBA_NULL__ +requisition_approved = __DJERBA_NULL__ +study = __DJERBA_NULL__ +tumour_id = ${tumour_id} + +[treatment_options_merger] +attributes = clinical,supplementary +depends_configure = +configure_priority = 300 +render_priority = 50 + +[tar.sample] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 300 +extract_priority = 200 +render_priority = 500 +group_id = PLACEHOLDER +oncotree_code = HGSOC +known_variants = None +sample_type = cfDNA +ichorcna_file = ${ichorcna_file} +raw_coverage = 27000 +consensus_cruncher_file = ${consensus_cruncher_tumour} +consensus_cruncher_file_normal = ${consensus_cruncher_normal} +collapsed_coverage_pl = 2000 +collapsed_coverage_bc = 1500 + +[summary] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 400 +extract_priority = 400 +render_priority = 400 +summary_file = __DJERBA_NULL__ + +[tar.swgs] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 400 +extract_priority = 250 +render_priority = 700 +donor = REVOLVE_0046 +oncotree_code = HGSOC +tumour_id = ${tumour_id} +seg_file = ${seg_file} +clinical = True +supplementary = False + +[tar.snv_indel] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 600 +extract_priority = 600 +render_priority = 600 +donor = ${donor} +oncotree_code = HGSOC +assay = TAR +cbio_id = REVOLVE +tumour_id = ${tumour_id} +normal_id = ${normal_id} +maf_file = ${maf_path_tar_tumour} +maf_file_normal = ${maf_path_tar_normal} + +[supplement.body] +attributes = clinical +depends_configure = +depends_extract = +configure_priority = 1200 +extract_priority = 1200 +render_priority = 1200 +assay = TAR +report_signoff_date = __DJERBA_NULL__ +user_supplied_draft_date = __DJERBA_NULL__ +clinical_geneticist_name = PLACEHOLDER +clinical_geneticist_licence = XXXXXXX +failed = False + +[gene_information_merger] +attributes = clinical,supplementary +depends_configure = +configure_priority = 2000 +render_priority = 2000 + diff --git a/src/lib/djerba/data/benchmark_wgs.ini b/src/lib/djerba/data/benchmark_wgs.ini new file mode 100644 index 000000000..100ec5d12 --- /dev/null +++ b/src/lib/djerba/data/benchmark_wgs.ini @@ -0,0 +1,143 @@ +[core] +archive_name = djerba +archive_url = http://admin:djerba123@10.30.133.78:5984 +attributes = +configure_priority = 100 +depends_configure = +depends_extract = +document_config = document_config.json +extract_priority = 100 +render_priority = 100 +report_id = __DJERBA_NULL__ +report_version = 1 +input_params = input_params.json + +[report_title] + +[patient_info] + +[input_params_helper] +assay = WGTS +donor = ${donor} +oncotree_code = PAAD +primary_cancer = Pancreatic Adenocarcinoma +project = ${project} +requisition_approved = 2022-01-01 +requisition_id = REQ_ID_PLACEHOLDER +sample_type = LCM +site_of_biopsy = Test site +study = PASS-01 +tcgacode = PAAD +attributes = +configure_priority = 10 +depends_configure = +depends_extract = +extract_priority = 10 + +[provenance_helper] +attributes = +configure_priority = 50 +depends_configure = +depends_extract = +donor = __DJERBA_NULL__ +extract_priority = 50 +project = __DJERBA_NULL__ +provenance_input_path = /.mounts/labs/CGI/private/djerba/benchmarking/provenance_subset.tsv.gz +sample_name_normal = ${normal_id} +sample_name_tumour = ${tumour_id} +sample_name_aux = SNWT_PLACEHOLDER +tumour_id = ${tumour_id} +normal_id = ${normal_id} + +[gene_information_merger] +attributes = clinical,supplementary +configure_priority = 1100 +depends_configure = +render_priority = 1100 + +[treatment_options_merger] +attributes = clinical,supplementary +configure_priority = 300 +depends_configure = +render_priority = 300 + +[case_overview] +assay = WGTS +assay_description = __DJERBA_NULL__ +attributes = clinical +configure_priority = 200 +depends_configure = provenance_helper +depends_extract = +donor = __DJERBA_NULL__ +extract_priority = 200 +normal_id = ${normal_id} +patient_study_id = __DJERBA_NULL__ +primary_cancer = __DJERBA_NULL__ +render_priority = 200 +report_id = __DJERBA_NULL__ +requisition_approved = __DJERBA_NULL__ +site_of_biopsy = __DJERBA_NULL__ +study = __DJERBA_NULL__ +tumour_id = ${tumour_id} + +[genomic_landscape] +apply cache = ${apply_cache} +ctdna_file=${ctdna_file} +msi_file=${msi_file} +hrd_path=${hrd_file} +oncokb cache = /.mounts/labs/CGI/gsi/tools/djerba/oncokb_cache/bench +oncotree_code = paad +tumour_id = ${tumour_id} +update cache = ${update_cache} + +[sample] +attributes = clinical +callability = 90.0 +configure_priority = 500 +depends_configure = +depends_extract = +extract_priority = 500 +mean_coverage = 100 +oncotree_code = __DJERBA_NULL__ +ploidy = __DJERBA_NULL__ +purity = ${purity} +render_priority = 500 +sample_type = __DJERBA_NULL__ + +[summary] +attributes = clinical +configure_priority = 400 +depends_configure = +depends_extract = +extract_priority = 400 +render_priority = 400 +summary_file = __DJERBA_NULL__ + +[supplement.body] +assay = __DJERBA_NULL__ +attributes = clinical +configure_priority = 1200 +depends_configure = +depends_extract = +extract_priority = 1200 +failed = False +render_priority = 1200 + +[wgts.cnv_purple] +tumour_id = ${tumour_id} +oncotree_code = PAAD +purple_zip=${purple_path} +whizbam_project=PASS01 +assay=WGTS + +[wgts.snv_indel] +apply cache = ${apply_cache} +attributes = clinical +configure_priority = 700 +depends_configure = +depends_extract = +extract_priority = 800 +oncokb cache = /.mounts/labs/CGI/gsi/tools/djerba/oncokb_cache/bench +render_priority = 700 +update cache = ${update_cache} +maf_path = ${maf_path} diff --git a/src/lib/djerba/data/benchmark_config.ini b/src/lib/djerba/data/benchmark_wgts.ini similarity index 100% rename from src/lib/djerba/data/benchmark_config.ini rename to src/lib/djerba/data/benchmark_wgts.ini diff --git a/src/lib/djerba/mergers/factory.py b/src/lib/djerba/mergers/factory.py index e9ced3fa3..42838a3aa 100644 --- a/src/lib/djerba/mergers/factory.py +++ b/src/lib/djerba/mergers/factory.py @@ -10,7 +10,7 @@ class factory(logger, ABC): def __init__(self, log_level=logging.WARNING, log_path=None): - self.logger = self.get_logger(log_level, log_path) + self.logger = self.get_logger(log_level, __name__, log_path) def get_json(**kwargs): """ diff --git a/src/lib/djerba/plugins/benchmark/benchmark_template.html b/src/lib/djerba/plugins/benchmark/benchmark_template.html index 85641f0db..0bd52fcad 100644 --- a/src/lib/djerba/plugins/benchmark/benchmark_template.html +++ b/src/lib/djerba/plugins/benchmark/benchmark_template.html @@ -22,13 +22,13 @@

Run time: ${results.get('run_time')}

- % for name in ['Donor', 'Status', 'Input JSON', 'Reference JSON', 'Diff']: + % for name in ['Report', 'Status', 'Input JSON', 'Reference JSON', 'Diff']: % endfor - % for r in results.get('donor_results'): + % for r in results.get('report_results'): - % for k in ['donor', 'status_emoji']: + % for k in ['report', 'status_emoji']: % endfor % for k in ['input_file', 'ref_file', 'diff_name']: @@ -49,7 +49,7 @@

Run time: ${results.get('run_time')}

  • Status key: diff --git a/src/lib/djerba/plugins/benchmark/plugin.py b/src/lib/djerba/plugins/benchmark/plugin.py index 26b007652..05649492e 100644 --- a/src/lib/djerba/plugins/benchmark/plugin.py +++ b/src/lib/djerba/plugins/benchmark/plugin.py @@ -5,10 +5,11 @@ import json import logging +import os import djerba.core.constants as core_constants from djerba.plugins.base import plugin_base -from djerba.util.benchmark import report_equivalence_tester +from djerba.util.benchmark_tools import report_equivalence_tester from djerba.util.date import get_timestamp from djerba.util.render_mako import mako_renderer from djerba.util.environment import directory_finder @@ -19,11 +20,13 @@ class main(plugin_base): PRIORITY = 10 PLUGIN_VERSION = '0.0.1' TEMPLATE_NAME = 'benchmark_template.html' - DONOR = 'donor' - DONOR_RESULTS = 'donor_results' + REPORT = 'report' + REPORT_RESULTS = 'report_results' BODY = 'body' INPUT_FILE = 'input_file' + REF_DIR = 'ref_dir' REF_FILE = 'ref_file' + REF_FILE_NAME = 'bench_ref_paths.json' STATUS = 'status' STATUS_EMOJI = 'status_emoji' DIFF = 'diff' @@ -35,20 +38,16 @@ class main(plugin_base): # __init__ is inherited from the parent class - def compare_reports(self, inputs_path, refs_path, delta_path): - with open(inputs_path) as in_file: - input_paths = json.load(in_file) - with open(refs_path) as in_file: - ref_paths = json.load(in_file) + def compare_reports(self, input_paths, ref_paths, delta_path): input_set = set(input_paths.keys()) ref_set = set(ref_paths.keys()) - donor_results = [] - for donor in sorted(list(input_set.union(ref_set))): + report_results = [] + for report in sorted(list(input_set.union(ref_set))): # load the input and reference report JSON files # find status (and full-text diff, if any) # record for output JSON - input_path = input_paths.get(donor) - ref_path = ref_paths.get(donor) + input_path = input_paths.get(report) + ref_path = ref_paths.get(report) if input_path and ref_path: tester = report_equivalence_tester( [input_path, ref_path], delta_path, self.log_level, self.log_path @@ -60,16 +59,16 @@ def compare_reports(self, inputs_path, refs_path, delta_path): status = 'INCOMPLETE' status_emoji = '❓' # question mark diff = 'NA' - input_file = input_paths.get(donor, self.NOT_FOUND) - ref_file = ref_paths.get(donor, self.NOT_FOUND) + input_file = input_paths.get(report, self.NOT_FOUND) + ref_file = ref_paths.get(report, self.NOT_FOUND) if input_file == self.NOT_FOUND or ref_file == self.NOT_FOUND: diff_name = self.NOT_FOUND elif status == tester.IDENTICAL_STATUS: diff_name = self.NOT_APPLICABLE else: - diff_name = donor+"_diff.txt" + diff_name = report+"_diff.txt" result = { - self.DONOR: donor, + self.REPORT: report, self.STATUS: status, self.STATUS_EMOJI: status_emoji, self.DIFF: diff, @@ -77,8 +76,8 @@ def compare_reports(self, inputs_path, refs_path, delta_path): self.INPUT_FILE: input_file, self.REF_FILE: ref_file } - donor_results.append(result) - return donor_results + report_results.append(result) + return report_results def configure(self, config): config = self.apply_defaults(config) @@ -88,8 +87,15 @@ def configure(self, config): def extract(self, config): wrapper = self.get_config_wrapper(config) + # validate the inputs attributes = wrapper.get_my_attributes() self.check_attributes_known(attributes) + validator = path_validator(self.log_level, self.log_path) + in_path = wrapper.get_my_string(self.INPUT_FILE) + validator.validate_input_file(in_path) + ref_dir = wrapper.get_my_string(self.REF_DIR) + validator.validate_input_dir(ref_dir) + # extract the data data = { 'plugin_name': self.identifier+' plugin', 'version': self.PLUGIN_VERSION, @@ -97,21 +103,35 @@ def extract(self, config): 'attributes': attributes, 'merge_inputs': {} } - input_file = wrapper.get_my_string(self.INPUT_FILE) - ref_file = wrapper.get_my_string(self.REF_FILE) - validator = path_validator(self.log_level, self.log_path) - validator.validate_input_file(input_file) - validator.validate_input_file(ref_file) + with open(in_path) as in_file: + input_paths = json.load(in_file) + ref_paths = self.get_ref_paths(ref_dir, validator) delta_file = None # TODO make this configurable - donor_results = self.compare_reports(input_file, ref_file, delta_file) - self.logger.debug('Found {0} donor results'.format(len(donor_results))) + report_results = self.compare_reports(input_paths, ref_paths, delta_file) + self.logger.debug('Found {0} report results'.format(len(report_results))) data['results'] = { self.INPUT_NAME: wrapper.get_my_string(self.INPUT_NAME), self.RUN_TIME: get_timestamp(), - self.DONOR_RESULTS: donor_results + self.REPORT_RESULTS: report_results } return data + def get_ref_paths(self, ref_dir, validator): + # The ref_dir contains an index file, listing relative paths to Djerba JSON reports. + # The index file contains a list of identifiers we expect to see. + # Some identifiers from the index may be absent from the input data, eg. because of + # workflow failures. This is shown in the HTML output. + ref_index_path = os.path.join(ref_dir, self.REF_FILE_NAME) + validator.validate_input_file(ref_index_path) + with open(ref_index_path) as index_file: + ref_index = json.loads(index_file.read()) + ref_index_full_paths = {} + for key, val in ref_index.items(): + full_path = os.path.join(ref_dir, val) + validator.validate_input_file(full_path) + ref_index_full_paths[key] = full_path + return ref_index_full_paths + def render(self, data): renderer = mako_renderer(self.get_module_dir()) return renderer.render_name(self.TEMPLATE_NAME, data) @@ -120,7 +140,7 @@ def specify_params(self): self.set_ini_default(core_constants.ATTRIBUTES, 'research') self.set_priority_defaults(self.PRIORITY) self.add_ini_required(self.INPUT_FILE) - self.add_ini_required(self.REF_FILE) + self.add_ini_required(self.REF_DIR) self.add_ini_discovered(self.INPUT_NAME) #finder = directory_finder(self.log_level, self.log_path) #default_delta_path = diff --git a/src/lib/djerba/plugins/benchmark/test/benchmark.json b/src/lib/djerba/plugins/benchmark/test/benchmark.json index dd4e14b0b..aaca7b678 100644 --- a/src/lib/djerba/plugins/benchmark/test/benchmark.json +++ b/src/lib/djerba/plugins/benchmark/test/benchmark.json @@ -10,27 +10,117 @@ "render": 10 }, "results": { - "donor_results": [ + "input_name": "Unknown", + "report_results": [ + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_0001_TAR_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_0001_TAR_ref.json", + "report": "GSICAPBENCH_0001_TAR", + "status": "identical", + "status_emoji": "✅" + }, + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_0001_WGS_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_0001_WGS_ref.json", + "report": "GSICAPBENCH_0001_WGS", + "status": "identical", + "status_emoji": "✅" + }, + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_0002_TAR_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_0002_TAR_ref.json", + "report": "GSICAPBENCH_0002_TAR", + "status": "identical", + "status_emoji": "✅" + }, + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_0003_TAR_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_0003_TAR_ref.json", + "report": "GSICAPBENCH_0003_TAR", + "status": "identical", + "status_emoji": "✅" + }, + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_011291_PWGS_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_011291_PWGS_ref.json", + "report": "GSICAPBENCH_011291_PWGS", + "status": "identical", + "status_emoji": "✅" + }, { "diff": "NONE", "diff_name": "Not applicable", - "donor": "GSICAPBENCH_1219", - "input_file": "PLACEHOLDER/GSICAPBENCH_1219_input.json", - "ref_file": "PLACEHOLDER/GSICAPBENCH_1219_reference.json", + "input_file": "PLACEHOLDER/GSICAPBENCH_011303_PWGS_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_011303_PWGS_ref.json", + "report": "GSICAPBENCH_011303_PWGS", "status": "identical", "status_emoji": "✅" }, { "diff": "NONE", "diff_name": "Not applicable", - "donor": "GSICAPBENCH_1232", - "input_file": "PLACEHOLDER/GSICAPBENCH_1232_input.json", - "ref_file": "PLACEHOLDER/GSICAPBENCH_1232_reference.json", + "input_file": "PLACEHOLDER/GSICAPBENCH_011524_PWGS_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_011524_PWGS_ref.json", + "report": "GSICAPBENCH_011524_PWGS", + "status": "identical", + "status_emoji": "✅" + }, + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_011633_PWGS_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_011633_PWGS_ref.json", + "report": "GSICAPBENCH_011633_PWGS", + "status": "identical", + "status_emoji": "✅" + }, + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_1248_WGTS_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_1248_WGTS_ref.json", + "report": "GSICAPBENCH_1248_WGTS", + "status": "identical", + "status_emoji": "✅" + }, + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_1309_WGTS_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_1309_WGTS_ref.json", + "report": "GSICAPBENCH_1309_WGTS", + "status": "identical", + "status_emoji": "✅" + }, + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_1390_WGTS_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_1390_WGTS_ref.json", + "report": "GSICAPBENCH_1390_WGTS", + "status": "identical", + "status_emoji": "✅" + }, + { + "diff": "NONE", + "diff_name": "Not applicable", + "input_file": "PLACEHOLDER/GSICAPBENCH_1391_WGTS_report.json", + "ref_file": "PLACEHOLDER/GSICAPBENCH_1391_WGTS_ref.json", + "report": "GSICAPBENCH_1391_WGTS", "status": "identical", "status_emoji": "✅" } ], - "input_name": "Unknown", "run_time": "PLACEHOLDER" }, "version": "0.0.1" diff --git a/src/lib/djerba/plugins/benchmark/test/plugin_test.py b/src/lib/djerba/plugins/benchmark/test/plugin_test.py index 6fb12f3cf..b213ab35e 100644 --- a/src/lib/djerba/plugins/benchmark/test/plugin_test.py +++ b/src/lib/djerba/plugins/benchmark/test/plugin_test.py @@ -5,8 +5,10 @@ import logging import unittest import tempfile -import djerba.core.constants as constants from configparser import ConfigParser +from shutil import copy + +import djerba.core.constants as constants from djerba.plugins.plugin_tester import PluginTester from djerba.plugins.benchmark.plugin import main as BenchmarkPlugin from djerba.util.environment import directory_finder @@ -21,48 +23,59 @@ def setUp(self): self.maxDiff = None self.tmp = tempfile.TemporaryDirectory(prefix='djerba_') self.tmp_dir = self.tmp.name + self.test_source_dir = os.path.realpath(os.path.dirname(__file__)) def testBenchmark(self): - data_dir_root = directory_finder().get_test_dir() - data_dir = os.path.join(data_dir_root, 'plugins', 'benchmark') - test_source_dir = os.path.realpath(os.path.dirname(__file__)) - json_location = os.path.join(test_source_dir, "benchmark.json") + json_location = os.path.join(self.test_source_dir, "benchmark.json") data_dir_root = directory_finder().get_test_dir() data_dir = os.path.join(data_dir_root, 'plugins', 'benchmark') params = { self.INI: self.write_ini_file(data_dir), self.JSON: json_location, - self.MD5: 'bd6a26968d6f384dd43c9c7b1f511dd6' + self.MD5: '473048e8505edbbfdc3e84a7e856e176' } - self.run_basic_test(test_source_dir, params) + self.run_basic_test(self.test_source_dir, params) def redact_json_data(self, data): results = data['results'] - redacted_donor_results = [] + redacted_report_results = [] for k,v in results.items(): - if k == 'donor_results': - for donor_result in v: - for k2,v2 in donor_result.items(): + if k == 'report_results': + for report_result in v: + for k2,v2 in report_result.items(): if k2 in ['input_file', 'ref_file']: file_name = os.path.basename(v2) - donor_result[k2] = os.path.join(self.PLACEHOLDER, file_name) - redacted_donor_results.append(donor_result) + report_result[k2] = os.path.join(self.PLACEHOLDER, file_name) + redacted_report_results.append(report_result) elif k=='run_time': results[k] = self.PLACEHOLDER elif k=='input_name': results[k] = 'Unknown' - results['donor_results'] = redacted_donor_results + results['report_results'] = redacted_report_results data['results'] = results return data def write_ini_file(self, data_dir): # write input/ref JSON on the fly, using individual report JSONs in data dir - donors = ['GSICAPBENCH_1219', 'GSICAPBENCH_1232'] + names = [ + 'GSICAPBENCH_0001_WGS', + 'GSICAPBENCH_0001_TAR', + 'GSICAPBENCH_0002_TAR', + 'GSICAPBENCH_0003_TAR', + 'GSICAPBENCH_011291_PWGS', + 'GSICAPBENCH_011303_PWGS', + 'GSICAPBENCH_011524_PWGS', + 'GSICAPBENCH_011633_PWGS', + 'GSICAPBENCH_1248_WGTS', + 'GSICAPBENCH_1309_WGTS', + 'GSICAPBENCH_1390_WGTS', + 'GSICAPBENCH_1391_WGTS' + ] inputs = {} refs = {} - for donor in donors: - inputs[donor] = os.path.join(data_dir, donor+'_input.json') - refs[donor] = os.path.join(data_dir, donor+'_reference.json') + for name in names: + inputs[name] = os.path.join(data_dir, name+'_report.json') + refs[name] = os.path.join(data_dir, name+'_report.json') input_path = os.path.join(self.tmp_dir, 'inputs.json') with open(input_path, 'w') as input_file: input_file.write(json.dumps(inputs)) @@ -73,7 +86,9 @@ def write_ini_file(self, data_dir): cp.add_section('core') cp.add_section('benchmark') cp.set('benchmark', BenchmarkPlugin.INPUT_FILE, input_path) - cp.set('benchmark', BenchmarkPlugin.REF_FILE, ref_path) + private_dir = directory_finder().get_private_dir() + ref_dir = os.path.join(private_dir, 'benchmarking', 'djerba_bench_reference') + cp.set('benchmark', BenchmarkPlugin.REF_DIR, ref_dir) ini_path = os.path.join(self.tmp_dir, 'benchmark.ini') with open(ini_path, 'w') as ini_file: cp.write(ini_file) diff --git a/src/lib/djerba/plugins/cnv/__init__.py b/src/lib/djerba/plugins/cnv/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/lib/djerba/plugins/cnv/cnv_template.html b/src/lib/djerba/plugins/cnv/cnv_template.html deleted file mode 100644 index 96dd77030..000000000 --- a/src/lib/djerba/plugins/cnv/cnv_template.html +++ /dev/null @@ -1,39 +0,0 @@ - -## This file is the HTML code for the Copy Number Variation (CNV) section of the report. - -<% - import djerba.plugins.wgts.common.cnv.constants as cnv - from djerba.plugins.cnv.html import make_table_header, make_table_rows - from djerba.util.html import html_builder -%> - - - -${html_builder.section_cells_begin("Copy Number Variation", True)} - -

    The percent genome altered (PGA) was ${results.get(cnv.PERCENT_GENOME_ALTERED)}%. - ${results.get(cnv.TOTAL_VARIANTS)} cancer gene(s) were subject to copy number variation, - of which ${results.get(cnv.CLINICALLY_RELEVANT_VARIANTS)} corresponded to an oncogenic alteration, as defined by OncoKB. - Regions with large copy number gains (≥ 6 CN) marked as ▲ in plot below. -

    - - - % if results.get(cnv.CLINICALLY_RELEVANT_VARIANTS) > 0: -
  • ${name}
    ${r.get(k)}
    - ${make_table_header()} - - % for row in make_table_rows(results.get(cnv.BODY)): - ${row} - % endfor -
    - - - % if results.get(cnv.HAS_EXPRESSION_DATA): - - -
    Expr. (%): Expression Percentile for gene mRNA, or NA if comparison data is not available
    - % endif - - % endif - -${html_builder.section_cells_end()} diff --git a/src/lib/djerba/plugins/cnv/plugin.py b/src/lib/djerba/plugins/cnv/plugin.py deleted file mode 100644 index 62af97a53..000000000 --- a/src/lib/djerba/plugins/cnv/plugin.py +++ /dev/null @@ -1,119 +0,0 @@ -""" -Plugin for whole-genome CNV reporting -""" - -import os -import djerba.core.constants as core_constants -import djerba.plugins.wgts.common.cnv.constants as cnv_constants -import djerba.util.oncokb.constants as oncokb_constants -from djerba.helpers.input_params_helper.helper import main as input_params_helper -from djerba.plugins.base import plugin_base, DjerbaPluginError -from djerba.plugins.wgts.common.cnv.tools import cnv_processor -from djerba.util.sequenza import sequenza_reader -from djerba.util.render_mako import mako_renderer - -class main(plugin_base): - - PLUGIN_VERSION = '1.0.0' - TEMPLATE_NAME = 'cnv_template.html' - - # priorities -- selected so CNV is extracted before SNV/indel but rendered after - CONFIGURE = 800 - EXTRACT = 700 - RENDER = 800 - - def check_purity_is_consistent(self, cnv_purity): - """Check CNV purity is consistent with input_params_helper value (if any)""" - delta = 0.0000001 # tolerance for float value check - if self.workspace.has_file(input_params_helper.INPUT_PARAMS_FILE): - data = self.workspace.read_json(input_params_helper.INPUT_PARAMS_FILE) - iph_purity = data.get(input_params_helper.PURITY) - if iph_purity != None and abs(iph_purity - cnv_purity) > delta: - msg = "Inconsistent purity values! "+\ - "CNV plugin purity = {0}, ".format(cnv_purity)+\ - "Input params helper purity = {0}. ".format(iph_purity)+\ - "Update CNV and/or input params INI config so values match." - self.logger.error(msg) - raise RuntimeError(msg) - else: - self.logger.info("Purity configuration check successful") - else: - self.logger.info("Input params JSON not found, purity check omitted") - - def configure(self, config): - config = self.apply_defaults(config) - wrapper = self.get_config_wrapper(config) - wrapper = self.update_wrapper_if_null( - wrapper, - input_params_helper.INPUT_PARAMS_FILE, - cnv_constants.ONCOTREE_CODE, - input_params_helper.ONCOTREE_CODE - ) - wrapper = self.update_wrapper_if_null( - wrapper, - core_constants.DEFAULT_SAMPLE_INFO, - cnv_constants.TUMOUR_ID, - 'tumour_id' - ) - wrapper = self.update_wrapper_if_null( - wrapper, - core_constants.DEFAULT_PATH_INFO, - cnv_constants.SEQUENZA_PATH, - 'sequenza_by_tumor_group' - ) - if wrapper.my_param_is_null(cnv_constants.PURITY): - gamma = wrapper.get_my_int(cnv_constants.SEQUENZA_GAMMA) - solution = wrapper.get_my_string(cnv_constants.SEQUENZA_SOLUTION) - reader = sequenza_reader(wrapper.get_my_string(cnv_constants.SEQUENZA_PATH)) - purity = reader.get_purity(gamma, solution) - wrapper.set_my_param(cnv_constants.PURITY, purity) - self.logger.debug("Found purity {0} from sequenza results".format(purity)) - else: - purity = wrapper.get_my_float(cnv_constants.PURITY) - self.logger.debug("Using user-supplied purity: {0}".format(purity)) - if wrapper.get_my_boolean(cnv_constants.PURITY_CHECK): - self.check_purity_is_consistent(purity) - return wrapper.get_config() - - def extract(self, config): - work_dir = self.workspace.get_work_dir() - wrapper = self.get_config_wrapper(config) - # write intermediate files to working directory - processor = cnv_processor(work_dir, wrapper, self.log_level, self.log_path) - processor.write_working_files() - # read results from working directory into data structure - data = self.get_starting_plugin_data(wrapper, self.PLUGIN_VERSION) - data['results'] = processor.get_results() - data['merge_inputs'] = processor.get_merge_inputs() - return data - - def render(self, data): - renderer = mako_renderer(self.get_module_dir()) - return renderer.render_name(self.TEMPLATE_NAME, data) - - def specify_params(self): - required = [ - cnv_constants.SEQUENZA_GAMMA, - cnv_constants.SEQUENZA_SOLUTION, - ] - for key in required: - self.add_ini_required(key) - discovered = [ - cnv_constants.ONCOTREE_CODE, - cnv_constants.SEQUENZA_PATH, - cnv_constants.PURITY, - cnv_constants.TUMOUR_ID - ] - self.set_ini_default( - oncokb_constants.ONCOKB_CACHE, - oncokb_constants.DEFAULT_CACHE_PATH - ) - self.set_ini_default(oncokb_constants.APPLY_CACHE, False) - self.set_ini_default(oncokb_constants.UPDATE_CACHE, False) - for key in discovered: - self.add_ini_discovered(key) - self.set_ini_default(core_constants.ATTRIBUTES, 'clinical') - self.set_ini_default(cnv_constants.PURITY_CHECK, True) - self.set_ini_default(core_constants.CONFIGURE_PRIORITY, self.CONFIGURE) - self.set_ini_default(core_constants.EXTRACT_PRIORITY, self.EXTRACT) - self.set_ini_default(core_constants.RENDER_PRIORITY, self.RENDER) diff --git a/src/lib/djerba/plugins/cnv/test/__init__.py b/src/lib/djerba/plugins/cnv/test/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/lib/djerba/plugins/cnv/test/cnv.ini b/src/lib/djerba/plugins/cnv/test/cnv.ini deleted file mode 100644 index 95f93a18f..000000000 --- a/src/lib/djerba/plugins/cnv/test/cnv.ini +++ /dev/null @@ -1,9 +0,0 @@ -[core] - -[cnv] -sequenza_path = $SEQUENZA_PATH -sequenza_gamma=400 -sequenza_solution=_primary_ -tumour_id = 100-NH-020_LCM3 -purity=0.6 -oncotree_code=PAAD diff --git a/src/lib/djerba/plugins/cnv/test/plugin_test.py b/src/lib/djerba/plugins/cnv/test/plugin_test.py deleted file mode 100755 index 940647b4e..000000000 --- a/src/lib/djerba/plugins/cnv/test/plugin_test.py +++ /dev/null @@ -1,57 +0,0 @@ -#! /usr/bin/env python3 - -""" -Test of the WGTS CNV plugin -""" - -import os -import string -import tempfile -import unittest -from shutil import copy -from djerba.util.validator import path_validator -from djerba.plugins.plugin_tester import PluginTester -from djerba.plugins.cnv.plugin import main as cnv -from djerba.core.workspace import workspace -from djerba.util.environment import directory_finder - -class TestWgtsCnv(PluginTester): - - INI_NAME = 'cnv.ini' - JSON_NAME = 'cnv.json' - - def testWgtsCnv(self): - sup_dir = directory_finder().get_test_dir() - test_source_dir = os.path.realpath(os.path.dirname(__file__)) - data_dir = os.path.join(sup_dir, 'plugins', 'cnv') - sequenza_filename = 'PANX_1391_Lv_M_WG_100-NH-020_LCM3_results.test.zip' - sequenza_path = os.path.join(sup_dir, 'plugins', 'cnv', sequenza_filename) - expression_filename = 'data_expression_percentile_tcga.json' - expression_path = os.path.join(sup_dir, 'plugins', 'cnv', expression_filename) - with open(os.path.join(test_source_dir, self.INI_NAME)) as in_file: - template_str = in_file.read() - template = string.Template(template_str) - ini_str = template.substitute({'SEQUENZA_PATH': sequenza_path}) - tmp_dir = self.get_tmp_dir() - input_dir = os.path.join(tmp_dir, 'input') - os.mkdir(input_dir) - work_dir = os.path.join(tmp_dir, 'work') - os.mkdir(work_dir) - copy(expression_path, work_dir) - with open(os.path.join(input_dir, self.INI_NAME), 'w') as ini_file: - ini_file.write(ini_str) - copy(os.path.join(data_dir, self.JSON_NAME), input_dir) - params = { - self.INI: self.INI_NAME, - self.JSON: self.JSON_NAME, - self.MD5: 'abdd11282b2f3dea6d09daf50bf0b071' - } - self.run_basic_test(input_dir, params, work_dir=work_dir) - - def redact_json_data(self, data): - """replaces empty method from testing.tools""" - del data['results']['cnv plot'] - return data - -if __name__ == '__main__': - unittest.main() diff --git a/src/lib/djerba/plugins/failed_report/__init__.py b/src/lib/djerba/plugins/failed_report/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/lib/djerba/plugins/failed_report/failed_report_template.html b/src/lib/djerba/plugins/failed_report/failed_report_template.html deleted file mode 100644 index 26b288626..000000000 --- a/src/lib/djerba/plugins/failed_report/failed_report_template.html +++ /dev/null @@ -1,15 +0,0 @@ -<% - import djerba.core.constants as core_constants - from djerba.util.html import html_builder - from djerba.plugins.failed_report.plugin import main as failed_report - FAILED_TEXT = results.get(failed_report.FAILED_TEXT) -%> - - - ${html_builder().section_cells_begin("

    Results Summary

    ","main")} - -

    - -
    - - ${html_builder().section_cells_end()} diff --git a/src/lib/djerba/plugins/failed_report/plugin.py b/src/lib/djerba/plugins/failed_report/plugin.py deleted file mode 100644 index e3f550f4c..000000000 --- a/src/lib/djerba/plugins/failed_report/plugin.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -Plugin to generate the failed report results summary report section - -""" - -import logging -import csv -import os -from djerba.plugins.base import plugin_base, DjerbaPluginError -from djerba.helpers.input_params_helper.helper import main as input_params_helper -from djerba.util.render_mako import mako_renderer -import djerba.core.constants as core_constants -from djerba.core.workspace import workspace - -class main(plugin_base): - - PRIORITY = 600 - PLUGIN_VERSION = '1.0.0' - MAKO_TEMPLATE_NAME = 'failed_report_template.html' - FAILED_TEMPLATE_FILE = 'failed_template.txt' - FAILED_FILE = 'failed_file' - FAILED_TEXT = 'failed_text' - - def configure(self, config): - config = self.apply_defaults(config) - wrapper = self.get_config_wrapper(config) - work_dir = self.workspace.get_work_dir() - - # Write the failed text if there isn't one already specified. - if wrapper.my_param_is_null(self.FAILED_FILE): - failed_template_path = os.path.join(work_dir, self.FAILED_TEMPLATE_FILE) - self.write_failed_text(failed_template_path) - wrapper.set_my_param(self.FAILED_FILE, failed_template_path) - - return wrapper.get_config() - - def extract(self, config): - wrapper = self.get_config_wrapper(config) - failed_text = self.read_failed_text(config[self.identifier][self.FAILED_FILE]) - data = self.get_starting_plugin_data(wrapper, self.PLUGIN_VERSION) - - # Construct failed text with parameters. - - data[core_constants.RESULTS][self.FAILED_TEXT] = failed_text - self.workspace.write_string('results_summary.txt', failed_text) - return data - - def specify_params(self): - discovered = [ - self.FAILED_FILE, - ] - for key in discovered: - self.add_ini_discovered(key) - self.set_ini_default(core_constants.ATTRIBUTES, 'clinical') - self.set_priority_defaults(self.PRIORITY) - - def render(self, data): - renderer = mako_renderer(self.get_module_dir()) - return renderer.render_name(self.MAKO_TEMPLATE_NAME, data) - - def write_failed_text(self, failed_template_path): - - primary_cancer = "..." - assay = "..." - study = "..." - failed_text = "The patient has been diagnosed with " + primary_cancer + \ - " and has been referred for the OICR Genomics " + assay + \ - " assay through the " + study + " study." + \ - " A quality failure report for this sample is being issued due to" + \ - " the informatically inferred tumour purity of ...% which is below the reportable threshold of 30% for the assay" + \ - " / is being issued due to failed extraction" + \ - " / is being issued as the quantity of extracted DNA/RNA from tissue material was below the lower quantifiable range and therefore below the minimum input amount for this assay (minimums of 25ng for DNA and 50ng for RNA)..." - - with open(failed_template_path, "w") as failed_file: - failed_file.write(failed_text) - - - def read_failed_text(self, results_failed_path): - """ - read results summary from file - """ - with open(results_failed_path, 'r') as failed_file: - failed_text = csv.reader(failed_file, delimiter="\t") - text = '' - for row in failed_text: - text = text.join(row) - return text diff --git a/src/lib/djerba/plugins/failed_report/test/__init__.py b/src/lib/djerba/plugins/failed_report/test/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/lib/djerba/plugins/failed_report/test/failed_report.ini b/src/lib/djerba/plugins/failed_report/test/failed_report.ini deleted file mode 100644 index 03123a05e..000000000 --- a/src/lib/djerba/plugins/failed_report/test/failed_report.ini +++ /dev/null @@ -1,3 +0,0 @@ -[core] - -[failed_report] diff --git a/src/lib/djerba/plugins/failed_report/test/failed_report.json b/src/lib/djerba/plugins/failed_report/test/failed_report.json deleted file mode 100644 index 4d88a7a23..000000000 --- a/src/lib/djerba/plugins/failed_report/test/failed_report.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "plugin_name": "failed_report plugin", - "version": "1.0.0", - "priorities": { - "configure": 600, - "extract": 600, - "render": 600 - }, - "attributes": [ - "clinical" - ], - "merge_inputs": {}, - "results": { - "failed_text": "The patient has been diagnosed with ... and has been referred for the OICR Genomics ... assay through the ... study. A quality failure report for this sample is being issued due to the informatically inferred tumour purity of ...% which is below the reportable threshold of 30% for the assay / is being issued due to failed extraction / is being issued as the quantity of extracted DNA/RNA from tissue material was below the lower quantifiable range and therefore below the minimum input amount for this assay (minimums of 25ng for DNA and 50ng for RNA)..." - } -} diff --git a/src/lib/djerba/plugins/failed_report/test/plugin_test.py b/src/lib/djerba/plugins/failed_report/test/plugin_test.py deleted file mode 100755 index 4b29b4834..000000000 --- a/src/lib/djerba/plugins/failed_report/test/plugin_test.py +++ /dev/null @@ -1,31 +0,0 @@ -#! /usr/bin/env python3 - -"""Test of the failed report plugin""" - -import os -import unittest -import tempfile -from djerba.util.validator import path_validator -from djerba.plugins.plugin_tester import PluginTester -from djerba.util.environment import directory_finder - -class TestFailedReportPlugin(PluginTester): - def setUp(self): - self.path_validator = path_validator() - self.maxDiff = None - self.tmp = tempfile.TemporaryDirectory(prefix='djerba_') - self.tmp_dir = self.tmp.name - self.sup_dir = directory_finder().get_test_dir() - - def testFailedReport(self): - test_source_dir = os.path.realpath(os.path.dirname(__file__)) - json_location = "failed_report.json" - params = { - self.INI: 'failed_report.ini', - self.JSON: json_location, - self.MD5: '416c14efbaec900ef37badad88955d7e' - } - self.run_basic_test(test_source_dir, params) - -if __name__ == '__main__': - unittest.main() diff --git a/src/lib/djerba/plugins/genomic_landscape/ctdna.py b/src/lib/djerba/plugins/genomic_landscape/ctdna.py index aaa510f4b..ec2cb215f 100644 --- a/src/lib/djerba/plugins/genomic_landscape/ctdna.py +++ b/src/lib/djerba/plugins/genomic_landscape/ctdna.py @@ -10,7 +10,7 @@ class ctdna_processor(logger): def __init__(self, log_level, log_path): self.log_level = log_level self.log_path = log_path - self.logger = self.get_logger(log_level, log_path) + self.logger = self.get_logger(log_level, __name__, log_path) def run(self, candidate_sites_path): candidates = self.extract_ctDNA_candidates(candidate_sites_path) diff --git a/src/lib/djerba/plugins/genomic_landscape/hrd.py b/src/lib/djerba/plugins/genomic_landscape/hrd.py index cd06d3a94..f5eac6936 100644 --- a/src/lib/djerba/plugins/genomic_landscape/hrd.py +++ b/src/lib/djerba/plugins/genomic_landscape/hrd.py @@ -12,7 +12,7 @@ class hrd_processor(logger): def __init__(self, log_level, log_path): self.log_level = log_level self.log_path = log_path - self.logger = self.get_logger(log_level, log_path) + self.logger = self.get_logger(log_level, __name__, log_path) self.validator = path_validator(log_level, log_path) ONCOTREE_FILE = 'OncoTree.json' diff --git a/src/lib/djerba/plugins/genomic_landscape/msi.py b/src/lib/djerba/plugins/genomic_landscape/msi.py index 9f3c5a53c..96cbd963e 100644 --- a/src/lib/djerba/plugins/genomic_landscape/msi.py +++ b/src/lib/djerba/plugins/genomic_landscape/msi.py @@ -19,7 +19,7 @@ class msi_processor(logger): def __init__(self, log_level, log_path): self.log_level = log_level self.log_path = log_path - self.logger = self.get_logger(log_level, log_path) + self.logger = self.get_logger(log_level, __name__, log_path) self.validator = path_validator(log_level, log_path) def run(self, work_dir, r_script_dir, msi_file, biomarkers_path, tumour_id): diff --git a/src/lib/djerba/plugins/genomic_landscape/tmb.py b/src/lib/djerba/plugins/genomic_landscape/tmb.py index 94cb27bb5..dc5388d26 100644 --- a/src/lib/djerba/plugins/genomic_landscape/tmb.py +++ b/src/lib/djerba/plugins/genomic_landscape/tmb.py @@ -13,7 +13,7 @@ class tmb_processor(logger): def __init__(self, log_level, log_path): self.log_level = log_level self.log_path = log_path - self.logger = self.get_logger(log_level, log_path) + self.logger = self.get_logger(log_level, __name__, log_path) def run(self, work_dir, data_dir, r_script_dir, tcga_code, biomarkers_path, tumour_id, tmb_value=None): genomic_landscape_info = self.build_genomic_landscape_info(work_dir, data_dir, tcga_code) diff --git a/src/lib/djerba/plugins/pwgs/analysis/plugin.py b/src/lib/djerba/plugins/pwgs/analysis/plugin.py index 5015becbc..d1babc6e7 100644 --- a/src/lib/djerba/plugins/pwgs/analysis/plugin.py +++ b/src/lib/djerba/plugins/pwgs/analysis/plugin.py @@ -88,10 +88,6 @@ def extract(self, config): pc.DATASET_DETECTION_CUTOFF: math.ceil(mrdetect_results[pc.DATASET_DETECTION_CUTOFF]), pc.COHORT_N: hbc_results[pc.COHORT_N], 'pwgs_base64': pwgs_base64, - 'files': { - 'hbc_results': wrapper.get_my_string(pc.HBC_FILE), - 'vaf_results': wrapper.get_my_string(pc.VAF_FILE) - } } data[pc.RESULTS] = results self.workspace.write_json('hbc_results.json', hbc_results) diff --git a/src/lib/djerba/plugins/pwgs/analysis/test/plugin_test.py b/src/lib/djerba/plugins/pwgs/analysis/test/plugin_test.py index dac8162ae..94b19e8e5 100755 --- a/src/lib/djerba/plugins/pwgs/analysis/test/plugin_test.py +++ b/src/lib/djerba/plugins/pwgs/analysis/test/plugin_test.py @@ -77,8 +77,7 @@ def run_test_with_scenario(self, json_filename, md5_checksum): def redact_json_data(self, data): """replaces empty method from testing.tools""" - for key in ['pwgs_base64','files']: - del data['results'][key] + del data['results']['pwgs_base64'] return data if __name__ == '__main__': diff --git a/src/lib/djerba/plugins/summary/plugin.py b/src/lib/djerba/plugins/summary/plugin.py index ba97b4b57..13259286f 100644 --- a/src/lib/djerba/plugins/summary/plugin.py +++ b/src/lib/djerba/plugins/summary/plugin.py @@ -16,27 +16,34 @@ class main(plugin_base): PRIORITY = 400 PLUGIN_VERSION = '0.1' MAKO_TEMPLATE_NAME = 'summary_report_template.html' - SUMMARY_TEMPLATE_FILE = 'summary_template.txt' + SUMMARY_TEMPLATE_FILE = 'templates/summary_template.txt' + FAILED_TEMPLATE_FILE = 'templates/failed_template.txt' SUMMARY_FILE = 'summary_file' SUMMARY_TEXT = 'summary_text' + FAILED = 'failed' def configure(self, config): config = self.apply_defaults(config) wrapper = self.get_config_wrapper(config) + failed = wrapper.get_my_boolean(self.FAILED) if wrapper.my_param_is_null(self.SUMMARY_FILE): - summary_template_path = \ - os.path.join(os.path.dirname(__file__), self.SUMMARY_TEMPLATE_FILE) - wrapper.set_my_param(self.SUMMARY_FILE, summary_template_path) + if not failed: + template_path = os.path.join(os.path.dirname(__file__), self.SUMMARY_TEMPLATE_FILE) + elif failed: + template_path = os.path.join(os.path.dirname(__file__), self.FAILED_TEMPLATE_FILE) + wrapper.set_my_param(self.SUMMARY_FILE, template_path) return wrapper.get_config() def extract(self, config): wrapper = self.get_config_wrapper(config) summary_path = wrapper.get_my_string(self.SUMMARY_FILE) + failed = wrapper.get_my_boolean(self.FAILED) with open(summary_path, encoding=core_constants.TEXT_ENCODING) as in_file: summary_text = in_file.read() self.logger.debug('Read summary from {0}: "{1}"'.format(summary_path, summary_text)) data = self.get_starting_plugin_data(wrapper, self.PLUGIN_VERSION) data[core_constants.RESULTS][self.SUMMARY_TEXT] = summary_text + data[core_constants.RESULTS][self.FAILED] = failed filename = 'results_summary.txt' self.workspace.write_string(filename, summary_text) self.logger.debug('Wrote summary to {0}'.format(self.workspace.abs_path(filename))) @@ -49,6 +56,7 @@ def specify_params(self): for key in discovered: self.add_ini_discovered(key) self.set_ini_default(core_constants.ATTRIBUTES, 'clinical') + self.set_ini_default(self.FAILED, False) self.set_priority_defaults(self.PRIORITY) def render(self, data): diff --git a/src/lib/djerba/plugins/summary/summary_report_template.html b/src/lib/djerba/plugins/summary/summary_report_template.html index 340b56f93..04cfb8baa 100644 --- a/src/lib/djerba/plugins/summary/summary_report_template.html +++ b/src/lib/djerba/plugins/summary/summary_report_template.html @@ -3,11 +3,17 @@ from djerba.util.html import html_builder from djerba.plugins.summary.plugin import main as summary SUMMARY_TEXT = results.get(summary.SUMMARY_TEXT) + FAILED = results.get(summary.FAILED) %> ${html_builder().section_cells_begin("

    Results Summary

    ","main")} - - ${html_builder().markdown_to_html(SUMMARY_TEXT)} - + + % if not FAILED: + ${html_builder().markdown_to_html(SUMMARY_TEXT)} + % elif FAILED: +

    + % endif + ${html_builder().section_cells_end()} + diff --git a/src/lib/djerba/plugins/summary/templates/failed_template.txt b/src/lib/djerba/plugins/summary/templates/failed_template.txt new file mode 100644 index 000000000..184c45384 --- /dev/null +++ b/src/lib/djerba/plugins/summary/templates/failed_template.txt @@ -0,0 +1 @@ +The patient has been diagnosed with ... and has been referred for the OICR Genomics ... assay through the ... study. A quality failure report for this sample is being issued due to the informatically inferred tumour purity of ...% which is below the reportable threshold of 30% for the assay \ is being issued due to failed extraction \ is being issued as the quantity of extracted DNA/RNA from tissue material was below the lower quantifiable range and therefore below the minimum input amount for this assay (minimums of 25ng for DNA and 50ng for RNA)... diff --git a/src/lib/djerba/plugins/summary/summary_template.txt b/src/lib/djerba/plugins/summary/templates/summary_template.txt similarity index 100% rename from src/lib/djerba/plugins/summary/summary_template.txt rename to src/lib/djerba/plugins/summary/templates/summary_template.txt diff --git a/src/lib/djerba/plugins/summary/test/failed.ini b/src/lib/djerba/plugins/summary/test/failed.ini new file mode 100644 index 000000000..ff10a41a7 --- /dev/null +++ b/src/lib/djerba/plugins/summary/test/failed.ini @@ -0,0 +1,4 @@ +[core] + +[summary] +failed = True diff --git a/src/lib/djerba/plugins/summary/test/plugin_test.py b/src/lib/djerba/plugins/summary/test/plugin_test.py index ca428873d..d8fa77437 100755 --- a/src/lib/djerba/plugins/summary/test/plugin_test.py +++ b/src/lib/djerba/plugins/summary/test/plugin_test.py @@ -25,10 +25,21 @@ def testSummary(self): params = { self.INI: 'summary.ini', self.JSON: json_location, - self.MD5: '155e22cc02a45e04dc9058112354367c' + self.MD5: '1599ec66c80c2607e71a1dea9d53aacf' } self.run_basic_test(test_source_dir, params) + def testFailedSummary(self): + test_source_dir = os.path.realpath(os.path.dirname(__file__)) + json_location = os.path.join(self.data_dir_root, "plugins", "summary", "report_json", "failed.json") + params = { + self.INI: 'failed.ini', + self.JSON: json_location, + self.MD5: 'abf18dc395150bf990a0b24b1cf9b422' + } + self.run_basic_test(test_source_dir, params) + + def testSummaryWithCustomText(self): test_source_dir = os.path.realpath(os.path.dirname(__file__)) summary_path = os.path.join(test_source_dir, 'custom_summary.txt') @@ -43,7 +54,7 @@ def testSummaryWithCustomText(self): params = { self.INI: ini_path, self.JSON: json_location, - self.MD5: 'cebbb53b9b074131e309dca71704a896' + self.MD5: 'b58589404184cd4b8d1a88f276f096b7' } self.run_basic_test(test_source_dir, params) diff --git a/src/lib/djerba/plugins/tar/sample/plugin.py b/src/lib/djerba/plugins/tar/sample/plugin.py index 2f5a3b7b2..3b7e5318e 100644 --- a/src/lib/djerba/plugins/tar/sample/plugin.py +++ b/src/lib/djerba/plugins/tar/sample/plugin.py @@ -18,22 +18,21 @@ raise RuntimeError('QC-ETL import failure! Try checking python versions') from err class main(plugin_base): - PLUGIN_VERSION = '1.0.0' QCETL_CACHE = "/scratch2/groups/gsi/production/qcetl_v1" - + def configure(self, config): config = self.apply_defaults(config) wrapper = self.get_config_wrapper(config) - + # Get input_data.json if it exists; else return None input_data = self.workspace.read_maybe_input_params() # Get various IDs keys = [constants.ONCOTREE, constants.KNOWN_VARIANTS, constants.SAMPLE_TYPE] - key_mapping = {k:k for k in keys} # mapping from INI keys to input_params.json keys + key_mapping = {k: k for k in keys} # mapping from INI keys to input_params.json keys key_mapping[constants.GROUP_ID] = constants.TUMOUR_ID - for key,val in key_mapping.items(): + for key, val in key_mapping.items(): if wrapper.my_param_is_null(key): if input_data != None: wrapper.set_my_param(key, input_data[val]) @@ -41,7 +40,6 @@ def configure(self, config): msg = "Cannot find {0} in manual config or input_params.json".format(key) self.logger.error(msg) raise RuntimeError(msg) - # Get files from path_info.json wrapper = self.update_wrapper_if_null( @@ -69,12 +67,14 @@ def configure(self, config): # Get values for collapsed coverage for Pl and BC and put in config for QC reporting if wrapper.my_param_is_null(constants.COVERAGE_PL): - wrapper.set_my_param(constants.COVERAGE_PL, self.process_consensus_cruncher(config[self.identifier][constants.CONSENSUS_FILE])) + wrapper.set_my_param(constants.COVERAGE_PL, + self.process_consensus_cruncher(config[self.identifier][constants.CONSENSUS_FILE])) if wrapper.my_param_is_null(constants.COVERAGE_BC): - wrapper.set_my_param(constants.COVERAGE_BC, self.process_consensus_cruncher(config[self.identifier][constants.CONSENSUS_NORMAL_FILE])) - + wrapper.set_my_param(constants.COVERAGE_BC, self.process_consensus_cruncher( + config[self.identifier][constants.CONSENSUS_NORMAL_FILE])) + return wrapper.get_config() - + def extract(self, config): wrapper = self.get_config_wrapper(config) work_dir = self.workspace.get_work_dir() @@ -90,18 +90,18 @@ def extract(self, config): # If purity is <10%, only report as <10% (not exact number) purity = float(purity) - rounded_purity = round(purity*100, 1) + rounded_purity = round(purity * 100, 1) if rounded_purity < 10: rounded_purity = "<10" - results = { - constants.ONCOTREE: config[self.identifier][constants.ONCOTREE], - constants.KNOWN_VARIANTS : config[self.identifier][constants.KNOWN_VARIANTS], - constants.SAMPLE_TYPE : config[self.identifier][constants.SAMPLE_TYPE], - constants.CANCER_CONTENT : rounded_purity, - constants.RAW_COVERAGE : int(config[self.identifier][constants.RAW_COVERAGE]), - constants.UNIQUE_COVERAGE : int(config[self.identifier][constants.COVERAGE_PL]), - } + results = { + constants.ONCOTREE: config[self.identifier][constants.ONCOTREE], + constants.KNOWN_VARIANTS: config[self.identifier][constants.KNOWN_VARIANTS], + constants.SAMPLE_TYPE: config[self.identifier][constants.SAMPLE_TYPE], + constants.CANCER_CONTENT: rounded_purity, + constants.RAW_COVERAGE: int(config[self.identifier][constants.RAW_COVERAGE]), + constants.UNIQUE_COVERAGE: int(config[self.identifier][constants.COVERAGE_PL]), + } data['results'] = results return data @@ -109,14 +109,42 @@ def fetch_coverage_etl_data(self, group_id): etl_cache = QCETLCache(self.QCETL_CACHE) cached_coverages = etl_cache.hsmetrics.metrics columns_of_interest = gsiqcetl.column.HsMetricsColumn - data = cached_coverages.loc[ (cached_coverages[columns_of_interest.GroupID] == group_id), [columns_of_interest.GroupID, columns_of_interest.MeanBaitCoverage] ] + + # Filter data for the group_id + data = cached_coverages.loc[ + (cached_coverages[columns_of_interest.GroupID] == group_id), + [ + columns_of_interest.GroupID, + columns_of_interest.MeanBaitCoverage, + columns_of_interest.TissueType, + ] + ] + qc_dict = {} if len(data) > 0: - qc_dict[constants.RAW_COVERAGE] = int(round(data.iloc[0][columns_of_interest.MeanBaitCoverage].item(),0)) + # Exclude the reference + filtered_data = data[data[columns_of_interest.TissueType] != 'R'] + + if len(filtered_data) > 0: + # Check if coverage values are unique + coverage = filtered_data[columns_of_interest.MeanBaitCoverage].unique() + if len(coverage) != 1: + msg = f"Multiple coverage values found for group_id {group_id}: {coverage}." + self.logger.error(msg) + raise ValueError(msg) + else: + selected_value = coverage[0] + qc_dict[constants.RAW_COVERAGE] = int(round(selected_value, 0)) + else: + msg = f"No valid QC metrics found for group_id {group_id} after filtering out the normal." + self.logger.error(msg) + raise MissingQCETLError(msg) else: - msg = "QC metrics associated with group_id {0} not found in QC-ETL and no value found in .ini ".format(group_id) + msg = f"QC metrics associated with group_id {group_id} not found in QC-ETL and no value found in .ini." + self.logger.error(msg) raise MissingQCETLError(msg) - return(qc_dict) + + return qc_dict def render(self, data): renderer = mako_renderer(self.get_module_dir()) @@ -125,22 +153,22 @@ def render(self, data): def process_ichor_json(self, ichor_metrics): with open(ichor_metrics, 'r') as ichor_results: ichor_json = json.load(ichor_results) - return(ichor_json) + return ichor_json - def process_consensus_cruncher(self, consensus_cruncher_file): + def process_consensus_cruncher(self, consensus_cruncher_file ): header_line = False with open(consensus_cruncher_file, 'r') as cc_file: reader_file = csv.reader(cc_file, delimiter="\t") for row in reader_file: if row: - if row[0] == "BAIT_SET" : + if row[0] == "BAIT_SET": header_line = True elif header_line: - unique_coverage = float(row[9]) + unique_coverage = float(row[9]) header_line = False else: next - return(int(round(unique_coverage, 0))) + return int(round(unique_coverage, 0)) def specify_params(self): discovered = [ diff --git a/src/lib/djerba/plugins/wgts/cnv_purple/cnv_template.html b/src/lib/djerba/plugins/wgts/cnv_purple/cnv_template.html index bb778a4ed..52205cc9c 100644 --- a/src/lib/djerba/plugins/wgts/cnv_purple/cnv_template.html +++ b/src/lib/djerba/plugins/wgts/cnv_purple/cnv_template.html @@ -6,7 +6,7 @@ <% import djerba.plugins.wgts.cnv_purple.constants as constants from djerba.util.image_to_base64 import converter -from djerba.plugins.cnv.html import make_table_header, make_table_rows +from djerba.plugins.wgts.cnv_purple.html import make_table_header, make_table_rows from djerba.util.html import html_builder %> diff --git a/src/lib/djerba/plugins/cnv/html.py b/src/lib/djerba/plugins/wgts/cnv_purple/html.py similarity index 100% rename from src/lib/djerba/plugins/cnv/html.py rename to src/lib/djerba/plugins/wgts/cnv_purple/html.py diff --git a/src/lib/djerba/plugins/wgts/cnv_purple/tests/plugin_test.py b/src/lib/djerba/plugins/wgts/cnv_purple/tests/plugin_test.py index 279a69663..4d7f207ad 100755 --- a/src/lib/djerba/plugins/wgts/cnv_purple/tests/plugin_test.py +++ b/src/lib/djerba/plugins/wgts/cnv_purple/tests/plugin_test.py @@ -41,7 +41,7 @@ def testWGTScnv(self): params = { self.INI: self.WGTS_INI_NAME, self.JSON: json_location, - self.MD5: 'b90f726e5f58eeddc4a495e9c55e5ce3' + self.MD5: '5c15283f5b0ee48201a980ac5ef721dc' } self.run_basic_test(input_dir, params) diff --git a/src/lib/djerba/plugins/wgts/common/cnv/tools.py b/src/lib/djerba/plugins/wgts/common/cnv/tools.py index 17494ab2f..fa6e27303 100644 --- a/src/lib/djerba/plugins/wgts/common/cnv/tools.py +++ b/src/lib/djerba/plugins/wgts/common/cnv/tools.py @@ -31,7 +31,7 @@ class cnv_processor(logger): ONCOLIST = "20200818-oncoKBcancerGeneList.tsv" PLOT_FILENAME = 'seg_CNV_plot.svg' # this name is hard-coded in the R plot script MINIMUM_MAGNITUDE_SEG_MEAN = 0.2 - GENOME_SIZE = 3*10**9 # TODO use more accurate value + GENOME_SIZE = 3095978931 # comes from https://www.ncbi.nlm.nih.gov/grc/human/data?asm=GRCh38.p12. Non-N bases. SEG_FILENAME = 'seg.txt' def __init__(self, work_dir, config_wrapper, log_level=logging.WARNING, log_path=None): diff --git a/src/lib/djerba/util/benchmark.py b/src/lib/djerba/util/benchmark_tools.py similarity index 52% rename from src/lib/djerba/util/benchmark.py rename to src/lib/djerba/util/benchmark_tools.py index 4aee7845a..506f9b8bd 100644 --- a/src/lib/djerba/util/benchmark.py +++ b/src/lib/djerba/util/benchmark_tools.py @@ -1,6 +1,5 @@ """ Process the GSICAPBENCH samples for benchmarking/validation: -- Detect new GSICAPBENCH runs (TODO) - Generate config and make working directories - Run main class to generate reports - Compare with previous runs @@ -9,6 +8,7 @@ import json import logging import os +import re import sys import unittest import djerba.core.constants as core_constants @@ -34,6 +34,7 @@ class benchmarker(logger): CONFIG_FILE_NAME = 'config.ini' # TODO set random seed in MSI workflow for consistent outputs MSI_DIR_NAME = 'msi' + DEFAULT_PLOIDY = 2.0 # arbitrary ploidy default DEFAULT_PURITY = 0.74 # arbitrary purity default DEFAULT_SAMPLES = [ 'GSICAPBENCH_0001', @@ -49,30 +50,99 @@ class benchmarker(logger): 'GSICAPBENCH_1391' ] REPORT_DIR_NAME = 'report' - TEMPLATE = 'benchmark_config.ini' - - # script modes - GENERATE = 'generate' - COMPARE = 'compare' + TEMPLATE_PWGS = 'benchmark_pwgs.ini' + TEMPLATE_TAR = 'benchmark_tar.ini' + TEMPLATE_WGTS = 'benchmark_wgts.ini' + TEMPLATE_WGS = 'benchmark_wgs.ini' + + # Assay identifiers + ASSAY = 'assay' + WGTS = 'WGTS' + WGS = 'WGS' + TAR = 'TAR' + PWGS = 'PWGS' # INI template field names ARRIBA_FILE = 'arriba_path' DONOR = 'donor' + BAMQC_FILE = 'bamqc_file' CTDNA_FILE = 'ctdna_file' HRD_FILE = 'hrd_file' MAF_FILE = 'maf_path' + MAF_TAR_T = 'maf_path_tar_tumour' + MAF_TAR_N = 'maf_path_tar_normal' MAVIS_FILE = 'mavis_path' - MRDETECT_VCF = 'mrdetect_vcf' + MRDETECT_HBC = 'mrdetect_hbc' + MRDETECT_SNP = 'mrdetect_snp' + MRDETECT_TXT = 'mrdetect_txt' + MRDETECT_VAF = 'mrdetect_vaf' MSI_FILE = 'msi_file' PLOIDY = 'ploidy' PROJECT = 'project' PURITY = 'purity' PURPLE_FILE = 'purple_path' RSEM_FILE = 'rsem_genes_results' + SEG_FILE = 'seg_file' + CC_T = 'consensus_cruncher_tumour' + CC_N = 'consensus_cruncher_normal' + ICHORCNA_FILE = 'ichorcna_file' TUMOUR_ID = 'tumour_id' NORMAL_ID = 'normal_id' APPLY_CACHE = 'apply_cache' UPDATE_CACHE = 'update_cache' + GLOB_TEMPLATES = { + MAF_FILE: '{0}/**/{1}_*mutect2.filtered.maf.gz', + MAVIS_FILE: '{0}/**/{1}*.mavis_summary.tab', + RSEM_FILE: '{0}/**/{1}_*.genes.results', + MSI_FILE: '{0}/**/{1}_*.msi.booted', + CTDNA_FILE: '{0}/**/{1}_*.SNP.count.txt', + ARRIBA_FILE: '{0}/**/{1}*.fusions.tsv', + PURPLE_FILE: '{0}/**/{1}*.purple.zip', + HRD_FILE: '{0}/**/{1}*.signatures.json', + MAF_TAR_T: '{0}/**/{1}_*_T_*.merged.maf.gz', + MAF_TAR_N: '{0}/**/{1}_*_R_*.merged.maf.gz', + SEG_FILE: '{0}/**/{1}*.seg.txt', + ICHORCNA_FILE: '{0}/**/{1}*_metrics.json', + BAMQC_FILE: '{0}/**/{1}*.bamQC_results.json', + MRDETECT_HBC: '{0}/**/{1}*.HBCs.csv', + MRDETECT_SNP: '{0}/**/{1}*.SNP.count.txt', + MRDETECT_TXT: '{0}/**/{1}*.mrdetect.txt', + MRDETECT_VAF: '{0}/**/{1}*.mrdetect.vaf.txt', + } + + # expected inputs by assay + EXPECTED_PWGS = [ + BAMQC_FILE, + MRDETECT_HBC, + MRDETECT_SNP, + MRDETECT_TXT, + MRDETECT_VAF + ] + EXPECTED_TAR = [ + ICHORCNA_FILE, + CC_T, + CC_N, + SEG_FILE, + MAF_TAR_T, + MAF_TAR_N + ] + EXPECTED_WGS = [ + MAF_FILE, + MSI_FILE, + CTDNA_FILE, + PURPLE_FILE, + HRD_FILE + ] + EXPECTED_WGTS = [ + MAF_FILE, + MAVIS_FILE, + RSEM_FILE, + MSI_FILE, + CTDNA_FILE, + ARRIBA_FILE, + PURPLE_FILE, + HRD_FILE + ] def __init__(self, args): self.log_level = self.get_args_log_level(args) @@ -90,8 +160,8 @@ def __init__(self, args): self.logger.error(msg) raise RuntimeError(msg) self.samples = args.sample if args.sample else self.DEFAULT_SAMPLES - self.validator.validate_input_file(args.ref_path) - self.ref_path = args.ref_path + self.validator.validate_input_dir(args.ref_dir) + self.ref_dir = args.ref_dir self.input_dir = os.path.abspath(self.args.input_dir) self.validator.validate_input_dir(self.input_dir) self.logger.info("GSICAPBENCH input directory is '{0}'".format(self.input_dir)) @@ -115,6 +185,12 @@ def glob_single(self, pattern): """Glob recursively for the given pattern; return a single result, or None""" self.logger.debug("Recursive glob for files matching {0}".format(pattern)) results = sorted(glob(pattern, recursive=True)) + # omit files pertaining to un-merged BAMs, eg. foo-bar_TACGCTAC-CGTGTGAT.bamQC_results.json + initial_len = len(results) + results = list(filter(lambda x: not re.search('[ACGT]{8}-[ACGT]{8}', x), results)) + omitted = initial_len - len(results) + if omitted > 0: + self.logger.debug('Omitting {0} un-merged results for {1}'.format(omitted, pattern)) if len(results)==0: result = None self.logger.debug("No glob results for pattern '{0}'".format(pattern)) @@ -128,52 +204,56 @@ def glob_single(self, pattern): self.logger.debug(msg) return result + def find_cc_metrics(self, maf_path): + # find consensus cruncher metrics -- in same directory as MAF file (if any) + if maf_path == None: + metric_path = None + else: + cc_dir = os.path.dirname(maf_path) + metric_path = os.path.join(cc_dir, 'allUnique-hsMetrics.HS.txt') + try: + self.validator.validate_input_file(metric_path) + except OSError as err: + msg = "Cannot find expected metrics path {0} ".format(metric_path)+\ + "from MAF path {0}".format(maf_path) + self.logger.error(msg) + raise OSError(msg) from err + return metric_path + def find_inputs(self, results_dir): inputs = {} - templates = { - self.MAF_FILE: '{0}/**/{1}_*mutect2.filtered.maf.gz', - self.MAVIS_FILE: '{0}/**/{1}*.mavis_summary.tab', - self.RSEM_FILE: '{0}/**/{1}_*.genes.results', - self.MSI_FILE: '{0}/**/{1}_*.msi.booted', - self.CTDNA_FILE: '{0}/**/{1}_*.SNP.count.txt', - self.ARRIBA_FILE: '{0}/**/{1}*.fusions.tsv', - self.PURPLE_FILE: '{0}/**/{1}*.purple.zip', - self.HRD_FILE: '{0}/**/{1}*.signatures.json' - } for sample in self.samples: sample_inputs = {} sample_inputs[self.DONOR] = sample sample_inputs[self.PROJECT] = 'placeholder' - sample_inputs[self.PLOIDY] = 2.0 + sample_inputs[self.PLOIDY] = self.DEFAULT_PLOIDY sample_inputs[self.APPLY_CACHE] = self.args.apply_cache sample_inputs[self.UPDATE_CACHE] = self.args.update_cache sample_inputs[self.TUMOUR_ID] = sample+'_T' sample_inputs[self.NORMAL_ID] = sample+'_N' sample_inputs[self.PURITY] = self.DEFAULT_PURITY - for key in templates.keys(): - pattern = templates[key].format(results_dir, sample) + for key in self.GLOB_TEMPLATES.keys(): + pattern = self.GLOB_TEMPLATES[key].format(results_dir, sample) sample_inputs[key] = self.glob_single(pattern) - # Workaround for placeholder arriba output - if sample_inputs[self.ARRIBA_FILE] == None: - arriba_path = os.path.join(self.private_dir, 'arriba', 'arriba.fusions.tsv') - if os.path.isfile(arriba_path): - sample_inputs[self.ARRIBA_FILE] = arriba_path - else: - msg = "No arriba input found from input directory; "+\ - "fallback arriba path '{0}' is not a file".format(arriba_path) - self.logger.error(msg) - raise RuntimeError(msg) - if None in sample_inputs.values(): - template = "Skipping {0} as one or more values are missing: {1}" - msg = template.format(sample, sample_inputs) - self.logger.warning(msg) - continue - self.logger.debug("Sample inputs for {0}: {1}".format(sample, sample_inputs)) - if any([x==None for x in sample_inputs.values()]): - # skip samples with missing inputs, eg. for testing - self.logger.info("Omitting {0}, one or more inputs missing".format(sample)) - else: - inputs[sample] = sample_inputs + sample_inputs[self.CC_T] = self.find_cc_metrics(sample_inputs[self.MAF_TAR_T]) + sample_inputs[self.CC_N] = self.find_cc_metrics(sample_inputs[self.MAF_TAR_N]) + # Check which assay(s) have inputs available; run all which apply + assays = [] + if self.ok_for_wgts(sample_inputs): + assays.append(self.WGTS) + elif self.ok_for_wgs(sample_inputs): + assays.append(self.WGS) # WGS/WGTS are mutually exclusive + if self.ok_for_tar(sample_inputs): + assays.append(self.TAR) + if self.ok_for_pwgs(sample_inputs): + assays.append(self.PWGS) + for assay in assays: + identifier = sample+"_"+assay + inputs_for_report = deepcopy(sample_inputs) + inputs_for_report[self.ASSAY] = assay + inputs[identifier] = inputs_for_report + self.logger.debug("Found {0} inputs: {1}".format(identifier, sample_inputs)) + self.log_inputs(assays, sample, sample_inputs) if len(inputs)==0: # require inputs for at least one sample msg = "No benchmark inputs found in {0} ".format(results_dir)+\ @@ -182,12 +262,78 @@ def find_inputs(self, results_dir): raise RuntimeError(msg) return inputs - def run_comparison(self, reports_path, ref_path): + def get_template_path(self, sample_inputs): + assay = sample_inputs[self.ASSAY] + if assay == self.WGTS: + filename = self.TEMPLATE_WGTS + elif assay == self.WGS: + filename = self.TEMPLATE_WGS + elif assay == self.PWGS: + filename = self.TEMPLATE_PWGS + elif assay == self.TAR: + filename = self.TEMPLATE_TAR + else: + msg = "No template INI supported for assay '{0}'".format(assay) + self.logger.error(msg) + raise RuntimeError(msg) + return os.path.join(self.data_dir, filename) + + def log_inputs(self, assays, sample, sample_inputs): + # summarize the available sample inputs in log output: + # - list the viable assays as INFO + # - warn if no assays are viable as WARNING + # - list the missing inputs for non-viable assays as DEBUG + self.logger.debug("Inputs for sample {0}: {1}".format(sample, sample_inputs)) + if len(assays)==0: + template = "Skipping {0} as inputs do not match any supported assay" + self.logger.warning(template.format(sample)) + else: + template = "Found {0} assays for sample {1}: {2}" + self.logger.info(template.format(len(assays), sample, assays)) + expected = { + self.PWGS: self.EXPECTED_PWGS, + self.TAR: self.EXPECTED_TAR, + self.WGS: self.EXPECTED_WGS, + self.WGTS: self.EXPECTED_WGTS + } + for assay, inputs in expected.items(): + if assay == self.WGS and self.WGTS in assays: + # WGTS takes precedence over WGS; WGS inputs are a subset of WGTS + continue + elif assay not in assays: + not_found = sorted(list(filter(lambda x: sample_inputs[x]==None, inputs))) + template = "The following inputs are not available "+\ + "for sample {0}, assay {1}: {2}" + self.logger.debug(template.format(sample, assay, not_found)) + + def ok_for_pwgs(self, sample_inputs): + return self.inputs_ok(sample_inputs, self.EXPECTED_PWGS) + + def ok_for_tar(self, sample_inputs): + return self.inputs_ok(sample_inputs, self.EXPECTED_TAR) + + def ok_for_wgs(self, sample_inputs): + return self.inputs_ok(sample_inputs, self.EXPECTED_WGS) + + def ok_for_wgts(self, sample_inputs): + return self.inputs_ok(sample_inputs, self.EXPECTED_WGTS) + + def inputs_ok(self, sample_inputs, expected_input_names): + # arguments: dictionary of sample inputs, list of expected input names + # check if dictionary has non-null values for all names in list + ok = True + for name in expected_input_names: + if sample_inputs[name] == None: + ok = False + break + return ok + + def run_comparison(self, reports_path, ref_dir): config = ConfigParser() config.add_section('benchmark') config.set('benchmark', 'input_name', self.input_name) config.set('benchmark', 'input_file', reports_path) - config.set('benchmark', 'ref_file', ref_path) + config.set('benchmark', 'ref_dir', ref_dir) self.logger.info("Loading plugin and running report comparison") plugin = self.plugin_loader.load('benchmark', self.workspace) full_config = plugin.configure(config) @@ -197,22 +343,22 @@ def run_comparison(self, reports_path, ref_path): html = plugin.render(data) return [data, html] - def run_reports(self, input_samples, work_dir): - self.logger.info("Reporting for {0} samples: {1}".format(len(input_samples), input_samples)) + def run_reports(self, inputs, work_dir): + self.logger.info("Reporting for {0} inputs: {1}".format(len(inputs), inputs)) report_paths = {} - for sample in input_samples: - self.logger.info("Generating Djerba draft report for {0}".format(sample)) - config_path = os.path.join(work_dir, sample, self.CONFIG_FILE_NAME) - report_dir = os.path.join(work_dir, sample, self.REPORT_DIR_NAME) + for name in inputs: + self.logger.info("Generating Djerba draft report for {0}".format(name)) + config_path = os.path.join(work_dir, name, self.CONFIG_FILE_NAME) + report_dir = os.path.join(work_dir, name, self.REPORT_DIR_NAME) self.validator.validate_output_dir(report_dir) # run the Djerba "main" class to generate a JSON report file djerba_main = main(report_dir, self.log_level, self.log_path) config = djerba_main.configure(config_path) - json_path = os.path.join(report_dir, sample+'_report.json') + json_path = os.path.join(report_dir, name+'_report.json') self.logger.debug("Extracting data to JSON path: "+json_path) data = djerba_main.extract(config, json_path, archive=False) - self.logger.info("Finished Djerba draft report for {0}".format(sample)) - report_paths[sample] = json_path + self.logger.info("Finished Djerba draft report for {0}".format(name)) + report_paths[name] = json_path json_path = os.path.join(work_dir, 'report_paths.json') with open(json_path, 'w', encoding=core_constants.TEXT_ENCODING) as json_file: json_file.write(json.dumps(report_paths)) @@ -222,38 +368,40 @@ def run_setup(self, results_dir, work_dir): """For each sample, set up working directory and generate config.ini""" self.validator.validate_input_dir(results_dir) inputs = self.find_inputs(results_dir) - input_samples = sorted(inputs.keys()) + input_names = sorted(inputs.keys()) self.validator.validate_output_dir(work_dir) - template_path = os.path.join(self.data_dir, self.TEMPLATE) - for sample in input_samples: - self.logger.debug("Setting up working directory for sample {0}".format(sample)) - sample_dir = os.path.join(work_dir, sample) - if os.path.isdir(sample_dir): - self.logger.warning("{0} exists, will overwrite".format(sample_dir)) + for name in input_names: + # names incorporate sample and assay, eg. GSICAPBENCH_0001_WGS + self.logger.debug("Setting up working directory for name {0}".format(name)) + work_subdir = os.path.join(work_dir, name) + if os.path.isdir(work_subdir): + self.logger.warning("{0} exists, will overwrite".format(work_subdir)) else: - os.mkdir(sample_dir) - report_dir = os.path.join(sample_dir, self.REPORT_DIR_NAME) + os.mkdir(work_subdir) + report_dir = os.path.join(work_subdir, self.REPORT_DIR_NAME) if not os.path.isdir(report_dir): os.mkdir(report_dir) + # Complete the appropriate INI template for report type: WGTS, TAR, PWGS + template_path = self.get_template_path(inputs.get(name)) self.logger.debug("Reading INI template: {0}".format(template_path)) with open(template_path) as template_file: template_ini = Template(template_file.read()) - self.logger.debug("Substituting with: {0}".format(inputs.get(sample))) - config = template_ini.substitute(inputs.get(sample)) - out_path = os.path.join(sample_dir, self.CONFIG_FILE_NAME) + self.logger.debug("Substituting with: {0}".format(inputs.get(name))) + config = template_ini.substitute(inputs.get(name)) + out_path = os.path.join(work_subdir, self.CONFIG_FILE_NAME) with open(out_path, 'w') as out_file: out_file.write(config) - self.logger.info("Created working directory {0}".format(sample_dir)) + self.logger.info("Created working directory {0}".format(work_subdir)) self.logger.info("GSICAPBENCH setup complete.") - return input_samples + return input_names def run(self): # generate Djerba reports # load and run plugin to compare reports and generate summary # copy JSON/text files and write HTML summary to output directory - input_samples = self.run_setup(self.input_dir, self.work_dir) - reports_path = self.run_reports(input_samples, self.work_dir) - data, html = self.run_comparison(reports_path, self.ref_path) + input_names = self.run_setup(self.input_dir, self.work_dir) + reports_path = self.run_reports(input_names, self.work_dir) + data, html = self.run_comparison(reports_path, self.ref_dir) self.logger.info("Writing data and HTML output") self.write_outputs(data, html) @@ -263,13 +411,13 @@ def write_outputs(self, data, html): with open(html_path, 'w', encoding=core_constants.TEXT_ENCODING) as html_file: html_file.write(html) # copy JSON files, and write the diff text (if any) - for result in data['results']['donor_results']: + for result in data['results']['report_results']: for json_path in [result['input_file'], result['ref_file']]: if os.path.exists(json_path): copy(json_path, self.output_dir) # TODO put diff link filename in JSON # TODO only write diff if non-empty - diff_path = os.path.join(self.output_dir, result['donor']+'_diff.txt') + diff_path = os.path.join(self.output_dir, result['report']+'_diff.txt') with open(diff_path, 'w', encoding=core_constants.TEXT_ENCODING) as diff_file: diff_file.write(result['diff']) self.logger.info('Finished writing summary to '+self.output_dir) @@ -283,24 +431,34 @@ class report_equivalence_tester(logger): CNV_NAME = 'wgts.cnv_purple' FUSION_NAME = 'fusion' - SNV_INDEL_NAME = 'wgts.snv_indel' + WGTS_SNV_INDEL_NAME = 'wgts.snv_indel' + TAR_SNV_INDEL_NAME = 'tar.snv_indel' SUPPLEMENT_NAME = 'supplement.body' + CASE_OVERVIEW_NAME = 'case_overview' + PWGS_ANALYSIS_NAME = 'pwgs.analysis' # deal with inconsistent capitalization BODY_KEY = { CNV_NAME: 'body', - SNV_INDEL_NAME: 'Body' + WGTS_SNV_INDEL_NAME: 'Body', + TAR_SNV_INDEL_NAME: 'Body' } XPCT_KEY = { CNV_NAME: 'Expression Percentile', - SNV_INDEL_NAME: 'Expression percentile' + WGTS_SNV_INDEL_NAME: 'Expression percentile' } - GENE = 'Gene' - RESULTS = 'results' EXPRESSION = 'expression' - MSI = 'msi' + MSI = 'MSI' + HRD = 'HRD' + T_DEPTH = 't_depth' + T_ALT_COUNT = 't_alt_count' DELTA_DEFAULTS = { + # WGS/WGTS deltas EXPRESSION: 0.1, # expression is recorded as a number, this delta is 10% - MSI: 1.0 # MSI is recorded as a percentage, this delta is 1.0% + MSI: 2.0, # MSI is recorded as a percentage, this delta is 2.0% + HRD: 0.01, + # TAR deltas, both are counts of reads + T_DEPTH: 25, + T_ALT_COUNT: 5 } PLACEHOLDER = 0 @@ -308,6 +466,19 @@ class report_equivalence_tester(logger): EQUIVALENT_STATUS = 'equivalent but not identical' NOT_EQUIVALENT_STATUS = 'not equivalent' + # additional plugin keys + ASSAY = 'assay' + GENE = 'Gene' + RESULTS = 'results' + GL = 'genomic_landscape' + GB = 'genomic_biomarkers' + GBP = 'Genomic biomarker plot' + GBV = 'Genomic biomarker value' + WGTS = 'WGTS' + WGS = 'WGS' + TAR = 'TAR' + PWGS = 'PWGS' + def __init__(self, report_paths, delta_path=None, log_level=logging.WARNING, log_path=None): self.logger = self.get_logger(log_level, __name__, log_path) @@ -323,7 +494,8 @@ def __init__(self, report_paths, delta_path=None, if msg: self.logger.error(msg) raise DjerbaReportDiffError(msg) - self.data = [self.read_and_preprocess_report(x) for x in report_paths] + self.data, assay = self.read_reports(report_paths) + apply_deltas = assay in [self.TAR, self.WGTS, self.WGS] if delta_path: with open(delta_path) as delta_file: deltas = json.loads(delta_file.read()) @@ -342,9 +514,9 @@ def __init__(self, report_paths, delta_path=None, self.logger.info("EQUIVALENT: Reports are identical") self.identical = True self.equivalent = True - elif self.deltas_are_equivalent(): + elif apply_deltas and self.deltas_are_equivalent(assay): # check if metrics without a delta match exactly - if self.non_deltas_are_equivalent(): + if self.non_deltas_are_equivalent(assay): msg = "EQUIVALENT: Reports are not identical, "+\ "but equivalent within tolerance" self.logger.info(msg) @@ -359,9 +531,17 @@ def __init__(self, report_paths, delta_path=None, self.logger.info(msg) self.equivalent = False - def deltas_are_equivalent(self): - eq = self.expressions_are_equivalent() and \ - self.msi_values_are_equivalent() + def deltas_are_equivalent(self, assay): + if assay in [self.WGTS, self.WGS]: + eq = self.expressions_are_equivalent() and \ + self.msi_values_are_equivalent() and \ + self.hrd_values_are_equivalent() + elif assay == self.TAR: + eq = self.t_counts_are_equivalent() + else: + msg = "Deltas are not defined for assay '{0}'".format(assay) + self.logger.error(msg) + raise DjerbaReportDiffError(msg) return eq def expressions_are_equivalent(self): @@ -370,7 +550,7 @@ def expressions_are_equivalent(self): Expression levels are permitted to differ by +/- delta """ equivalent = True - for name in [self.CNV_NAME, self.SNV_INDEL_NAME]: + for name in [self.CNV_NAME, self.WGTS_SNV_INDEL_NAME]: plugin_eq = True self.logger.debug("Checking expression levels for plugin: {0}".format(name)) expr0 = self.get_expressions_by_gene(self.data[0], name) @@ -423,9 +603,9 @@ def get_status(self): def get_status_emoji(self): status = self.get_status() if status == self.IDENTICAL_STATUS: - return '✅' # white check mark + return '✅' # white check mark on green elif status == self.EQUIVALENT_STATUS: - return '⚠' # warning sign + return '🟩' # green circle else: return '❌' # X mark @@ -444,38 +624,67 @@ def get_expressions_by_gene(self, data, plugin): expr[key] = value return expr - def get_msi(self, report_data): - return report_data['genomic_landscape']['results']\ - ['genomic_biomarkers']['MSI']['Genomic biomarker value'] + ### Start: Methods to evaluate biomarkers (HRD, MSI) - def msi_values_are_equivalent(self): - msi0 = self.get_msi(self.data[0]) - msi1 = self.get_msi(self.data[1]) - delta = self.deltas[self.MSI] - if abs(msi0 - msi1) < delta: - self.logger.info("MSI values are equivalent") + def get_biomarker(self, report_data, key): + return report_data['genomic_landscape']['results']\ + ['genomic_biomarkers'][key]['Genomic biomarker value'] + + def biomarker_values_are_equivalent(self, key): + bio0 = self.get_biomarker(self.data[0], key) + bio1 = self.get_biomarker(self.data[1], key) + delta = self.deltas[key] + if abs(bio0 - bio1) < delta: + self.logger.info("{0} values are equivalent".format(key)) eq = True else: - self.logger.info("MSI values are NOT equivalent") + self.logger.info("{1} values are NOT equivalent".format(key)) eq = False return eq - def non_deltas_are_equivalent(self): + def hrd_values_are_equivalent(self): + return self.biomarker_values_are_equivalent(self.HRD) + + def msi_values_are_equivalent(self): + return self.biomarker_values_are_equivalent(self.MSI) + + ### End: Methods to evaluate biomarkers (HRD, MSI) + + def non_deltas_are_equivalent(self, assay): # remove metrics with a non-zero tolerance range; compare the other metrics redacted = [] for data_set in self.data: redacted_set = deepcopy(data_set) - redacted_set = self.set_msi(redacted_set, self.PLACEHOLDER) - for name in [self.CNV_NAME, self.SNV_INDEL_NAME]: - redacted_set = self.set_expression(redacted_set, name, self.PLACEHOLDER) + if assay in [self.WGTS, self.WGS]: + redacted_set = self.set_hrd(redacted_set, self.PLACEHOLDER) + redacted_set = self.set_msi(redacted_set, self.PLACEHOLDER) + for name in [self.CNV_NAME, self.WGTS_SNV_INDEL_NAME]: + redacted_set = self.set_expression(redacted_set, name, self.PLACEHOLDER) + elif assay == self.TAR: + redacted_set = self.set_t_counts(redacted_set, self.PLACEHOLDER) redacted.append(redacted_set) diff = ReportDiff(redacted) return diff.is_identical() + def read_reports(self, report_paths): + plugins0, assay0 = self.read_and_preprocess_report(report_paths[0]) + plugins1, assay1 = self.read_and_preprocess_report(report_paths[1]) + data = [plugins0, plugins1] + msg = None + if assay0 != assay1: + msg = "Mismatched assays [{0}, {1}] in {2}".format(assay0, assay1, report_paths) + elif assay0 == None: + msg = "Cannot find assays for {0}".format(report_paths) + if msg: + self.logger.error(msg) + raise DjerbaReportDiffError(msg) + return [data, assay0] + def read_and_preprocess_report(self, report_path): """ Read report from a JSON file Replace variable elements (images, dates) with dummy values + Also find the assay type """ placeholder = 'redacted for benchmark comparison' self.logger.info("Preprocessing report path {0}".format(report_path)) @@ -489,21 +698,37 @@ def read_and_preprocess_report(self, report_path): self.logger.error("JSON error: {0}".format(err)) raise DjerbaReportDiffError(msg) from err plugins = data['plugins'] # don't compare config or core elements - # redact plugin versions, plots, dates + # redact plugin versions for plugin_name in plugins.keys(): plugins[plugin_name]['version'] = placeholder - results = 'results' - plugins[self.CNV_NAME][results]['cnv plot'] = placeholder - plugins[self.SNV_INDEL_NAME][results]['vaf_plot'] = placeholder - for biomarker in ['MSI', 'TMB', 'HRD']: - plugins['genomic_landscape'][results]['genomic_biomarkers'][biomarker]['Genomic biomarker plot'] = placeholder - for date_key in ['extract_date', 'report_signoff_date']: - plugins[self.SUPPLEMENT_NAME][results][date_key] = placeholder - # redact gene descriptions; text encoding issues can cause irrelevant discrepancies - for name in [self.CNV_NAME, self.SNV_INDEL_NAME, self.FUSION_NAME]: - for item in plugins[name]['merge_inputs']['gene_information_merger']: - item['Summary'] = placeholder - return plugins + # redact base64-encoded images; also check assay type + assay = None + if self.CASE_OVERVIEW_NAME in plugins: + assay = plugins[self.CASE_OVERVIEW_NAME][self.RESULTS][self.ASSAY] + if assay in [self.WGTS, self.WGS]: + plugins[self.CNV_NAME][self.RESULTS]['cnv plot'] = placeholder + plugins[self.WGTS_SNV_INDEL_NAME][self.RESULTS]['vaf_plot'] = placeholder + for biomarker in ['MSI', 'TMB', 'HRD']: + plugins[self.GL][self.RESULTS][self.GB][biomarker][self.GBP] = \ + placeholder + # TAR assay does not have images to redact + elif self.PWGS_ANALYSIS_NAME in plugins: + assay = self.PWGS + plugins[self.PWGS_ANALYSIS_NAME][self.RESULTS]['pwgs_base64'] = placeholder + # redact dates + if self.SUPPLEMENT_NAME in plugins: + for date_key in ['extract_date', 'report_signoff_date']: + plugins[self.SUPPLEMENT_NAME][self.RESULTS][date_key] = placeholder + else: + msg = 'Plugin {0} not found for {1}'.format(self.SUPPLEMENT_NAME, report_path) + self.logger.warning(msg) + # redact gene descriptions; text encoding issues can cause discrepancies + for name in [self.CNV_NAME, self.WGTS_SNV_INDEL_NAME, self.TAR_SNV_INDEL_NAME, + self.FUSION_NAME]: + if name in plugins: + for item in plugins[name]['merge_inputs']['gene_information_merger']: + item['Summary'] = placeholder + return plugins, assay def set_expression(self, data, plugin, value): # set all expressions for the given plugin to the same value @@ -519,11 +744,53 @@ def set_expression(self, data, plugin, value): item[xpct_key] = value return data - def set_msi(self, report_data, value): - report_data['genomic_landscape']['results']\ - ['genomic_biomarkers']['MSI']['Genomic biomarker value'] = value - return report_data + def set_hrd(self, data, value): + data[self.GL][self.RESULTS][self.GB][self.HRD][self.GBV] = value + return data + + def set_msi(self, data, value): + data[self.GL][self.RESULTS][self.GB][self.MSI][self.GBV] = value + return data + + def set_t_counts(self, data, value): + body_key = self.BODY_KEY[self.TAR_SNV_INDEL_NAME] + body = data[self.TAR_SNV_INDEL_NAME][self.RESULTS][body_key] + for item in body: + for key in [self.T_DEPTH, self.T_ALT_COUNT]: + item[key] = value + return data + + ### Start: Methods to evaluate TAR metrics (t_depth, t_alt_count) + + def get_tar_results_by_gene(self, data): + results = {} + body_key = self.BODY_KEY[self.TAR_SNV_INDEL_NAME] + for item in data[self.TAR_SNV_INDEL_NAME][self.RESULTS][body_key]: + results[item['Gene']] = item + return results + + def t_counts_are_equivalent(self): + tar0 = self.get_tar_results_by_gene(self.data[0]) + tar1 = self.get_tar_results_by_gene(self.data[1]) + if set(tar0.keys()) != set(tar1.keys()): + self.logger.info("Gene sets differ, TAR metrics are not equivalent") + eq = False + else: + eq = True + for gene in tar0.keys(): + t_depth_diff = abs(tar0[gene][self.T_DEPTH] - tar1[gene][self.T_DEPTH]) + t_alt_diff = abs(tar0[gene][self.T_ALT_COUNT] - tar1[gene][self.T_ALT_COUNT]) + if t_depth_diff > self.deltas.get(self.T_DEPTH): + self.logger.info(self.T_DEPTH+' not equivalent for gene '+gene) + eq = False + elif t_alt_diff > self.deltas.get(self.T_ALT_COUNT): + self.logger.info(self.T_ALT_COUNT+' not equivalent for gene '+gene) + eq = False + if not eq: + break + return eq + ### End: Methods to evaluate TAR metrics (t_depth, t_alt_count) class ReportDiff(unittest.TestCase): """Use a test assertion to diff two data structures""" diff --git a/src/lib/djerba/version.py b/src/lib/djerba/version.py index 0660f352f..365a02c2d 100644 --- a/src/lib/djerba/version.py +++ b/src/lib/djerba/version.py @@ -3,7 +3,7 @@ # 2) we can import it in setup.py for the same reason # 3) it only needs to be stored in one place # See https://stackoverflow.com/a/16084844 -__version__ = '1.7.8' +__version__ = '1.7.9' def get_djerba_version(): return __version__ diff --git a/src/test/core/prepop.ini b/src/test/core/prepop.ini new file mode 100644 index 000000000..1af528cf4 --- /dev/null +++ b/src/test/core/prepop.ini @@ -0,0 +1,4 @@ +[input_params_helper] +assay = WGTS +project = Tunis +study = Toronto diff --git a/src/test/core/simple_report_for_update.json b/src/test/core/simple_report_for_update.json index fe8b39b2d..4247a242d 100644 --- a/src/test/core/simple_report_for_update.json +++ b/src/test/core/simple_report_for_update.json @@ -43,6 +43,7 @@ ], "merge_inputs": {}, "results": { + "failed": false, "summary_text": "Summary text goes here" } } diff --git a/src/test/core/simple_report_for_update_failed.json b/src/test/core/simple_report_for_update_failed.json new file mode 100644 index 000000000..c523be798 --- /dev/null +++ b/src/test/core/simple_report_for_update_failed.json @@ -0,0 +1,98 @@ +{ + "core": { + "author": "Test Author", + "document_config": "document_config.json", + "report_id": "placeholder", + "core_version": "1.6.5", + "extract_time": "2024-07-17_17:00:08 -0400" + }, + "plugins": { + "patient_info": { + "plugin_name": "patient_info plugin", + "version": "1.0.0", + "priorities": { + "configure": 100, + "extract": 100, + "render": 30 + }, + "attributes": [ + "clinical" + ], + "merge_inputs": {}, + "results": { + "patient_name": "LAST, FIRST", + "patient_dob": "yyyy/mm/dd", + "patient_genetic_sex": "SEX", + "requisitioner_email": "NAME@domain.com", + "physician_licence_number": "nnnnnnnn", + "physician_name": "LAST, FIRST", + "physician_phone_number": "nnn-nnn-nnnn", + "hospital_name_and_address": "HOSPITAL NAME AND ADDRESS" + } + }, + "summary": { + "plugin_name": "summary plugin", + "version": "0.1", + "priorities": { + "configure": 400, + "extract": 400, + "render": 400 + }, + "attributes": [ + "clinical" + ], + "merge_inputs": {}, + "results": { + "failed": true, + "summary_text": "Summary text goes here" + } + } + }, + "mergers": {}, + "config": { + "core": { + "author": "Test Author", + "report_id": "placeholder", + "attributes": "", + "depends_configure": "", + "depends_extract": "", + "configure_priority": "100", + "extract_priority": "100", + "render_priority": "100", + "report_version": "1", + "input_params": "input_params.json", + "author": "CGI Author", + "archive_name": "djerba", + "archive_url": "http://${username}:${password}@${address}:${port}", + "document_config": "document_config.json" + }, + "patient_info": { + "attributes": "clinical", + "depends_configure": "", + "depends_extract": "", + "configure_priority": "100", + "extract_priority": "100", + "render_priority": "30", + "patient_name": "LAST, FIRST", + "patient_dob": "yyyy/mm/dd", + "patient_genetic_sex": "SEX", + "requisitioner_email": "NAME@domain.com", + "physician_licence_number": "nnnnnnnn", + "physician_name": "LAST, FIRST", + "physician_phone_number": "nnn-nnn-nnnn", + "hospital_name_and_address": "HOSPITAL NAME AND ADDRESS" + }, + "summary": { + "summary_file": "lorem.txt", + "attributes": "clinical", + "depends_configure": "", + "depends_extract": "", + "configure_priority": "400", + "extract_priority": "400", + "render_priority": "400" + } + }, + "html_cache": { + "placeholder_report.clinical": "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" + } +} diff --git a/src/test/core/test_core.py b/src/test/core/test_core.py index 8d6685327..eb521360a 100755 --- a/src/test/core/test_core.py +++ b/src/test/core/test_core.py @@ -36,8 +36,9 @@ class TestCore(TestBase): LOREM_FILENAME = 'lorem.txt' SIMPLE_REPORT_JSON = 'simple_report_expected.json' SIMPLE_REPORT_UPDATE_JSON = 'simple_report_for_update.json' + SIMPLE_REPORT_UPDATE_FAILED_JSON = 'simple_report_for_update_failed.json' SIMPLE_CONFIG_MD5 = '04b749b3ec489ed9c06c1a06eb2dc886' - SIMPLE_REPORT_MD5 = 'ab049488c58758e26b0ad1c480c28c99' + SIMPLE_REPORT_MD5 = 'cfa53b636c7e8ae0f78fff698c4f76b7' class mock_args: """Use instead of argparse to store params for testing""" @@ -182,9 +183,9 @@ def test_attributes(self): self.assertTrue(plugin.check_attributes_known(attributes)) config.set('demo1', 'attributes', 'clinical,awesome') attributes = plugin.get_config_wrapper(config).get_my_attributes() - with self.assertLogs('djerba.core.configure', level=logging.WARNING) as log_context: + with self.assertLogs('djerba:demo1', level=logging.WARNING) as log_context: self.assertFalse(plugin.check_attributes_known(attributes)) - msg = "WARNING:djerba.core.configure:Unknown attribute 'awesome' in config" + msg = "WARNING:djerba:demo1:Unknown attribute 'awesome' in config" self.assertIn(msg, log_context.output) def test_simple(self): @@ -192,9 +193,9 @@ def test_simple(self): config = self.read_demo1_config(plugin) # test a simple plugin self.assertTrue(plugin.validate_minimal_config(config)) - with self.assertLogs('djerba.core.configure', level=logging.DEBUG) as log_context: + with self.assertLogs('djerba:demo1', level=logging.DEBUG) as log_context: self.assertTrue(plugin.validate_full_config(config)) - msg = 'DEBUG:djerba.core.configure:'+\ + msg = 'DEBUG:djerba:demo1:'+\ '8 expected INI param(s) found for component demo1' self.assertIn(msg, log_context.output) @@ -243,9 +244,9 @@ def test_required(self): # now give foo a config value config.set('demo1', 'foo', 'snark') self.assertTrue(plugin.validate_minimal_config(config)) - with self.assertLogs('djerba.core.configure', level=logging.DEBUG) as log_context: + with self.assertLogs('djerba:demo1', level=logging.DEBUG) as log_context: self.assertTrue(plugin.validate_full_config(config)) - msg = 'DEBUG:djerba.core.configure:'+\ + msg = 'DEBUG:djerba:demo1:'+\ '9 expected INI param(s) found for component demo1' self.assertIn(msg, log_context.output) # test setting all requirements @@ -621,6 +622,26 @@ def test_report_cli(self): self.assertEqual(result.returncode, 0) self.assertSimpleReport(json_path, html) + def test_setup_cli(self): + mode = 'setup' + ini_path = os.path.join(self.tmp_dir, 'config.ini') + html = os.path.join(self.tmp_dir, 'placeholder_report.clinical.html') + cmd = [ + 'djerba.py', mode, + '--assay', 'wgts', + '--ini', ini_path, + '--compact' + ] + result = subprocess_runner().run(cmd) + self.assertEqual(result.returncode, 0) + self.assertEqual(self.getMD5(ini_path), 'a211144356b5ec200e1c31ecd3128b45') + os.remove(ini_path) + prepop_path = os.path.join(self.test_source_dir, 'prepop.ini') + cmd.extend(['--pre-populate', prepop_path]) + result = subprocess_runner().run(cmd) + self.assertEqual(result.returncode, 0) + self.assertEqual(self.getMD5(ini_path), '2387e66d783b1deb0fe5361e7770ec7a') + def test_update_cli_with_ini(self): mode = 'update' work_dir = self.tmp_dir @@ -648,7 +669,7 @@ def test_update_cli_with_ini(self): html_path = os.path.join(self.tmp_dir, 'placeholder_report.clinical.html') with open(html_path) as html_file: html_string = html_file.read() - self.assert_report_MD5(html_string, '5bc52ffc10821f166fed7b3055cc8bad') + self.assert_report_MD5(html_string, 'a262bf44dc2d759f165bbe817ec16d22') pdf_path = os.path.join(self.tmp_dir, 'placeholder_report.clinical.pdf') self.assertTrue(os.path.isfile(pdf_path)) updated_path = os.path.join(self.tmp_dir, 'simple_report_for_update.updated.json') @@ -661,24 +682,39 @@ def test_update_cli_with_summary(self): summary_path = os.path.join(self.test_source_dir, 'alternate_summary.txt') # run djerba.py and check the results json_path = os.path.join(self.test_source_dir, self.SIMPLE_REPORT_UPDATE_JSON) - cmd = [ + cmd_base = [ 'djerba.py', mode, '--work-dir', work_dir, '--summary', summary_path, - '--json', json_path, '--out-dir', self.tmp_dir, '--pdf' ] + cmd = cmd_base + ['--json', json_path] result = subprocess_runner().run(cmd) self.assertEqual(result.returncode, 0) html_path = os.path.join(self.tmp_dir, 'placeholder_report.clinical.html') with open(html_path) as html_file: html_string = html_file.read() - self.assert_report_MD5(html_string, '285adea0d50933a5da00c6f0452ba045') + self.assert_report_MD5(html_string, '781d477894d5a6e269cb68535a82ca89') pdf_path = os.path.join(self.tmp_dir, 'placeholder_report.clinical.pdf') self.assertTrue(os.path.isfile(pdf_path)) updated_path = os.path.join(self.tmp_dir, 'simple_report_for_update.updated.json') self.assertTrue(os.path.isfile(updated_path)) + # test again with a failed report + for output in [html_path, pdf_path, updated_path]: + os.remove(output) + json_path = os.path.join(self.test_source_dir, self.SIMPLE_REPORT_UPDATE_FAILED_JSON) + cmd_failed = cmd_base + ['--json', json_path] + result = subprocess_runner().run(cmd_failed) + self.assertEqual(result.returncode, 0) + html_path = os.path.join(self.tmp_dir, 'placeholder_report.clinical.html') + with open(html_path) as html_file: + html_string = html_file.read() + self.assert_report_MD5(html_string, '093ca0030bcb2a69d9ac4d784a19b147') + pdf_path = os.path.join(self.tmp_dir, 'placeholder_report.clinical.pdf') + self.assertTrue(os.path.isfile(pdf_path)) + updated_path = os.path.join(self.tmp_dir, 'simple_report_for_update_failed.updated.json') + self.assertTrue(os.path.isfile(updated_path)) class TestModuleDir(TestCore): diff --git a/src/test/util/mini/test_mini.py b/src/test/util/mini/test_mini.py index 3369b31ca..c9e0b310a 100755 --- a/src/test/util/mini/test_mini.py +++ b/src/test/util/mini/test_mini.py @@ -16,7 +16,7 @@ class TestMiniBase(TestBase): JSON_NAME = 'simple_report_for_update.json' JSON_NO_SUMMARY = 'simple_report_no_summary.json' - REPORT_MD5 = '8ce3372f4935c4918294e9c36299303a' + REPORT_MD5 = 'd74c65f217a96361d81bc1837542a74b' REPORT_NO_SUMMARY_MD5 = '6c6f367792bee295f32ccac87d1401ab' def assert_setup(self, ini_path, summary_path=None): @@ -224,7 +224,7 @@ def test_report_only_summary(self): ] result = subprocess_runner().run(cmd) self.assertEqual(result.returncode, 0) - self.assert_report('5d483a2283fce6ec3f92d60eac5185eb') + self.assert_report('bdf747ef1156a4600e3402656fca68dc') def test_report_no_change(self): test_dir = os.path.dirname(os.path.realpath(__file__)) diff --git a/src/test/util/test_util.py b/src/test/util/test_util.py index 47338c2c4..652edc93e 100755 --- a/src/test/util/test_util.py +++ b/src/test/util/test_util.py @@ -11,12 +11,13 @@ from configparser import ConfigParser from glob import glob -from djerba.util.benchmark import benchmarker, report_equivalence_tester, \ +from djerba.util.benchmark_tools import benchmarker, report_equivalence_tester, \ DjerbaReportDiffError from djerba.util.environment import directory_finder from djerba.util.render_mako import mako_renderer from djerba.util.subprocess_runner import subprocess_runner from djerba.util.testing.tools import TestBase +from djerba.util.validator import path_validator class TestBenchmark(TestBase): @@ -24,25 +25,19 @@ class TestBenchmark(TestBase): class mock_report_args: """Use instead of argparse to store params for testing""" - def __init__(self, input_dir, output_dir, ref_path, samples, work_dir=None): - if not os.path.isdir(input_dir): - raise OSError("Input dir '{0}' is not a directory".format(input_dir)) - else: - self.input_dir = input_dir - if not os.path.isdir(output_dir): - raise OSError("Output dir '{0}' is not a directory".format(output_dir)) - else: - self.output_dir = output_dir + def __init__(self, input_dir, output_dir, ref_dir, samples, work_dir=None): + v = path_validator() + v.validate_input_dir(input_dir) + v.validate_output_dir(output_dir) + v.validate_input_dir(ref_dir) + self.input_dir = input_dir + self.output_dir = output_dir + self.ref_dir = ref_dir if work_dir==None: self.work_dir = output_dir - elif not os.path.isdir(work_dir): - raise OSError("Work dir '{0}' is not a directory".format(work_dir)) else: + v.validate_output_dir(work_dir) self.work_dir = work_dir - if not os.path.isfile(ref_path): - raise OSError("Reference path '{0}' is not a file".format(ref_path)) - else: - self.ref_path = ref_path self.sample = samples self.apply_cache = True self.update_cache = False @@ -52,30 +47,69 @@ def __init__(self, input_dir, output_dir, ref_path, samples, work_dir=None): self.verbose = False self.quiet = True + EXPECTED_OUTPUTS = [ + 'GSICAPBENCH_0001_TAR_diff.txt', + 'GSICAPBENCH_0001_TAR_ref.json', + 'GSICAPBENCH_0001_TAR_report.json', + 'GSICAPBENCH_0001_WGS_diff.txt', + 'GSICAPBENCH_0001_WGS_ref.json', + 'GSICAPBENCH_0001_WGS_report.json', + 'GSICAPBENCH_0002_TAR_diff.txt', + 'GSICAPBENCH_0002_TAR_ref.json', + 'GSICAPBENCH_0003_TAR_diff.txt', + 'GSICAPBENCH_0003_TAR_ref.json', + 'GSICAPBENCH_011291_PWGS_diff.txt', + 'GSICAPBENCH_011291_PWGS_ref.json', + 'GSICAPBENCH_011291_PWGS_report.json', + 'GSICAPBENCH_011303_PWGS_diff.txt', + 'GSICAPBENCH_011303_PWGS_ref.json', + 'GSICAPBENCH_011524_PWGS_diff.txt', + 'GSICAPBENCH_011524_PWGS_ref.json', + 'GSICAPBENCH_011633_PWGS_diff.txt', + 'GSICAPBENCH_011633_PWGS_ref.json', + 'GSICAPBENCH_1248_WGTS_diff.txt', + 'GSICAPBENCH_1248_WGTS_ref.json', + 'GSICAPBENCH_1248_WGTS_report.json', + 'GSICAPBENCH_1309_WGTS_diff.txt', + 'GSICAPBENCH_1309_WGTS_ref.json', + 'GSICAPBENCH_1390_WGTS_diff.txt', + 'GSICAPBENCH_1390_WGTS_ref.json', + 'GSICAPBENCH_1391_WGTS_diff.txt', + 'GSICAPBENCH_1391_WGTS_ref.json', + 'djerba_bench_test_inputs_summary.html' + ] + def setUp(self): super().setUp() # includes tmp_dir private_dir = directory_finder().get_private_dir() self.input_dir = os.path.join( private_dir, 'benchmarking', 'djerba_bench_test_inputs' ) - self.ref_path = os.path.join( - private_dir, 'benchmarking', 'djerba_bench_reference', 'bench_ref_paths.json' + self.ref_dir = os.path.join( + private_dir, 'benchmarking', 'djerba_bench_reference' ) - self.samples = ['GSICAPBENCH_1219', 'GSICAPBENCH_1273', 'GSICAPBENCH_1275'] + # use a reduced set of samples for greater speed + self.samples = ['GSICAPBENCH_0001', 'GSICAPBENCH_011291', 'GSICAPBENCH_1248'] + self.reports = [ + self.samples[0]+'_TAR', + self.samples[0]+'_WGS', + self.samples[1]+'_PWGS', + self.samples[2]+'_WGTS' + ] def test_inputs(self): - args = self.mock_report_args(self.input_dir, self.tmp_dir, self.ref_path, self.samples) + args = self.mock_report_args(self.input_dir, self.tmp_dir, self.ref_dir, self.samples) bench = benchmarker(args) bench_inputs = bench.find_inputs(self.input_dir) - self.assertEqual(sorted(list(bench_inputs.keys())), args.sample) + self.assertEqual(sorted(list(bench_inputs.keys())), self.reports) for k in bench_inputs.keys(): - self.assertEqual(len(bench_inputs[k]), 16) + self.assertEqual(len(bench_inputs[k]), 28) def test_setup(self): - args = self.mock_report_args(self.input_dir, self.tmp_dir, self.ref_path, self.samples) + args = self.mock_report_args(self.input_dir, self.tmp_dir, self.ref_dir, self.samples) bench = benchmarker(args) samples = bench.run_setup(args.input_dir, args.work_dir) - self.assertEqual(sorted(samples), args.sample) + self.assertEqual(sorted(samples), self.reports) for sample in samples: ini_path = os.path.join(self.tmp_dir, sample, 'config.ini') self.assertTrue(os.path.isfile(ini_path)) @@ -86,15 +120,15 @@ def test_outputs(self): os.mkdir(out_dir) os.mkdir(work_dir) args = self.mock_report_args( - self.input_dir, out_dir, self.ref_path, self.samples, work_dir + self.input_dir, out_dir, self.ref_dir, self.samples, work_dir ) #args.verbose = True # uncomment to view progress of report generation bench = benchmarker(args) samples = bench.run_setup(args.input_dir, args.work_dir) reports_path = bench.run_reports(samples, args.work_dir) - [data, html] = bench.run_comparison(reports_path, self.ref_path) + [data, html] = bench.run_comparison(reports_path, self.ref_dir) # check the JSON output - self.assertEqual(len(data['results']['donor_results']), 7) + self.assertEqual(len(data['results']['report_results']), 12) # check the HTML output exclude = ['Run time:', 'Djerba core version:'] html_lines = [] @@ -102,33 +136,13 @@ def test_outputs(self): if not any([re.search(x, line) for x in exclude]): html_lines.append(line) html_md5 = self.getMD5_of_string("\n".join(html_lines)) - # TODO update the md5 and output files; assertions commented out for now - # self.assertEqual(html_md5, 'a5cd7ccd3c717975b12f8d2b2d06ff56') + self.assertEqual(html_md5, 'af7d7975cbfaadb166572546b0c498f4') # check output files bench.write_outputs(data, html) run_dir_name = os.listdir(out_dir)[0] self.assertTrue(re.match('djerba_bench_test_inputs_runtime-', run_dir_name)) output_files = sorted(os.listdir(os.path.join(out_dir, run_dir_name))) - expected_files = [ - '100-009-005_LCM3-v1_report.json', - '100-009-006_LCM3-v1_report.json', - '100-009-008_LCM2-v1_report.json', - '100-PM-018_LCM4-v1_report.json', - '100-PM-019_LCM3-v1_report.json', - '100_JHU_004_LCM3_6-v1_report.json', - 'GSICAPBENCH_1219_diff.txt', - 'GSICAPBENCH_1219_report.json', - 'GSICAPBENCH_1232_diff.txt', - 'GSICAPBENCH_1233_diff.txt', - 'GSICAPBENCH_1273_diff.txt', - 'GSICAPBENCH_1273_report.json', - 'GSICAPBENCH_1275_diff.txt', - 'GSICAPBENCH_1275_report.json', - 'GSICAPBENCH_1288_diff.txt', - 'djerba_bench_test_inputs_summary.html' - ] - # TODO update list and uncomment this assertion - #self.assertEqual(output_files, expected_files) + self.assertEqual(output_files, self.EXPECTED_OUTPUTS) class TestDiffScript(TestBase):