From aa5e12e4b80093a0b64067f384a436c0cfef4544 Mon Sep 17 00:00:00 2001 From: Vadym Date: Tue, 21 Nov 2023 09:50:11 +0100 Subject: [PATCH] Add delivery report to Balsamic-QC workflow (#2689) ### Added: - Delivery report to Balsamic-QC workflow --- cg/cli/generate/report/utils.py | 5 ++ cg/constants/delivery.py | 52 ++++++------ cg/constants/report.py | 79 ++++++++++--------- cg/meta/report/balsamic.py | 32 +++++--- cg/meta/report/balsamic_qc.py | 16 ++++ cg/meta/report/balsamic_umi.py | 4 +- cg/meta/report/field_validators.py | 10 +-- cg/meta/report/mip_dna.py | 18 ++--- cg/meta/report/report_api.py | 28 +++---- cg/meta/report/rnafusion.py | 10 +-- cg/meta/report/templates/balsamic_report.html | 14 ++-- 11 files changed, 153 insertions(+), 115 deletions(-) create mode 100644 cg/meta/report/balsamic_qc.py diff --git a/cg/cli/generate/report/utils.py b/cg/cli/generate/report/utils.py index dc3383e58b..dc02b7b3b7 100644 --- a/cg/cli/generate/report/utils.py +++ b/cg/cli/generate/report/utils.py @@ -11,11 +11,13 @@ Pipeline, ) from cg.meta.report.balsamic import BalsamicReportAPI +from cg.meta.report.balsamic_qc import BalsamicQCReportAPI from cg.meta.report.balsamic_umi import BalsamicUmiReportAPI from cg.meta.report.mip_dna import MipDNAReportAPI from cg.meta.report.report_api import ReportAPI from cg.meta.report.rnafusion import RnafusionReportAPI from cg.meta.workflow.balsamic import BalsamicAnalysisAPI +from cg.meta.workflow.balsamic_qc import BalsamicQCAnalysisAPI from cg.meta.workflow.balsamic_umi import BalsamicUmiAnalysisAPI from cg.meta.workflow.mip_dna import MipDNAAnalysisAPI from cg.meta.workflow.rnafusion import RnafusionAnalysisAPI @@ -85,6 +87,9 @@ def get_report_api_pipeline(context: click.Context, pipeline: Pipeline) -> Repor Pipeline.BALSAMIC_UMI: BalsamicUmiReportAPI( config=context.obj, analysis_api=BalsamicUmiAnalysisAPI(config=context.obj) ), + Pipeline.BALSAMIC_QC: BalsamicQCReportAPI( + config=context.obj, analysis_api=BalsamicQCAnalysisAPI(config=context.obj) + ), Pipeline.MIP_DNA: MipDNAReportAPI( config=context.obj, analysis_api=MipDNAAnalysisAPI(config=context.obj) ), diff --git a/cg/constants/delivery.py b/cg/constants/delivery.py index 7dc08365e8..c6c98eb0b6 100644 --- a/cg/constants/delivery.py +++ b/cg/constants/delivery.py @@ -2,19 +2,19 @@ from cg.constants.constants import Pipeline -ONLY_ONE_CASE_PER_TICKET = [ +ONLY_ONE_CASE_PER_TICKET: list[Pipeline] = [ Pipeline.FASTQ, Pipeline.MICROSALT, Pipeline.SARS_COV_2, ] -SKIP_MISSING = [ +SKIP_MISSING: list[Pipeline] = [ Pipeline.FASTQ, Pipeline.MICROSALT, Pipeline.SARS_COV_2, ] -BALSAMIC_ANALYSIS_CASE_TAGS = [ +BALSAMIC_ANALYSIS_CASE_TAGS: list[set[str]] = [ {"delivery-report"}, {"multiqc-html"}, {"metrics"}, @@ -36,21 +36,22 @@ {"vcf2cytosure"}, ] -BALSAMIC_ANALYSIS_SAMPLE_TAGS = [ +BALSAMIC_ANALYSIS_SAMPLE_TAGS: list[set[str]] = [ {"cram"}, {"cram-index"}, ] -BALSAMIC_QC_ANALYSIS_CASE_TAGS = [ +BALSAMIC_QC_ANALYSIS_CASE_TAGS: list[set[str]] = [ + {"delivery-report"}, {"multiqc-html"}, ] -BALSAMIC_QC_ANALYSIS_SAMPLE_TAGS = [ +BALSAMIC_QC_ANALYSIS_SAMPLE_TAGS: list[set[str]] = [ {"qc-cram"}, {"qc-cram-index"}, ] -BALSAMIC_UMI_ANALYSIS_CASE_TAGS = [ +BALSAMIC_UMI_ANALYSIS_CASE_TAGS: list[set[str]] = [ {"vcf-umi-snv"}, {"vcf-umi-snv-index"}, {"vcf-umi-snv-research"}, @@ -61,7 +62,7 @@ BALSAMIC_UMI_ANALYSIS_CASE_TAGS.extend(BALSAMIC_ANALYSIS_CASE_TAGS) -BALSAMIC_UMI_ANALYSIS_SAMPLE_TAGS = [ +BALSAMIC_UMI_ANALYSIS_SAMPLE_TAGS: list[set[str]] = [ {"umi-cram"}, {"umi-cram-index"}, ] @@ -69,7 +70,7 @@ BALSAMIC_UMI_ANALYSIS_SAMPLE_TAGS.extend(BALSAMIC_ANALYSIS_SAMPLE_TAGS) -MIP_DNA_ANALYSIS_CASE_TAGS = [ +MIP_DNA_ANALYSIS_CASE_TAGS: list[set[str]] = [ {"delivery-report"}, {"vcf-clinical-sv-bin"}, {"vcf-clinical-sv-bin-index"}, @@ -93,9 +94,14 @@ {"vcf-sv-research-index"}, ] -MIP_DNA_ANALYSIS_SAMPLE_TAGS = [{"bam"}, {"bam-index"}, {"cram"}, {"cram-index"}] +MIP_DNA_ANALYSIS_SAMPLE_TAGS: list[set[str]] = [ + {"bam"}, + {"bam-index"}, + {"cram"}, + {"cram-index"}, +] -MIP_RNA_ANALYSIS_CASE_TAGS = [ +MIP_RNA_ANALYSIS_CASE_TAGS: list[set[str]] = [ {"fusion", "clinical", "pdf"}, {"fusion", "research", "pdf"}, {"fusion", "vcf"}, @@ -107,7 +113,7 @@ {"multiqc-html"}, ] -MIP_RNA_ANALYSIS_SAMPLE_TAGS = [ +MIP_RNA_ANALYSIS_SAMPLE_TAGS: list[set[str]] = [ {"fusion", "star-fusion"}, {"fusion", "arriba"}, {"cram"}, @@ -117,7 +123,7 @@ {"salmon-quant"}, ] -MICROSALT_ANALYSIS_CASE_TAGS = [ +MICROSALT_ANALYSIS_CASE_TAGS: list[set[str]] = [ {"microsalt-qc"}, {"microsalt-type"}, {"assembly"}, @@ -126,24 +132,24 @@ {"reference-alignment-deduplicated"}, ] -MICROSALT_ANALYSIS_SAMPLE_TAGS = [] +MICROSALT_ANALYSIS_SAMPLE_TAGS: list[set[str]] = [] -FASTQ_ANALYSIS_CASE_TAGS = [] +FASTQ_ANALYSIS_CASE_TAGS: list[set[str]] = [] -FASTQ_ANALYSIS_SAMPLE_TAGS = [ +FASTQ_ANALYSIS_SAMPLE_TAGS: list[set[str]] = [ {"fastq"}, ] -SARSCOV2_ANALYSIS_CASE_TAGS = [ +SARSCOV2_ANALYSIS_CASE_TAGS: list[set[str]] = [ {"pangolin"}, {"ks-delivery"}, ] -SARSCOV2_ANALYSIS_SAMPLE_TAGS = [ +SARSCOV2_ANALYSIS_SAMPLE_TAGS: list[set[str]] = [ {"fastq"}, ] -RNAFUSION_ANALYSIS_CASE_TAGS = [ +RNAFUSION_ANALYSIS_CASE_TAGS: list[set[str]] = [ {"fusion", "arriba"}, {"fusion", "star-fusion"}, {"fusion", "fusioncatcher"}, @@ -160,10 +166,10 @@ {"delivery-report"}, ] -RNAFUSION_ANALYSIS_SAMPLE_TAGS = [] +RNAFUSION_ANALYSIS_SAMPLE_TAGS: list[set[str]] = [] -PIPELINE_ANALYSIS_TAG_MAP = { +PIPELINE_ANALYSIS_TAG_MAP: dict[Pipeline, dict] = { Pipeline.BALSAMIC: { "case_tags": BALSAMIC_ANALYSIS_CASE_TAGS, "sample_tags": BALSAMIC_ANALYSIS_SAMPLE_TAGS, @@ -204,5 +210,5 @@ PIPELINE_ANALYSIS_OPTIONS = PIPELINE_ANALYSIS_TAG_MAP.keys() -INBOX_NAME = "inbox" -OUTBOX_NAME = "outbox" +INBOX_NAME: str = "inbox" +OUTBOX_NAME: str = "outbox" diff --git a/cg/constants/report.py b/cg/constants/report.py index dd11c1eb3e..953f654799 100644 --- a/cg/constants/report.py +++ b/cg/constants/report.py @@ -1,18 +1,18 @@ -# Delivery report constants - +"""Delivery report constants.""" from cg.constants import DataDelivery from cg.constants.constants import Pipeline -BALSAMIC_REPORT_ACCREDITED_PANELS = ["gmsmyeloid"] +BALSAMIC_REPORT_ACCREDITED_PANELS: list[str] = ["gmsmyeloid"] -REPORT_SUPPORTED_PIPELINES = ( +REPORT_SUPPORTED_PIPELINES: tuple[Pipeline, ...] = ( Pipeline.BALSAMIC, Pipeline.BALSAMIC_UMI, + Pipeline.BALSAMIC_QC, Pipeline.MIP_DNA, Pipeline.RNAFUSION, ) -REPORT_SUPPORTED_DATA_DELIVERY = ( +REPORT_SUPPORTED_DATA_DELIVERY: tuple[DataDelivery, ...] = ( DataDelivery.ANALYSIS_FILES, DataDelivery.ANALYSIS_SCOUT, DataDelivery.FASTQ_ANALYSIS, @@ -22,18 +22,18 @@ DataDelivery.SCOUT, ) -NA_FIELD = "N/A" -YES_FIELD = "Ja" -NO_FIELD = "Nej" -PRECISION = 2 +NA_FIELD: str = "N/A" +YES_FIELD: str = "Ja" +NO_FIELD: str = "Nej" +PRECISION: int = 2 -REPORT_GENDER = { +REPORT_GENDER: dict[str, str] = { "unknown": "Okänd", "female": "Kvinna", "male": "Man", } -BALSAMIC_ANALYSIS_TYPE = { +BALSAMIC_ANALYSIS_TYPE: dict[str, str] = { "tumor_wgs": "Tumör-endast (helgenomsekvensering)", "tumor_normal_wgs": "Tumör/normal (helgenomsekvensering)", "tumor_panel": "Tumör-endast (panelsekvensering)", @@ -41,7 +41,7 @@ } # Report required fields (OPTIONAL: "version") -REQUIRED_REPORT_FIELDS = [ +REQUIRED_REPORT_FIELDS: list[str] = [ "customer", "date", "case", @@ -49,14 +49,14 @@ ] # Customer required fields (OPTIONAL: "id") -REQUIRED_CUSTOMER_FIELDS = [ +REQUIRED_CUSTOMER_FIELDS: list[str] = [ "name", "invoice_address", "scout_access", ] # Case required fields -REQUIRED_CASE_FIELDS = [ +REQUIRED_CASE_FIELDS: list[str] = [ "name", "id", "samples", @@ -65,32 +65,32 @@ ] # Application required fields (OPTIONAL: "version", "prep_category", "description", "limitations", "external") -REQUIRED_APPLICATION_FIELDS = [ +REQUIRED_APPLICATION_FIELDS: list[str] = [ "tag", "accredited", ] # Data analysis required fields -_REQUIRED_DATA_ANALYSIS_FIELDS = [ +REQUIRED_DATA_ANALYSIS_FIELDS: list[str] = [ "customer_pipeline", "pipeline", "pipeline_version", "genome_build", ] -REQUIRED_DATA_ANALYSIS_MIP_DNA_FIELDS = _REQUIRED_DATA_ANALYSIS_FIELDS + [ +REQUIRED_DATA_ANALYSIS_MIP_DNA_FIELDS: list[str] = REQUIRED_DATA_ANALYSIS_FIELDS + [ "panels", ] -REQUIRED_DATA_ANALYSIS_BALSAMIC_FIELDS = _REQUIRED_DATA_ANALYSIS_FIELDS + [ +REQUIRED_DATA_ANALYSIS_BALSAMIC_FIELDS: list[str] = REQUIRED_DATA_ANALYSIS_FIELDS + [ "type", "variant_callers", ] -REQUIRED_DATA_ANALYSIS_RNAFUSION_FIELDS = _REQUIRED_DATA_ANALYSIS_FIELDS +REQUIRED_DATA_ANALYSIS_RNAFUSION_FIELDS: list[str] = REQUIRED_DATA_ANALYSIS_FIELDS # Sample required fields -_REQUIRED_SAMPLE_FIELDS = [ +_REQUIRED_SAMPLE_FIELDS: list[str] = [ "name", "id", "ticket", @@ -102,48 +102,50 @@ "timestamps", ] -REQUIRED_SAMPLE_MIP_DNA_FIELDS = _REQUIRED_SAMPLE_FIELDS + [ +REQUIRED_SAMPLE_MIP_DNA_FIELDS: list[str] = _REQUIRED_SAMPLE_FIELDS + [ "status", ] -REQUIRED_SAMPLE_BALSAMIC_FIELDS = _REQUIRED_SAMPLE_FIELDS + [ +REQUIRED_SAMPLE_BALSAMIC_FIELDS: list[str] = _REQUIRED_SAMPLE_FIELDS + [ "tumour", ] -REQUIRED_SAMPLE_RNAFUSION_FIELDS = REQUIRED_SAMPLE_BALSAMIC_FIELDS +REQUIRED_SAMPLE_RNAFUSION_FIELDS: list[str] = REQUIRED_SAMPLE_BALSAMIC_FIELDS # Methods required fields (OPTIONAL: "library_prep", "sequencing") -REQUIRED_SAMPLE_METHODS_FIELDS = [] +REQUIRED_SAMPLE_METHODS_FIELDS: list[str] = [] # Timestamp required fields (OPTIONAL: "prepared_at", "reads_updated_at") -REQUIRED_SAMPLE_TIMESTAMP_FIELDS = [ +REQUIRED_SAMPLE_TIMESTAMP_FIELDS: list[str] = [ "ordered_at", "received_at", # Optional for external samples ] # Metadata required fields -_REQUIRED_SAMPLE_METADATA_FIELDS = [ +_REQUIRED_SAMPLE_METADATA_FIELDS: list[str] = [ "million_read_pairs", "duplicates", ] -REQUIRED_SAMPLE_METADATA_MIP_DNA_WGS_FIELDS = _REQUIRED_SAMPLE_METADATA_FIELDS + [ +REQUIRED_SAMPLE_METADATA_MIP_DNA_WGS_FIELDS: list[str] = _REQUIRED_SAMPLE_METADATA_FIELDS + [ "gender", "mapped_reads", "mean_target_coverage", "pct_10x", ] -REQUIRED_SAMPLE_METADATA_MIP_DNA_FIELDS = REQUIRED_SAMPLE_METADATA_MIP_DNA_WGS_FIELDS + [ +REQUIRED_SAMPLE_METADATA_MIP_DNA_FIELDS: list[str] = REQUIRED_SAMPLE_METADATA_MIP_DNA_WGS_FIELDS + [ "bait_set", ] -_REQUIRED_SAMPLE_METADATA_BALSAMIC_FIELDS = _REQUIRED_SAMPLE_METADATA_FIELDS + [ +_REQUIRED_SAMPLE_METADATA_BALSAMIC_FIELDS: list[str] = _REQUIRED_SAMPLE_METADATA_FIELDS + [ "mean_insert_size", "fold_80", ] -REQUIRED_SAMPLE_METADATA_BALSAMIC_TARGETED_FIELDS = _REQUIRED_SAMPLE_METADATA_BALSAMIC_FIELDS + [ +REQUIRED_SAMPLE_METADATA_BALSAMIC_TARGETED_FIELDS: list[ + str +] = _REQUIRED_SAMPLE_METADATA_BALSAMIC_FIELDS + [ "bait_set", "bait_set_version", "median_target_coverage", @@ -152,20 +154,21 @@ "gc_dropout", ] -REQUIRED_SAMPLE_METADATA_BALSAMIC_TO_WGS_FIELDS = _REQUIRED_SAMPLE_METADATA_BALSAMIC_FIELDS + [ +REQUIRED_SAMPLE_METADATA_BALSAMIC_TO_WGS_FIELDS: list[ + str +] = _REQUIRED_SAMPLE_METADATA_BALSAMIC_FIELDS + [ "median_coverage", "pct_60x", "pct_reads_improper_pairs", ] -REQUIRED_SAMPLE_METADATA_BALSAMIC_TN_WGS_FIELDS = ( - REQUIRED_SAMPLE_METADATA_BALSAMIC_TO_WGS_FIELDS - + [ - "pct_15x", - ] -) +REQUIRED_SAMPLE_METADATA_BALSAMIC_TN_WGS_FIELDS: list[ + str +] = REQUIRED_SAMPLE_METADATA_BALSAMIC_TO_WGS_FIELDS + [ + "pct_15x", +] -REQUIRED_SAMPLE_METADATA_RNAFUSION_FIELDS = _REQUIRED_SAMPLE_METADATA_FIELDS + [ +REQUIRED_SAMPLE_METADATA_RNAFUSION_FIELDS: list[str] = _REQUIRED_SAMPLE_METADATA_FIELDS + [ "bias_5_3", "gc_content", "input_amount", diff --git a/cg/meta/report/balsamic.py b/cg/meta/report/balsamic.py index 0b140315bc..05911ac445 100644 --- a/cg/meta/report/balsamic.py +++ b/cg/meta/report/balsamic.py @@ -18,6 +18,7 @@ REQUIRED_SAMPLE_METHODS_FIELDS, REQUIRED_SAMPLE_TIMESTAMP_FIELDS, Pipeline, + REQUIRED_DATA_ANALYSIS_FIELDS, ) from cg.constants.scout_upload import BALSAMIC_CASE_TAGS from cg.meta.report.field_validators import get_million_read_pairs @@ -43,7 +44,7 @@ class BalsamicReportAPI(ReportAPI): - """API to create BALSAMIC delivery reports.""" + """API to create Balsamic delivery reports.""" def __init__(self, config: CGConfig, analysis_api: BalsamicAnalysisAPI): super().__init__(config=config, analysis_api=analysis_api) @@ -52,7 +53,7 @@ def __init__(self, config: CGConfig, analysis_api: BalsamicAnalysisAPI): def get_sample_metadata( self, case: Case, sample: Sample, analysis_metadata: BalsamicAnalysis ) -> Union[BalsamicTargetedSampleMetadataModel, BalsamicWGSSampleMetadataModel]: - """Return the sample metadata to include in the report.""" + """Return sample metadata to include in the report.""" sample_metrics: dict[str, BalsamicQCMetrics] = analysis_metadata.sample_metrics[ sample.internal_id ] @@ -73,7 +74,7 @@ def get_panel_metadata( sample_metrics: BalsamicTargetedQCMetrics, analysis_metadata: BalsamicAnalysis, ) -> BalsamicTargetedSampleMetadataModel: - """Returns a report metadata for BALSAMIC TGS analysis.""" + """Return report metadata for Balsamic TGS analysis.""" bed_version: BedVersion = self.status_db.get_bed_version_by_file_name( analysis_metadata.config.panel.capture_kit ) @@ -96,7 +97,7 @@ def get_panel_metadata( def get_wgs_metadata( self, million_read_pairs: float, sample_metrics: BalsamicWGSQCMetrics ) -> BalsamicWGSSampleMetadataModel: - """Returns a report metadata for BALSAMIC WGS analysis.""" + """Return report metadata for Balsamic WGS analysis.""" return BalsamicWGSSampleMetadataModel( million_read_pairs=million_read_pairs, median_coverage=sample_metrics.median_coverage if sample_metrics else None, @@ -112,7 +113,7 @@ def get_wgs_metadata( @staticmethod def get_wgs_percent_duplication(sample_metrics: BalsamicWGSQCMetrics): - """Returns the duplication percentage taking into account both reads.""" + """Return duplication percentage taking into account both reads.""" return ( (sample_metrics.percent_duplication_r1 + sample_metrics.percent_duplication_r2) / 2 if sample_metrics @@ -120,7 +121,7 @@ def get_wgs_percent_duplication(sample_metrics: BalsamicWGSQCMetrics): ) def get_data_analysis_type(self, case: Case) -> Optional[str]: - """Retrieves the data analysis type carried out.""" + """Return data analysis type carried out.""" return self.analysis_api.get_bundle_deliverables_type(case_id=case.internal_id) def get_genome_build(self, analysis_metadata: BalsamicAnalysis) -> str: @@ -129,7 +130,7 @@ def get_genome_build(self, analysis_metadata: BalsamicAnalysis) -> str: def get_variant_callers(self, _analysis_metadata: BalsamicAnalysis) -> list: """ - Extracts the list of BALSAMIC variant-calling filters and their versions (if available) from the + Return list of Balsamic variant-calling filters and their versions (if available) from the config.json file. """ sequencing_type: str = _analysis_metadata.config.analysis.sequencing_type @@ -154,7 +155,7 @@ def get_variant_callers(self, _analysis_metadata: BalsamicAnalysis) -> list: def get_variant_caller_version( var_caller_name: str, var_caller_versions: dict ) -> Optional[str]: - """Returns the version of a specific BALSAMIC tool.""" + """Return version of a specific Balsamic tool.""" for tool_name, versions in var_caller_versions.items(): if tool_name in var_caller_name: return versions[0] @@ -176,8 +177,13 @@ def get_report_accreditation( return False def get_required_fields(self, case: CaseModel) -> dict: - """Retrieves a dictionary with the delivery report required fields for BALSAMIC.""" + """Return a dictionary with the delivery report required fields for Balsamic.""" analysis_type: str = case.data_analysis.type + required_data_analysis_fields: list[str] = ( + REQUIRED_DATA_ANALYSIS_FIELDS + if self.analysis_api.pipeline == Pipeline.BALSAMIC_QC + else REQUIRED_DATA_ANALYSIS_BALSAMIC_FIELDS + ) required_sample_metadata_fields: list[str] = [] if BALSAMIC_ANALYSIS_TYPE["tumor_wgs"] in analysis_type: required_sample_metadata_fields: list[ @@ -201,7 +207,7 @@ def get_required_fields(self, case: CaseModel) -> dict: "applications": self.get_application_required_fields( case=case, required_fields=REQUIRED_APPLICATION_FIELDS ), - "data_analysis": REQUIRED_DATA_ANALYSIS_BALSAMIC_FIELDS, + "data_analysis": required_data_analysis_fields, "samples": self.get_sample_required_fields( case=case, required_fields=REQUIRED_SAMPLE_BALSAMIC_FIELDS ), @@ -217,15 +223,15 @@ def get_required_fields(self, case: CaseModel) -> dict: } def get_template_name(self) -> str: - """Retrieves the template name to render the delivery report.""" + """Return template name to render the delivery report.""" return Pipeline.BALSAMIC + "_report.html" def get_upload_case_tags(self) -> dict: - """Retrieves BALSAMIC upload case tags.""" + """Return Balsamic upload case tags.""" return BALSAMIC_CASE_TAGS def get_scout_uploaded_file_from_hk(self, case_id: str, scout_tag: str) -> Optional[str]: - """Return the file path of the uploaded to Scout file given its tag.""" + """Return file path of the uploaded to Scout file given its tag.""" version: Version = self.housekeeper_api.last_version(bundle=case_id) tags: list = self.get_hk_scout_file_tags(scout_tag=scout_tag) uploaded_file: File = self.housekeeper_api.get_latest_file( diff --git a/cg/meta/report/balsamic_qc.py b/cg/meta/report/balsamic_qc.py new file mode 100644 index 0000000000..9cf8f82331 --- /dev/null +++ b/cg/meta/report/balsamic_qc.py @@ -0,0 +1,16 @@ +"""Balsamic QC delivery report API.""" +import logging + +from cg.meta.report.balsamic import BalsamicReportAPI +from cg.meta.workflow.balsamic_qc import BalsamicQCAnalysisAPI +from cg.models.cg_config import CGConfig + +LOG = logging.getLogger(__name__) + + +class BalsamicQCReportAPI(BalsamicReportAPI): + """API to create Balsamic QC delivery reports.""" + + def __init__(self, config: CGConfig, analysis_api: BalsamicQCAnalysisAPI): + super().__init__(config=config, analysis_api=analysis_api) + self.analysis_api: BalsamicQCAnalysisAPI = analysis_api diff --git a/cg/meta/report/balsamic_umi.py b/cg/meta/report/balsamic_umi.py index 13186c7509..9dec8e2165 100644 --- a/cg/meta/report/balsamic_umi.py +++ b/cg/meta/report/balsamic_umi.py @@ -9,12 +9,12 @@ class BalsamicUmiReportAPI(BalsamicReportAPI): - """API to create BALSAMIC UMI delivery reports.""" + """API to create Balsamic UMI delivery reports.""" def __init__(self, config: CGConfig, analysis_api: BalsamicUmiAnalysisAPI): super().__init__(config=config, analysis_api=analysis_api) self.analysis_api: BalsamicUmiAnalysisAPI = analysis_api def get_upload_case_tags(self) -> dict: - """Retrieves BALSAMIC UMI upload case tags.""" + """Return Balsamic UMI upload case tags.""" return BALSAMIC_UMI_CASE_TAGS diff --git a/cg/meta/report/field_validators.py b/cg/meta/report/field_validators.py index 366904c2e1..1899c2c19f 100644 --- a/cg/meta/report/field_validators.py +++ b/cg/meta/report/field_validators.py @@ -8,14 +8,14 @@ def get_million_read_pairs(reads: int) -> Optional[float]: - """Represents the number of sequencing reads as millions of read pairs.""" + """Return number of sequencing reads as millions of read pairs.""" return ( round(reads / SCALE_TO_MILLION_READ_PAIRS, 1) if reads or isinstance(reads, int) else None ) def get_missing_fields(empty_fields: list, required_fields: list) -> list: - """Extracts the missing fields that are required to generate successfully the delivery report.""" + """Return missing fields that are required to generate successfully the delivery report.""" missing_fields = list() for field in empty_fields: if field in required_fields: @@ -24,7 +24,7 @@ def get_missing_fields(empty_fields: list, required_fields: list) -> list: def get_empty_fields(report_data: dict) -> list: - """Returns a list of empty report fields.""" + """Return list of empty report fields.""" empty_fields = list() for field, value in report_data.items(): if not value or value == NA_FIELD: @@ -35,7 +35,7 @@ def get_empty_fields(report_data: dict) -> list: def get_empty_report_data(report_data: ReportModel) -> dict: - """Retrieve empty fields from a report data model.""" + """Return empty fields from a report data model.""" empty_fields = { "report": get_empty_fields(report_data=report_data.model_dump()), "customer": get_empty_fields(report_data=report_data.customer.model_dump()), @@ -73,7 +73,7 @@ def get_empty_report_data(report_data: ReportModel) -> dict: def get_missing_report_data(empty_fields: dict, required_fields: dict) -> dict: - """Retrieve the missing required fields from a report data model.""" + """Return missing required fields from a report data model.""" nested_sources = ["applications", "samples", "methods", "timestamps", "metadata"] missing_fields = dict() for source in empty_fields: diff --git a/cg/meta/report/mip_dna.py b/cg/meta/report/mip_dna.py index aa843f405b..9011f9af5f 100644 --- a/cg/meta/report/mip_dna.py +++ b/cg/meta/report/mip_dna.py @@ -41,7 +41,7 @@ def __init__(self, config: CGConfig, analysis_api: MipDNAAnalysisAPI): def get_sample_metadata( self, case: Case, sample: Sample, analysis_metadata: MipAnalysis ) -> MipDNASampleMetadataModel: - """Fetches the MIP DNA sample metadata to include in the report.""" + """Return MIP DNA sample metadata to include in the report.""" parsed_metrics = get_sample_id_metric( sample_id=sample.internal_id, sample_id_metrics=analysis_metadata.sample_id_metrics ) @@ -57,7 +57,7 @@ def get_sample_metadata( ) def get_sample_coverage(self, sample: Sample, case: Case) -> dict: - """Calculates coverage values for a specific sample.""" + """Return coverage values for a specific sample.""" genes = self.get_genes_from_scout(panels=case.panels) sample_coverage = self.chanjo_api.sample_coverage( sample_id=sample.internal_id, panel_genes=genes @@ -68,7 +68,7 @@ def get_sample_coverage(self, sample: Sample, case: Case) -> dict: return dict() def get_genes_from_scout(self, panels: list) -> list: - """Extracts panel gene IDs information from Scout.""" + """Return panel gene IDs information from Scout.""" panel_genes = list() for panel in panels: panel_genes.extend(self.scout_api.get_genes(panel)) @@ -76,7 +76,7 @@ def get_genes_from_scout(self, panels: list) -> list: return panel_gene_ids def get_genome_build(self, analysis_metadata: MipAnalysis) -> str: - """Returns the build version of the genome reference of a specific case.""" + """Return build version of the genome reference of a specific case.""" return analysis_metadata.genome_build def get_report_accreditation( @@ -89,7 +89,7 @@ def get_report_accreditation( return True def get_required_fields(self, case: CaseModel) -> dict: - """Retrieves a dictionary with the delivery report required fields for MIP DNA.""" + """Return dictionary with the delivery report required fields for MIP DNA.""" return { "report": REQUIRED_REPORT_FIELDS, "customer": REQUIRED_CUSTOMER_FIELDS, @@ -112,7 +112,7 @@ def get_required_fields(self, case: CaseModel) -> dict: @staticmethod def get_sample_metadata_required_fields(case: CaseModel) -> dict: - """Retrieves sample metadata required fields associated to a specific sample ID.""" + """Return sample metadata required fields associated to a specific sample ID.""" required_sample_metadata_fields = dict() for sample in case.samples: required_fields = ( @@ -124,15 +124,15 @@ def get_sample_metadata_required_fields(case: CaseModel) -> dict: return required_sample_metadata_fields def get_template_name(self) -> str: - """Retrieves the template name to render the delivery report.""" + """Return template name to render the delivery report.""" return Pipeline.MIP_DNA + "_report.html" def get_upload_case_tags(self) -> dict: - """Retrieves MIP DNA upload case tags.""" + """Return MIP DNA upload case tags.""" return MIP_CASE_TAGS def get_scout_uploaded_file_from_hk(self, case_id: str, scout_tag: str) -> Optional[str]: - """Returns the file path of the uploaded to Scout file given its tag.""" + """Return file path of the uploaded to Scout file given its tag.""" version: Version = self.housekeeper_api.last_version(bundle=case_id) tags: list = self.get_hk_scout_file_tags(scout_tag=scout_tag) uploaded_files: Iterable[File] = self.housekeeper_api.get_files( diff --git a/cg/meta/report/report_api.py b/cg/meta/report/report_api.py index a26661f3ab..5f0152ac21 100644 --- a/cg/meta/report/report_api.py +++ b/cg/meta/report/report_api.py @@ -327,7 +327,7 @@ def get_case_analysis_data( analysis: Analysis, analysis_metadata: AnalysisModel, ) -> DataAnalysisModel: - """Retrieves the pipeline attributes used for data analysis.""" + """Return pipeline attributes used for data analysis.""" return DataAnalysisModel( customer_pipeline=case.data_analysis, data_delivery=case.data_delivery, @@ -341,7 +341,7 @@ def get_case_analysis_data( ) def get_scout_uploaded_files(self, case: Case) -> ScoutReportFiles: - """Extracts the files that will be uploaded to Scout.""" + """Return files that will be uploaded to Scout.""" return ScoutReportFiles( snv_vcf=self.get_scout_uploaded_file_from_hk( case_id=case.internal_id, scout_tag="snv_vcf" @@ -359,7 +359,7 @@ def get_scout_uploaded_files(self, case: Case) -> ScoutReportFiles: @staticmethod def get_sample_timestamp_data(sample: Sample) -> TimestampModel: - """Retrieves the sample processing dates.""" + """Return sample processing dates.""" return TimestampModel( ordered_at=sample.ordered_at, received_at=sample.received_at, @@ -373,11 +373,11 @@ def get_sample_metadata( sample: Sample, analysis_metadata: AnalysisModel, ) -> SampleMetadataModel: - """Return the sample metadata to include in the report.""" + """Return sample metadata to include in the report.""" raise NotImplementedError def get_data_analysis_type(self, case: Case) -> Optional[str]: - """Retrieves the data analysis type carried out.""" + """Return data analysis type carried out.""" case_sample: Sample = self.status_db.get_case_samples_by_case_id( case_internal_id=case.internal_id )[0].sample @@ -388,11 +388,11 @@ def get_data_analysis_type(self, case: Case) -> Optional[str]: return application.analysis_type if application else None def get_genome_build(self, analysis_metadata: AnalysisModel) -> str: - """Returns the build version of the genome reference of a specific case.""" + """Return build version of the genome reference of a specific case.""" raise NotImplementedError def get_variant_callers(self, _analysis_metadata: AnalysisModel) -> list: - """Extracts the list of variant-calling filters used during analysis.""" + """Return list of variant-calling filters used during analysis.""" return [] def get_report_accreditation( @@ -402,16 +402,16 @@ def get_report_accreditation( raise NotImplementedError def get_required_fields(self, case: CaseModel) -> dict: - """Retrieves a dictionary with the delivery report required fields.""" + """Return dictionary with the delivery report required fields.""" raise NotImplementedError def get_template_name(self) -> str: - """Retrieves the pipeline specific template name.""" + """Return pipeline specific template name.""" raise NotImplementedError @staticmethod def get_application_required_fields(case: CaseModel, required_fields: list) -> dict: - """Retrieves sample required fields.""" + """Return sample required fields.""" required_sample_fields = dict() for application in case.applications: required_sample_fields.update({application.tag: required_fields}) @@ -419,7 +419,7 @@ def get_application_required_fields(case: CaseModel, required_fields: list) -> d @staticmethod def get_sample_required_fields(case: CaseModel, required_fields: list) -> dict: - """Retrieves sample required fields.""" + """Return sample required fields.""" required_sample_fields = dict() for sample in case.samples: required_sample_fields.update({sample.id: required_fields}) @@ -427,7 +427,7 @@ def get_sample_required_fields(case: CaseModel, required_fields: list) -> dict: @staticmethod def get_timestamp_required_fields(case: CaseModel, required_fields: list) -> dict: - """Retrieves sample timestamps required fields.""" + """Return sample timestamps required fields.""" for sample in case.samples: if sample.application.external: required_fields.remove("received_at") @@ -435,10 +435,10 @@ def get_timestamp_required_fields(case: CaseModel, required_fields: list) -> dic return ReportAPI.get_sample_required_fields(case=case, required_fields=required_fields) def get_hk_scout_file_tags(self, scout_tag: str) -> Optional[list]: - """Retrieves pipeline specific uploaded to Scout Housekeeper file tags given a Scout key.""" + """Return pipeline specific uploaded to Scout Housekeeper file tags given a Scout key.""" tags = self.get_upload_case_tags().get(scout_tag) return list(tags) if tags else None def get_upload_case_tags(self): - """Retrieves pipeline specific upload case tags.""" + """Return pipeline specific upload case tags.""" raise NotImplementedError diff --git a/cg/meta/report/rnafusion.py b/cg/meta/report/rnafusion.py index c81d80f7fa..67d11716e0 100644 --- a/cg/meta/report/rnafusion.py +++ b/cg/meta/report/rnafusion.py @@ -36,7 +36,7 @@ def __init__(self, config: CGConfig, analysis_api: RnafusionAnalysisAPI): def get_sample_metadata( self, case: Case, sample: Sample, analysis_metadata: RnafusionAnalysis ) -> RnafusionSampleMetadataModel: - """Return the sample metadata to include in the report.""" + """Return sample metadata to include in the report.""" sample_metrics: RnafusionQCMetrics = analysis_metadata.sample_metrics[sample.internal_id] return RnafusionSampleMetadataModel( bias_5_3=sample_metrics.bias_5_3, @@ -63,7 +63,7 @@ def get_sample_metadata( ) def get_genome_build(self, analysis_metadata: AnalysisModel) -> str: - """Returns the build version of the genome reference of a specific case.""" + """Return build version of the genome reference of a specific case.""" return GenomeVersion.hg38.value def get_report_accreditation( @@ -73,15 +73,15 @@ def get_report_accreditation( return False def get_scout_uploaded_file_from_hk(self, case_id: str, scout_tag: str) -> Optional[str]: - """Return the file path of the uploaded to Scout file given its tag.""" + """Return file path of the uploaded to Scout file given its tag.""" return None def get_template_name(self) -> str: - """Retrieves the template name to render the delivery report.""" + """Return template name to render the delivery report.""" return Pipeline.RNAFUSION + "_report.html" def get_required_fields(self, case: CaseModel) -> dict: - """Return a dictionary with the delivery report required fields for Rnafusion.""" + """Return dictionary with the delivery report required fields for Rnafusion.""" return { "report": REQUIRED_REPORT_FIELDS, "customer": REQUIRED_CUSTOMER_FIELDS, diff --git a/cg/meta/report/templates/balsamic_report.html b/cg/meta/report/templates/balsamic_report.html index daa7681058..e4f780e187 100644 --- a/cg/meta/report/templates/balsamic_report.html +++ b/cg/meta/report/templates/balsamic_report.html @@ -151,12 +151,14 @@

Kundinformation

{{ case.data_analysis.type }} - - Tillämpade filter för variantanrop: {{ case.data_analysis.variant_callers }}
- - https://balsamic.readthedocs.io/en/latest/balsamic_filters.html - - + {% if case.data_analysis.pipeline != 'balsamic-qc' %} + + Tillämpade filter för variantanrop: {{ case.data_analysis.variant_callers }}
+ + https://balsamic.readthedocs.io/en/latest/balsamic_filters.html + + + {% endif %}