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.
Files changed (152) hide show
  1. cg/__init__.py +1 -1
  2. cg/apps/housekeeper/hk.py +18 -1
  3. cg/apps/tb/api.py +42 -5
  4. cg/cli/transfer.py +13 -2
  5. cg/cli/upload/mutacc.py +16 -3
  6. cg/cli/upload/scout.py +2 -2
  7. cg/cli/upload/utils.py +10 -1
  8. cg/cli/workflow/balsamic/base.py +86 -172
  9. cg/cli/workflow/balsamic/options.py +3 -48
  10. cg/cli/workflow/balsamic/umi.py +210 -15
  11. cg/cli/workflow/microsalt/base.py +4 -2
  12. cg/cli/workflow/mip_dna/base.py +1 -1
  13. cg/cli/workflow/nallo/base.py +73 -23
  14. cg/cli/workflow/nf_analysis.py +5 -207
  15. cg/cli/workflow/raredisease/base.py +41 -54
  16. cg/cli/workflow/rnafusion/base.py +38 -8
  17. cg/cli/workflow/taxprofiler/base.py +31 -18
  18. cg/cli/workflow/tomte/base.py +83 -10
  19. cg/constants/constants.py +25 -30
  20. cg/constants/devices.py +6 -1
  21. cg/constants/gene_panel.py +3 -1
  22. cg/constants/housekeeper_tags.py +28 -28
  23. cg/constants/lims.py +4 -0
  24. cg/constants/nf_analysis.py +0 -1
  25. cg/constants/observations.py +21 -5
  26. cg/constants/orderforms.py +3 -3
  27. cg/constants/pacbio.py +1 -0
  28. cg/constants/priority.py +1 -1
  29. cg/constants/report.py +1 -0
  30. cg/constants/scout.py +12 -9
  31. cg/constants/sequencing.py +2 -2
  32. cg/constants/tb.py +5 -5
  33. cg/exc.py +27 -5
  34. cg/meta/compress/compress.py +7 -2
  35. cg/meta/delivery_report/balsamic.py +3 -1
  36. cg/meta/delivery_report/delivery_report_api.py +4 -3
  37. cg/meta/delivery_report/nallo.py +11 -11
  38. cg/meta/delivery_report/raredisease.py +7 -3
  39. cg/meta/delivery_report/templates/macros/data_analysis/qc_metrics/balsamic_qc_metrics.html +1 -0
  40. cg/meta/delivery_report/templates/macros/ticket_system.html +1 -1
  41. cg/meta/observations/balsamic_observations_api.py +110 -14
  42. cg/meta/observations/mip_dna_observations_api.py +1 -1
  43. cg/meta/observations/nallo_observations_api.py +1 -1
  44. cg/meta/observations/observations_api.py +23 -32
  45. cg/meta/observations/raredisease_observations_api.py +1 -1
  46. cg/meta/tar/tar.py +5 -2
  47. cg/meta/transfer/lims.py +32 -3
  48. cg/meta/upload/balsamic/balsamic.py +1 -8
  49. cg/meta/upload/coverage.py +5 -5
  50. cg/meta/upload/raredisease/raredisease.py +3 -0
  51. cg/meta/upload/scout/hk_tags.py +1 -0
  52. cg/meta/upload/scout/nallo_config_builder.py +31 -7
  53. cg/meta/workflow/balsamic.py +70 -36
  54. cg/meta/workflow/fastq.py +8 -0
  55. cg/meta/workflow/microsalt/quality_controller/models.py +0 -2
  56. cg/meta/workflow/microsalt/quality_controller/quality_controller.py +8 -16
  57. cg/meta/workflow/microsalt/quality_controller/result_logger.py +3 -6
  58. cg/meta/workflow/microsalt/quality_controller/utils.py +2 -45
  59. cg/meta/workflow/nallo.py +21 -99
  60. cg/meta/workflow/nf_analysis.py +12 -263
  61. cg/meta/workflow/raredisease.py +3 -112
  62. cg/meta/workflow/rnafusion.py +2 -34
  63. cg/meta/workflow/taxprofiler.py +2 -38
  64. cg/meta/workflow/tomte.py +2 -42
  65. cg/models/balsamic/config.py +0 -24
  66. cg/models/balsamic/metrics.py +5 -3
  67. cg/models/cg_config.py +39 -16
  68. cg/models/deliverables/metric_deliverables.py +1 -1
  69. cg/models/delivery_report/metadata.py +2 -1
  70. cg/models/nallo/nallo.py +14 -64
  71. cg/models/nf_analysis.py +1 -41
  72. cg/models/raredisease/raredisease.py +1 -63
  73. cg/models/rnafusion/rnafusion.py +0 -26
  74. cg/models/scout/scout_load_config.py +5 -2
  75. cg/models/taxprofiler/taxprofiler.py +0 -42
  76. cg/models/tomte/tomte.py +0 -69
  77. cg/resources/nallo_bundle_filenames.yaml +292 -22
  78. cg/resources/raredisease_bundle_filenames.yaml +11 -1
  79. cg/resources/taxprofiler_bundle_filenames.yaml +20 -0
  80. cg/server/admin.py +106 -25
  81. cg/server/app.py +15 -4
  82. cg/server/endpoints/sequencing_run/dtos.py +21 -3
  83. cg/server/endpoints/sequencing_run/pacbio_sequencing_run.py +29 -10
  84. cg/server/endpoints/sequencing_run/pacbio_smrt_cell_metrics.py +20 -0
  85. cg/services/analysis_starter/{service.py → analysis_starter.py} +11 -9
  86. cg/services/analysis_starter/configurator/abstract_model.py +8 -0
  87. cg/services/analysis_starter/configurator/configurator.py +1 -1
  88. cg/services/analysis_starter/configurator/extensions/nallo.py +27 -0
  89. cg/services/analysis_starter/configurator/extensions/{abstract.py → pipeline_extension.py} +1 -1
  90. cg/services/analysis_starter/configurator/extensions/raredisease.py +3 -1
  91. cg/services/analysis_starter/configurator/extensions/tomte_extension.py +28 -0
  92. cg/services/analysis_starter/configurator/file_creators/balsamic_config.py +240 -0
  93. cg/services/analysis_starter/configurator/file_creators/gene_panel.py +10 -5
  94. cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/abstract.py +2 -1
  95. cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/models.py +40 -1
  96. cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/nallo.py +37 -0
  97. cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/raredisease.py +8 -5
  98. cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/tomte_params_file_creator.py +64 -0
  99. cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/creator.py +1 -1
  100. cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/nallo_sample_sheet_creator.py +65 -0
  101. cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/protocol.py +12 -0
  102. cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{raredisease.py → raredisease_sample_sheet_creator.py} +2 -2
  103. cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{rnafusion.py → rnafusion_sample_sheet_creator.py} +2 -2
  104. cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{taxprofiler.py → taxprofiler_sample_sheet_creator.py} +2 -2
  105. cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/tomte_sample_sheet_creator.py +36 -0
  106. cg/services/analysis_starter/configurator/implementations/balsamic.py +68 -0
  107. cg/services/analysis_starter/configurator/implementations/nextflow.py +22 -5
  108. cg/services/analysis_starter/configurator/models/balsamic.py +152 -0
  109. cg/services/analysis_starter/configurator/models/mip_dna.py +6 -8
  110. cg/services/analysis_starter/configurator/models/nextflow.py +9 -0
  111. cg/services/analysis_starter/constants.py +2 -0
  112. cg/services/analysis_starter/factories/configurator_factory.py +131 -51
  113. cg/services/analysis_starter/factories/starter_factory.py +36 -7
  114. cg/services/analysis_starter/input_fetcher/implementations/bam_fetcher.py +57 -0
  115. cg/services/analysis_starter/input_fetcher/implementations/fastq_fetcher.py +3 -3
  116. cg/services/analysis_starter/submitters/seqera_platform/{client.py → seqera_platform_client.py} +19 -3
  117. cg/services/analysis_starter/submitters/seqera_platform/seqera_platform_submitter.py +73 -0
  118. cg/services/analysis_starter/submitters/submitter.py +1 -1
  119. cg/services/analysis_starter/submitters/subprocess/submitter.py +2 -1
  120. cg/services/analysis_starter/tracker/implementations/balsamic.py +22 -0
  121. cg/services/analysis_starter/tracker/implementations/microsalt.py +4 -4
  122. cg/services/analysis_starter/tracker/implementations/mip_dna.py +4 -1
  123. cg/services/analysis_starter/tracker/implementations/{nextflow.py → nextflow_tracker.py} +6 -4
  124. cg/services/analysis_starter/tracker/tracker.py +19 -15
  125. cg/services/deliver_files/factory.py +1 -1
  126. cg/services/delivery_message/messages/__init__.py +24 -14
  127. cg/services/delivery_message/messages/{microsalt_mwr_message.py → microsalt_message.py} +1 -1
  128. cg/services/delivery_message/utils.py +4 -40
  129. cg/services/illumina/backup/backup_service.py +29 -7
  130. cg/services/orders/validation/constants.py +3 -0
  131. cg/services/orders/validation/index_sequences.py +558 -0
  132. cg/services/orders/validation/order_types/microsalt/models/sample.py +2 -3
  133. cg/services/run_devices/pacbio/data_storage_service/pacbio_store_service.py +39 -18
  134. cg/services/run_devices/pacbio/data_transfer_service/data_transfer_service.py +8 -2
  135. cg/services/run_devices/pacbio/data_transfer_service/dto.py +9 -3
  136. cg/services/run_devices/pacbio/data_transfer_service/utils.py +14 -7
  137. cg/services/run_devices/pacbio/metrics_parser/models.py +1 -0
  138. cg/services/run_devices/pacbio/sequencing_runs_service.py +35 -7
  139. cg/services/sequencing_qc_service/quality_checks/checks.py +18 -16
  140. cg/services/sequencing_qc_service/quality_checks/utils.py +82 -18
  141. cg/services/sequencing_qc_service/sequencing_qc_service.py +12 -10
  142. cg/store/crud/create.py +73 -42
  143. cg/store/crud/read.py +73 -7
  144. cg/store/crud/update.py +14 -3
  145. cg/store/models.py +98 -35
  146. cg/store/store.py +8 -1
  147. {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/METADATA +1 -1
  148. {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/RECORD +150 -138
  149. cg/services/analysis_starter/submitters/seqera_platform/submitter.py +0 -39
  150. cg/services/delivery_message/messages/microsalt_mwx_message.py +0 -18
  151. {cg-76.0.0.dist-info → cg-83.14.0.dist-info}/WHEEL +0 -0
  152. {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.get_sample_by_internal_id(sample_id)
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
- def is_qc_required(self, case_run_dir: Path) -> bool:
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.get_sample_by_internal_id(sample_id)
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[str]:
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[str]:
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 MicrosaltAppTags, MicrosaltQC
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
- urgent_pass_qc: bool = urgent_samples_pass_qc(sample_results)
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 FileFormat, GenomeVersion
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, ScoutExportFileName
27
- from cg.constants.subject import PlinkPhenotypeStatus, PlinkSex
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 CaseSample, Sample
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
- @staticmethod
239
- def set_peddy_sex_for_sample(sample: Sample, metric_conditions: dict) -> None:
240
- metric_conditions["predicted_sex_sex_check"]["threshold"] = sample.sex
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: