cg 76.0.0__py3-none-any.whl → 83.14.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cg/__init__.py +1 -1
- cg/apps/housekeeper/hk.py +18 -1
- cg/apps/tb/api.py +42 -5
- cg/cli/transfer.py +13 -2
- cg/cli/upload/mutacc.py +16 -3
- cg/cli/upload/scout.py +2 -2
- cg/cli/upload/utils.py +10 -1
- cg/cli/workflow/balsamic/base.py +86 -172
- cg/cli/workflow/balsamic/options.py +3 -48
- cg/cli/workflow/balsamic/umi.py +210 -15
- cg/cli/workflow/microsalt/base.py +4 -2
- cg/cli/workflow/mip_dna/base.py +1 -1
- cg/cli/workflow/nallo/base.py +73 -23
- cg/cli/workflow/nf_analysis.py +5 -207
- cg/cli/workflow/raredisease/base.py +41 -54
- cg/cli/workflow/rnafusion/base.py +38 -8
- cg/cli/workflow/taxprofiler/base.py +31 -18
- cg/cli/workflow/tomte/base.py +83 -10
- cg/constants/constants.py +25 -30
- cg/constants/devices.py +6 -1
- cg/constants/gene_panel.py +3 -1
- cg/constants/housekeeper_tags.py +28 -28
- cg/constants/lims.py +4 -0
- cg/constants/nf_analysis.py +0 -1
- cg/constants/observations.py +21 -5
- cg/constants/orderforms.py +3 -3
- cg/constants/pacbio.py +1 -0
- cg/constants/priority.py +1 -1
- cg/constants/report.py +1 -0
- cg/constants/scout.py +12 -9
- cg/constants/sequencing.py +2 -2
- cg/constants/tb.py +5 -5
- cg/exc.py +27 -5
- cg/meta/compress/compress.py +7 -2
- cg/meta/delivery_report/balsamic.py +3 -1
- cg/meta/delivery_report/delivery_report_api.py +4 -3
- cg/meta/delivery_report/nallo.py +11 -11
- cg/meta/delivery_report/raredisease.py +7 -3
- cg/meta/delivery_report/templates/macros/data_analysis/qc_metrics/balsamic_qc_metrics.html +1 -0
- cg/meta/delivery_report/templates/macros/ticket_system.html +1 -1
- cg/meta/observations/balsamic_observations_api.py +110 -14
- cg/meta/observations/mip_dna_observations_api.py +1 -1
- cg/meta/observations/nallo_observations_api.py +1 -1
- cg/meta/observations/observations_api.py +23 -32
- cg/meta/observations/raredisease_observations_api.py +1 -1
- cg/meta/tar/tar.py +5 -2
- cg/meta/transfer/lims.py +32 -3
- cg/meta/upload/balsamic/balsamic.py +1 -8
- cg/meta/upload/coverage.py +5 -5
- cg/meta/upload/raredisease/raredisease.py +3 -0
- cg/meta/upload/scout/hk_tags.py +1 -0
- cg/meta/upload/scout/nallo_config_builder.py +31 -7
- cg/meta/workflow/balsamic.py +70 -36
- cg/meta/workflow/fastq.py +8 -0
- cg/meta/workflow/microsalt/quality_controller/models.py +0 -2
- cg/meta/workflow/microsalt/quality_controller/quality_controller.py +8 -16
- cg/meta/workflow/microsalt/quality_controller/result_logger.py +3 -6
- cg/meta/workflow/microsalt/quality_controller/utils.py +2 -45
- cg/meta/workflow/nallo.py +21 -99
- cg/meta/workflow/nf_analysis.py +12 -263
- cg/meta/workflow/raredisease.py +3 -112
- cg/meta/workflow/rnafusion.py +2 -34
- cg/meta/workflow/taxprofiler.py +2 -38
- cg/meta/workflow/tomte.py +2 -42
- cg/models/balsamic/config.py +0 -24
- cg/models/balsamic/metrics.py +5 -3
- cg/models/cg_config.py +39 -16
- cg/models/deliverables/metric_deliverables.py +1 -1
- cg/models/delivery_report/metadata.py +2 -1
- cg/models/nallo/nallo.py +14 -64
- cg/models/nf_analysis.py +1 -41
- cg/models/raredisease/raredisease.py +1 -63
- cg/models/rnafusion/rnafusion.py +0 -26
- cg/models/scout/scout_load_config.py +5 -2
- cg/models/taxprofiler/taxprofiler.py +0 -42
- cg/models/tomte/tomte.py +0 -69
- cg/resources/nallo_bundle_filenames.yaml +292 -22
- cg/resources/raredisease_bundle_filenames.yaml +11 -1
- cg/resources/taxprofiler_bundle_filenames.yaml +20 -0
- cg/server/admin.py +106 -25
- cg/server/app.py +15 -4
- cg/server/endpoints/sequencing_run/dtos.py +21 -3
- cg/server/endpoints/sequencing_run/pacbio_sequencing_run.py +29 -10
- cg/server/endpoints/sequencing_run/pacbio_smrt_cell_metrics.py +20 -0
- cg/services/analysis_starter/{service.py → analysis_starter.py} +11 -9
- cg/services/analysis_starter/configurator/abstract_model.py +8 -0
- cg/services/analysis_starter/configurator/configurator.py +1 -1
- cg/services/analysis_starter/configurator/extensions/nallo.py +27 -0
- cg/services/analysis_starter/configurator/extensions/{abstract.py → pipeline_extension.py} +1 -1
- cg/services/analysis_starter/configurator/extensions/raredisease.py +3 -1
- cg/services/analysis_starter/configurator/extensions/tomte_extension.py +28 -0
- cg/services/analysis_starter/configurator/file_creators/balsamic_config.py +240 -0
- cg/services/analysis_starter/configurator/file_creators/gene_panel.py +10 -5
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/abstract.py +2 -1
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/models.py +40 -1
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/nallo.py +37 -0
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/raredisease.py +8 -5
- cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/tomte_params_file_creator.py +64 -0
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/creator.py +1 -1
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/nallo_sample_sheet_creator.py +65 -0
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/protocol.py +12 -0
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{raredisease.py → raredisease_sample_sheet_creator.py} +2 -2
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{rnafusion.py → rnafusion_sample_sheet_creator.py} +2 -2
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{taxprofiler.py → taxprofiler_sample_sheet_creator.py} +2 -2
- cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/tomte_sample_sheet_creator.py +36 -0
- cg/services/analysis_starter/configurator/implementations/balsamic.py +68 -0
- cg/services/analysis_starter/configurator/implementations/nextflow.py +22 -5
- cg/services/analysis_starter/configurator/models/balsamic.py +152 -0
- cg/services/analysis_starter/configurator/models/mip_dna.py +6 -8
- cg/services/analysis_starter/configurator/models/nextflow.py +9 -0
- cg/services/analysis_starter/constants.py +2 -0
- cg/services/analysis_starter/factories/configurator_factory.py +131 -51
- cg/services/analysis_starter/factories/starter_factory.py +36 -7
- cg/services/analysis_starter/input_fetcher/implementations/bam_fetcher.py +57 -0
- cg/services/analysis_starter/input_fetcher/implementations/fastq_fetcher.py +3 -3
- cg/services/analysis_starter/submitters/seqera_platform/{client.py → seqera_platform_client.py} +19 -3
- cg/services/analysis_starter/submitters/seqera_platform/seqera_platform_submitter.py +73 -0
- cg/services/analysis_starter/submitters/submitter.py +1 -1
- cg/services/analysis_starter/submitters/subprocess/submitter.py +2 -1
- cg/services/analysis_starter/tracker/implementations/balsamic.py +22 -0
- cg/services/analysis_starter/tracker/implementations/microsalt.py +4 -4
- cg/services/analysis_starter/tracker/implementations/mip_dna.py +4 -1
- cg/services/analysis_starter/tracker/implementations/{nextflow.py → nextflow_tracker.py} +6 -4
- cg/services/analysis_starter/tracker/tracker.py +19 -15
- cg/services/deliver_files/factory.py +1 -1
- cg/services/delivery_message/messages/__init__.py +24 -14
- cg/services/delivery_message/messages/{microsalt_mwr_message.py → microsalt_message.py} +1 -1
- cg/services/delivery_message/utils.py +4 -40
- cg/services/illumina/backup/backup_service.py +29 -7
- cg/services/orders/validation/constants.py +3 -0
- cg/services/orders/validation/index_sequences.py +558 -0
- cg/services/orders/validation/order_types/microsalt/models/sample.py +2 -3
- cg/services/run_devices/pacbio/data_storage_service/pacbio_store_service.py +39 -18
- cg/services/run_devices/pacbio/data_transfer_service/data_transfer_service.py +8 -2
- cg/services/run_devices/pacbio/data_transfer_service/dto.py +9 -3
- cg/services/run_devices/pacbio/data_transfer_service/utils.py +14 -7
- cg/services/run_devices/pacbio/metrics_parser/models.py +1 -0
- cg/services/run_devices/pacbio/sequencing_runs_service.py +35 -7
- cg/services/sequencing_qc_service/quality_checks/checks.py +18 -16
- cg/services/sequencing_qc_service/quality_checks/utils.py +82 -18
- cg/services/sequencing_qc_service/sequencing_qc_service.py +12 -10
- cg/store/crud/create.py +73 -42
- cg/store/crud/read.py +73 -7
- cg/store/crud/update.py +14 -3
- cg/store/models.py +98 -35
- cg/store/store.py +8 -1
- {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/METADATA +1 -1
- {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/RECORD +150 -138
- cg/services/analysis_starter/submitters/seqera_platform/submitter.py +0 -39
- cg/services/delivery_message/messages/microsalt_mwx_message.py +0 -18
- {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/WHEEL +0 -0
- {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import cast
|
|
3
4
|
|
|
4
5
|
from cg.meta.workflow.microsalt.constants import QUALITY_REPORT_FILE_NAME
|
|
5
|
-
from cg.meta.workflow.microsalt.metrics_parser import
|
|
6
|
-
MetricsParser,
|
|
7
|
-
QualityMetrics,
|
|
8
|
-
SampleMetrics,
|
|
9
|
-
)
|
|
6
|
+
from cg.meta.workflow.microsalt.metrics_parser import MetricsParser, QualityMetrics, SampleMetrics
|
|
10
7
|
from cg.meta.workflow.microsalt.quality_controller.models import (
|
|
11
8
|
CaseQualityResult,
|
|
12
9
|
QualityResult,
|
|
13
10
|
SampleQualityResult,
|
|
14
11
|
)
|
|
15
|
-
from cg.meta.workflow.microsalt.quality_controller.report_generator import
|
|
16
|
-
ReportGenerator,
|
|
17
|
-
)
|
|
12
|
+
from cg.meta.workflow.microsalt.quality_controller.report_generator import ReportGenerator
|
|
18
13
|
from cg.meta.workflow.microsalt.quality_controller.result_logger import ResultLogger
|
|
19
14
|
from cg.meta.workflow.microsalt.quality_controller.utils import (
|
|
20
15
|
get_application_tag,
|
|
21
16
|
get_percent_reads_guaranteed,
|
|
22
17
|
get_report_path,
|
|
23
18
|
get_sample_target_reads,
|
|
24
|
-
has_non_microbial_apptag,
|
|
25
19
|
has_valid_10x_coverage,
|
|
26
20
|
has_valid_average_coverage,
|
|
27
21
|
has_valid_duplication_rate,
|
|
@@ -70,7 +64,7 @@ class MicroSALTQualityController:
|
|
|
70
64
|
valid_coverage: bool = has_valid_average_coverage(metrics)
|
|
71
65
|
valid_10x_coverage: bool = has_valid_10x_coverage(metrics)
|
|
72
66
|
|
|
73
|
-
sample: Sample = self.status_db.
|
|
67
|
+
sample: Sample = self.status_db.get_sample_by_internal_id_strict(sample_id)
|
|
74
68
|
application_tag: str = get_application_tag(sample)
|
|
75
69
|
|
|
76
70
|
if is_control := is_sample_negative_control(sample):
|
|
@@ -93,9 +87,6 @@ class MicroSALTQualityController:
|
|
|
93
87
|
and valid_10x_coverage
|
|
94
88
|
)
|
|
95
89
|
|
|
96
|
-
if has_non_microbial_apptag(sample):
|
|
97
|
-
sample_passes_qc = valid_read_count
|
|
98
|
-
|
|
99
90
|
sample_quality = SampleQualityResult(
|
|
100
91
|
sample_id=sample_id,
|
|
101
92
|
passes_qc=sample_passes_qc,
|
|
@@ -111,7 +102,8 @@ class MicroSALTQualityController:
|
|
|
111
102
|
ResultLogger.log_sample_result(sample_quality)
|
|
112
103
|
return sample_quality
|
|
113
104
|
|
|
114
|
-
|
|
105
|
+
@staticmethod
|
|
106
|
+
def is_qc_required(case_run_dir: Path | None) -> bool:
|
|
115
107
|
if not case_run_dir:
|
|
116
108
|
LOG.warning(f"Skipping QC, run directory {case_run_dir} does not exist.")
|
|
117
109
|
return False
|
|
@@ -122,10 +114,10 @@ class MicroSALTQualityController:
|
|
|
122
114
|
return not qc_done_path.exists()
|
|
123
115
|
|
|
124
116
|
def has_valid_total_reads(self, sample_id: str) -> bool:
|
|
125
|
-
sample: Sample = self.status_db.
|
|
117
|
+
sample: Sample = self.status_db.get_sample_by_internal_id_strict(sample_id)
|
|
126
118
|
target_reads: int = get_sample_target_reads(sample)
|
|
127
119
|
percent_reads_guaranteed: int = get_percent_reads_guaranteed(sample)
|
|
128
|
-
sample_reads: int = sample.reads
|
|
120
|
+
sample_reads: int = cast(int, sample.reads)
|
|
129
121
|
|
|
130
122
|
if is_sample_negative_control(sample):
|
|
131
123
|
return is_valid_total_reads_for_negative_control(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
|
|
3
4
|
from cg.meta.workflow.microsalt.quality_controller.models import (
|
|
4
5
|
CaseQualityResult,
|
|
5
6
|
SampleQualityResult,
|
|
@@ -43,10 +44,6 @@ def get_case_fail_message(case: CaseQualityResult) -> str:
|
|
|
43
44
|
|
|
44
45
|
if not case.control_passes_qc:
|
|
45
46
|
fail_reasons.append("The negative control sample failed QC.\n")
|
|
46
|
-
if not case.urgent_passes_qc:
|
|
47
|
-
fail_reasons.append("The urgent samples failed QC.\n")
|
|
48
|
-
if not case.non_urgent_passes_qc:
|
|
49
|
-
fail_reasons.append("The non-urgent samples failed QC.\n")
|
|
50
47
|
fail_message = "QC failed.\n"
|
|
51
48
|
return fail_message + "".join(fail_reasons)
|
|
52
49
|
|
|
@@ -62,9 +59,9 @@ def sample_result_message(samples: list[SampleQualityResult]) -> str:
|
|
|
62
59
|
return f"Sample results: {failed_count} failed, {passed_count} passed, {total_count} total."
|
|
63
60
|
|
|
64
61
|
|
|
65
|
-
def get_failed_results(samples: list[SampleQualityResult]) -> list[
|
|
62
|
+
def get_failed_results(samples: list[SampleQualityResult]) -> list[SampleQualityResult]:
|
|
66
63
|
return [result for result in samples if not result.passes_qc]
|
|
67
64
|
|
|
68
65
|
|
|
69
|
-
def get_passed_results(samples: list[SampleQualityResult]) -> list[
|
|
66
|
+
def get_passed_results(samples: list[SampleQualityResult]) -> list[SampleQualityResult]:
|
|
70
67
|
return [result for result in samples if result.passes_qc]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
-
from cg.constants.constants import
|
|
3
|
+
from cg.constants.constants import MicrosaltQC
|
|
4
4
|
from cg.meta.workflow.microsalt.constants import QUALITY_REPORT_FILE_NAME
|
|
5
5
|
from cg.meta.workflow.microsalt.metrics_parser.models import SampleMetrics
|
|
6
6
|
from cg.meta.workflow.microsalt.quality_controller.models import (
|
|
@@ -65,11 +65,6 @@ def has_valid_10x_coverage(metrics: SampleMetrics) -> bool:
|
|
|
65
65
|
return is_valid_10x_coverage(coverage_10x) if coverage_10x else False
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def has_non_microbial_apptag(sample: Sample) -> bool:
|
|
69
|
-
app_tag: str = get_application_tag(sample)
|
|
70
|
-
return app_tag not in list(MicrosaltAppTags)
|
|
71
|
-
|
|
72
|
-
|
|
73
68
|
def get_negative_control_result(results: list[SampleQualityResult]) -> SampleQualityResult | None:
|
|
74
69
|
for result in results:
|
|
75
70
|
if result.is_control:
|
|
@@ -82,38 +77,6 @@ def negative_control_pass_qc(results: list[SampleQualityResult]) -> bool:
|
|
|
82
77
|
return True
|
|
83
78
|
|
|
84
79
|
|
|
85
|
-
def get_results_passing_qc(results: list[SampleQualityResult]) -> list[SampleQualityResult]:
|
|
86
|
-
return [result for result in results if result.passes_qc]
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def get_non_urgent_results(results: list[SampleQualityResult]) -> list[SampleQualityResult]:
|
|
90
|
-
return [result for result in results if not is_urgent_result(result)]
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def get_urgent_results(results: list[SampleQualityResult]) -> list[SampleQualityResult]:
|
|
94
|
-
return [result for result in results if is_urgent_result(result)]
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def is_urgent_result(result: SampleQualityResult) -> bool:
|
|
98
|
-
return result.application_tag == MicrosaltAppTags.MWRNXTR003
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def urgent_samples_pass_qc(results: list[SampleQualityResult]) -> bool:
|
|
102
|
-
urgent_results: list[SampleQualityResult] = get_urgent_results(results)
|
|
103
|
-
return all(result.passes_qc for result in urgent_results)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def non_urgent_samples_pass_qc(results: list[SampleQualityResult]) -> bool:
|
|
107
|
-
non_urgent_samples: list[SampleQualityResult] = get_non_urgent_results(results)
|
|
108
|
-
passing_qc: list[SampleQualityResult] = get_results_passing_qc(non_urgent_samples)
|
|
109
|
-
|
|
110
|
-
if not non_urgent_samples:
|
|
111
|
-
return True
|
|
112
|
-
|
|
113
|
-
fraction_passing_qc: float = len(passing_qc) / len(non_urgent_samples)
|
|
114
|
-
return fraction_passing_qc >= MicrosaltQC.MWX_THRESHOLD_SAMPLES_PASSING
|
|
115
|
-
|
|
116
|
-
|
|
117
80
|
def is_sample_negative_control(sample: Sample) -> bool:
|
|
118
81
|
return sample.control == ControlEnum.negative
|
|
119
82
|
|
|
@@ -136,16 +99,10 @@ def get_report_path(metrics_file_path: Path) -> Path:
|
|
|
136
99
|
|
|
137
100
|
def quality_control_case(sample_results: list[SampleQualityResult]) -> CaseQualityResult:
|
|
138
101
|
control_pass_qc: bool = negative_control_pass_qc(sample_results)
|
|
139
|
-
|
|
140
|
-
non_urgent_pass_qc: bool = non_urgent_samples_pass_qc(sample_results)
|
|
141
|
-
|
|
142
|
-
case_passes_qc: bool = control_pass_qc and urgent_pass_qc and non_urgent_pass_qc
|
|
143
|
-
|
|
102
|
+
case_passes_qc: bool = all(sample.passes_qc for sample in sample_results)
|
|
144
103
|
result = CaseQualityResult(
|
|
145
104
|
passes_qc=case_passes_qc,
|
|
146
105
|
control_passes_qc=control_pass_qc,
|
|
147
|
-
urgent_passes_qc=urgent_pass_qc,
|
|
148
|
-
non_urgent_passes_qc=non_urgent_pass_qc,
|
|
149
106
|
)
|
|
150
107
|
ResultLogger.log_case_result(result)
|
|
151
108
|
return result
|
cg/meta/workflow/nallo.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Module for Nallo Analysis API."""
|
|
2
2
|
|
|
3
|
+
import copy
|
|
3
4
|
import logging
|
|
4
5
|
from itertools import permutations
|
|
5
6
|
from pathlib import Path
|
|
@@ -14,7 +15,7 @@ from cg.clients.chanjo2.models import (
|
|
|
14
15
|
CoverageSample,
|
|
15
16
|
)
|
|
16
17
|
from cg.constants import Workflow
|
|
17
|
-
from cg.constants.constants import
|
|
18
|
+
from cg.constants.constants import GenomeVersion
|
|
18
19
|
from cg.constants.nf_analysis import (
|
|
19
20
|
NALLO_COVERAGE_FILE_TAGS,
|
|
20
21
|
NALLO_COVERAGE_INTERVAL_TYPE,
|
|
@@ -23,21 +24,15 @@ from cg.constants.nf_analysis import (
|
|
|
23
24
|
NALLO_PARENT_PEDDY_METRIC_CONDITION,
|
|
24
25
|
NALLO_RAW_METRIC_CONDITIONS,
|
|
25
26
|
)
|
|
26
|
-
from cg.constants.scout import NALLO_CASE_TAGS
|
|
27
|
-
from cg.constants.subject import
|
|
28
|
-
from cg.io.controller import WriteFile
|
|
27
|
+
from cg.constants.scout import NALLO_CASE_TAGS
|
|
28
|
+
from cg.constants.subject import PlinkSex
|
|
29
29
|
from cg.meta.workflow.nf_analysis import NfAnalysisAPI
|
|
30
30
|
from cg.models.analysis import NextflowAnalysis
|
|
31
31
|
from cg.models.cg_config import CGConfig
|
|
32
32
|
from cg.models.deliverables.metric_deliverables import MetricsBase, MultiqcDataJson
|
|
33
|
-
from cg.models.nallo.nallo import
|
|
34
|
-
NalloParameters,
|
|
35
|
-
NalloQCMetrics,
|
|
36
|
-
NalloSampleSheetEntry,
|
|
37
|
-
NalloSampleSheetHeaders,
|
|
38
|
-
)
|
|
33
|
+
from cg.models.nallo.nallo import NalloQCMetrics
|
|
39
34
|
from cg.resources import NALLO_BUNDLE_FILENAMES_PATH
|
|
40
|
-
from cg.store.models import
|
|
35
|
+
from cg.store.models import Sample
|
|
41
36
|
|
|
42
37
|
LOG = logging.getLogger(__name__)
|
|
43
38
|
|
|
@@ -69,90 +64,6 @@ class NalloAnalysisAPI(NfAnalysisAPI):
|
|
|
69
64
|
self.revision: str = config.nallo.revision
|
|
70
65
|
self.nextflow_binary_path: str = config.nallo.binary_path
|
|
71
66
|
|
|
72
|
-
@property
|
|
73
|
-
def sample_sheet_headers(self) -> list[str]:
|
|
74
|
-
"""Headers for sample sheet."""
|
|
75
|
-
return NalloSampleSheetHeaders.list()
|
|
76
|
-
|
|
77
|
-
def get_sample_sheet_content_per_sample(self, case_sample: CaseSample) -> list[list[str]]:
|
|
78
|
-
"""Collect and format information required to build a sample sheet for a single sample."""
|
|
79
|
-
read_file_paths = self.get_bam_read_file_paths(sample=case_sample.sample)
|
|
80
|
-
sample_sheet_entries = []
|
|
81
|
-
|
|
82
|
-
for bam_path in read_file_paths:
|
|
83
|
-
sample_sheet_entry = NalloSampleSheetEntry(
|
|
84
|
-
project=case_sample.case.internal_id,
|
|
85
|
-
sample=case_sample.sample.internal_id,
|
|
86
|
-
read_file=Path(bam_path),
|
|
87
|
-
family_id=case_sample.case.internal_id,
|
|
88
|
-
paternal_id=case_sample.get_paternal_sample_id or "0",
|
|
89
|
-
maternal_id=case_sample.get_maternal_sample_id or "0",
|
|
90
|
-
sex=self.get_sex_code(case_sample.sample.sex),
|
|
91
|
-
phenotype=self.get_phenotype_code(case_sample.status),
|
|
92
|
-
)
|
|
93
|
-
sample_sheet_entries.extend(sample_sheet_entry.reformat_sample_content)
|
|
94
|
-
return sample_sheet_entries
|
|
95
|
-
|
|
96
|
-
@staticmethod
|
|
97
|
-
def get_phenotype_code(phenotype: str) -> int:
|
|
98
|
-
"""Return Nallo phenotype code."""
|
|
99
|
-
LOG.debug("Translate phenotype to integer code")
|
|
100
|
-
try:
|
|
101
|
-
code = PlinkPhenotypeStatus[phenotype.upper()]
|
|
102
|
-
except KeyError:
|
|
103
|
-
raise ValueError(f"{phenotype} is not a valid phenotype")
|
|
104
|
-
return code
|
|
105
|
-
|
|
106
|
-
@staticmethod
|
|
107
|
-
def get_sex_code(sex: str) -> int:
|
|
108
|
-
"""Return Nallo sex code."""
|
|
109
|
-
LOG.debug("Translate sex to integer code")
|
|
110
|
-
try:
|
|
111
|
-
code = PlinkSex[sex.upper()]
|
|
112
|
-
except KeyError:
|
|
113
|
-
raise ValueError(f"{sex} is not a valid sex")
|
|
114
|
-
return code
|
|
115
|
-
|
|
116
|
-
def get_built_workflow_parameters(self, case_id: str, dry_run: bool = False) -> NalloParameters:
|
|
117
|
-
"""Return parameters."""
|
|
118
|
-
outdir = self.get_case_path(case_id=case_id)
|
|
119
|
-
|
|
120
|
-
return NalloParameters(
|
|
121
|
-
input=self.get_sample_sheet_path(case_id=case_id),
|
|
122
|
-
outdir=outdir,
|
|
123
|
-
filter_variants_hgnc_ids=f"{outdir}/{ScoutExportFileName.PANELS_TSV}",
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
@property
|
|
127
|
-
def is_gene_panel_required(self) -> bool:
|
|
128
|
-
"""Return True if a gene panel needs to be created using information in StatusDB and exporting it from Scout."""
|
|
129
|
-
return True
|
|
130
|
-
|
|
131
|
-
def create_gene_panel(self, case_id: str, dry_run: bool) -> None:
|
|
132
|
-
"""Create and write an aggregated gene panel file exported from Scout as tsv file."""
|
|
133
|
-
LOG.info("Creating gene panel file")
|
|
134
|
-
bed_lines: list[str] = self.get_gene_panel(case_id=case_id, dry_run=dry_run)
|
|
135
|
-
if dry_run:
|
|
136
|
-
bed_lines: str = "\n".join(bed_lines)
|
|
137
|
-
LOG.debug(f"{bed_lines}")
|
|
138
|
-
return
|
|
139
|
-
self.write_panel_as_tsv(case_id=case_id, content=bed_lines)
|
|
140
|
-
|
|
141
|
-
def write_panel_as_tsv(self, case_id: str, content: list[str]) -> None:
|
|
142
|
-
"""Write the gene panel to case dir."""
|
|
143
|
-
self._write_panel_as_tsv(out_dir=Path(self.root, case_id), content=content)
|
|
144
|
-
|
|
145
|
-
@staticmethod
|
|
146
|
-
def _write_panel_as_tsv(out_dir: Path, content: list[str]) -> None:
|
|
147
|
-
"""Write the gene panel to case dir while omitted the commented BED lines."""
|
|
148
|
-
filtered_content = [line for line in content if not line.startswith("##")]
|
|
149
|
-
out_dir.mkdir(parents=True, exist_ok=True)
|
|
150
|
-
WriteFile.write_file_from_content(
|
|
151
|
-
content="\n".join(filtered_content),
|
|
152
|
-
file_format=FileFormat.TXT,
|
|
153
|
-
file_path=Path(out_dir, ScoutExportFileName.PANELS_TSV),
|
|
154
|
-
)
|
|
155
|
-
|
|
156
67
|
def get_genome_build(self, case_id: str) -> GenomeVersion:
|
|
157
68
|
"""Return reference genome for a Nallo case. Currently fixed for hg38."""
|
|
158
69
|
return GenomeVersion.HG38
|
|
@@ -168,7 +79,6 @@ class NalloAnalysisAPI(NfAnalysisAPI):
|
|
|
168
79
|
if "-" not in sample_id:
|
|
169
80
|
metric_conditions: dict[str, dict[str, Any]] = NALLO_GENERAL_METRIC_CONDITIONS.copy()
|
|
170
81
|
metric_conditions.update(NALLO_RAW_METRIC_CONDITIONS)
|
|
171
|
-
self.set_peddy_sex_for_sample(sample=sample, metric_conditions=metric_conditions)
|
|
172
82
|
self.set_somalier_sex_for_sample(sample=sample, metric_conditions=metric_conditions)
|
|
173
83
|
else:
|
|
174
84
|
metric_conditions = NALLO_PARENT_PEDDY_METRIC_CONDITION.copy()
|
|
@@ -235,9 +145,21 @@ class NalloAnalysisAPI(NfAnalysisAPI):
|
|
|
235
145
|
metrics = self.get_deduplicated_metrics(metrics=metrics)
|
|
236
146
|
return metrics
|
|
237
147
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
148
|
+
def _get_list_of_metric_dicts(self, multiqc_json: MultiqcDataJson) -> list[dict[str, Any]]:
|
|
149
|
+
metric_dicts: list[dict[str, Any]] = super()._get_list_of_metric_dicts(multiqc_json)
|
|
150
|
+
|
|
151
|
+
list_copy: list[dict[str, Any]] = copy.deepcopy(metric_dicts)
|
|
152
|
+
list_copy.append(self._get_somalier_dict(multiqc_json))
|
|
153
|
+
|
|
154
|
+
return list_copy
|
|
155
|
+
|
|
156
|
+
def _get_somalier_dict(self, multiqc_json: MultiqcDataJson) -> dict[str, Any]:
|
|
157
|
+
somalier_raw = copy.deepcopy(multiqc_json.report_saved_raw_data["multiqc_somalier"])
|
|
158
|
+
|
|
159
|
+
for sample_id, metrics in somalier_raw.items():
|
|
160
|
+
somalier_raw[sample_id] = {f"somalier_{k}": v for k, v in metrics.items()}
|
|
161
|
+
|
|
162
|
+
return somalier_raw
|
|
241
163
|
|
|
242
164
|
@staticmethod
|
|
243
165
|
def set_somalier_sex_for_sample(sample: Sample, metric_conditions: dict) -> None:
|