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
@@ -0,0 +1,68 @@
1
+ import logging
2
+ from pathlib import Path
3
+ from typing import cast
4
+
5
+ from cg.constants.priority import SlurmQos
6
+ from cg.exc import CaseNotConfiguredError
7
+ from cg.meta.workflow.fastq import BalsamicFastqHandler
8
+ from cg.models.cg_config import BalsamicConfig
9
+ from cg.services.analysis_starter.configurator.configurator import Configurator
10
+ from cg.services.analysis_starter.configurator.file_creators.balsamic_config import (
11
+ BalsamicConfigFileCreator,
12
+ )
13
+ from cg.services.analysis_starter.configurator.models.balsamic import BalsamicCaseConfig
14
+ from cg.store.store import Store
15
+
16
+ LOG = logging.getLogger(__name__)
17
+
18
+
19
+ class BalsamicConfigurator(Configurator):
20
+ def __init__(
21
+ self,
22
+ config: BalsamicConfig,
23
+ config_file_creator: BalsamicConfigFileCreator,
24
+ fastq_handler: BalsamicFastqHandler,
25
+ store: Store,
26
+ ):
27
+ self.store: Store = store
28
+
29
+ self.balsamic_binary: Path = config.binary_path
30
+ self.conda_binary: Path = config.conda_binary
31
+ self.environment: str = config.conda_env
32
+ self.head_job_partition: str = config.head_job_partition
33
+ self.root_dir: Path = config.root
34
+ self.slurm_account: str = config.slurm.account
35
+
36
+ self.fastq_handler: BalsamicFastqHandler = fastq_handler
37
+ self.config_file_creator: BalsamicConfigFileCreator = config_file_creator
38
+
39
+ def configure(self, case_id: str, **flags) -> BalsamicCaseConfig:
40
+ LOG.info(f"Configuring case {case_id}")
41
+ self.fastq_handler.link_fastq_files(case_id)
42
+ fastq_path: Path = self.fastq_handler.get_fastq_dir(case_id)
43
+ self.config_file_creator.create(case_id=case_id, fastq_path=fastq_path, **flags)
44
+ return self.get_config(case_id=case_id, **flags)
45
+
46
+ def get_config(self, case_id: str, **flags) -> BalsamicCaseConfig:
47
+ balsamic_config: BalsamicCaseConfig = BalsamicCaseConfig(
48
+ account=self.slurm_account,
49
+ binary=self.balsamic_binary,
50
+ case_id=case_id,
51
+ conda_binary=self.conda_binary,
52
+ environment=self.environment,
53
+ head_job_partition=self.head_job_partition,
54
+ qos=cast(SlurmQos, self.store.get_case_by_internal_id_strict(case_id).slurm_priority),
55
+ sample_config=self._get_sample_config_path(case_id),
56
+ )
57
+ balsamic_config: BalsamicCaseConfig = self._set_flags(config=balsamic_config, **flags)
58
+ self._ensure_required_config_files_exist(balsamic_config)
59
+ return balsamic_config
60
+
61
+ def _get_sample_config_path(self, case_id: str) -> Path:
62
+ return Path(self.root_dir, case_id, f"{case_id}.json")
63
+
64
+ def _ensure_required_config_files_exist(self, config: BalsamicCaseConfig) -> None:
65
+ if not config.sample_config.exists():
66
+ raise CaseNotConfiguredError(
67
+ f"Please ensure that the config file {config.sample_config} exists."
68
+ )
@@ -1,19 +1,22 @@
1
1
  from pathlib import Path
2
2
 
3
- from cg.exc import MissingConfigFilesError
3
+ from cg.exc import AnalysisAlreadyCompletedError, MissingConfigFilesError
4
4
  from cg.models.cg_config import CommonAppConfig
5
5
  from cg.services.analysis_starter.configurator.configurator import Configurator
6
- from cg.services.analysis_starter.configurator.extensions.abstract import PipelineExtension
6
+ from cg.services.analysis_starter.configurator.extensions.pipeline_extension import (
7
+ PipelineExtension,
8
+ )
7
9
  from cg.services.analysis_starter.configurator.file_creators.nextflow.config_file import (
8
10
  NextflowConfigFileCreator,
9
11
  )
10
12
  from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.abstract import (
11
13
  ParamsFileCreator,
12
14
  )
13
- from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.creator import (
14
- NextflowSampleSheetCreator,
15
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.protocol import (
16
+ SampleSheetCreator,
15
17
  )
16
18
  from cg.services.analysis_starter.configurator.models.nextflow import NextflowCaseConfig
19
+ from cg.store.models import Analysis
17
20
  from cg.store.store import Store
18
21
 
19
22
 
@@ -23,7 +26,7 @@ class NextflowConfigurator(Configurator):
23
26
  config_file_creator: NextflowConfigFileCreator,
24
27
  params_file_creator: ParamsFileCreator,
25
28
  pipeline_config: CommonAppConfig,
26
- sample_sheet_creator: NextflowSampleSheetCreator,
29
+ sample_sheet_creator: SampleSheetCreator,
27
30
  store: Store,
28
31
  pipeline_extension: PipelineExtension = PipelineExtension(),
29
32
  ):
@@ -82,9 +85,23 @@ class NextflowConfigurator(Configurator):
82
85
  workflow=self.store.get_case_workflow(case_id),
83
86
  )
84
87
  config: NextflowCaseConfig = self._set_flags(config=config, **flags)
88
+ config = self._set_session_id(config)
85
89
  self._ensure_required_config_files_exist(config)
86
90
  return config
87
91
 
92
+ def _set_session_id(self, config: NextflowCaseConfig) -> NextflowCaseConfig:
93
+ new_config: NextflowCaseConfig = config.model_copy()
94
+ if config.resume:
95
+ analysis: Analysis = self.store.get_latest_started_analysis_for_case(
96
+ case_id=new_config.case_id
97
+ )
98
+ if analysis.completed_at:
99
+ raise AnalysisAlreadyCompletedError(
100
+ "Resume not possible for an already completed analysis"
101
+ )
102
+ new_config.session_id = analysis.session_id
103
+ return new_config
104
+
88
105
  def _get_config_file_path(self, case_id: str) -> Path:
89
106
  """Return the path to the Nextflow config file."""
90
107
  return Path(self._get_case_run_directory(case_id), f"{case_id}_nextflow_config.json")
@@ -0,0 +1,152 @@
1
+ from abc import abstractmethod
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ from pydantic import BaseModel
6
+
7
+ from cg.constants import SexOptions, Workflow
8
+ from cg.constants.constants import GenomeVersion
9
+ from cg.constants.priority import SlurmQos
10
+ from cg.services.analysis_starter.configurator.abstract_model import CaseConfig
11
+
12
+
13
+ class BalsamicConfigInput(BaseModel):
14
+ analysis_dir: Path
15
+ analysis_workflow: Workflow
16
+ artefact_snv_observations: Path
17
+ balsamic_binary: Path
18
+ balsamic_cache: Path
19
+ cadd_annotations: Path
20
+ cancer_germline_snv_observations: Path
21
+ cancer_somatic_snv_observations: Path
22
+ cancer_somatic_sv_observations: Path
23
+ case_id: str
24
+ clinical_snv_observations: Path
25
+ clinical_sv_observations: Path
26
+ conda_binary: Path
27
+ conda_env: str
28
+ fastq_path: Path
29
+ gender: SexOptions
30
+ genome_version: GenomeVersion
31
+ gnomad_min_af5: Path
32
+ normal_sample_name: str | None = None
33
+ sentieon_install_dir: Path
34
+ sentieon_license: str
35
+ swegen_snv: Path
36
+ swegen_sv: Path
37
+ tumor_sample_name: str
38
+
39
+ def dump_to_cli(self) -> str:
40
+ """Dump the Balsamic case config to a CLI command. None flags are excluded and boolean flags are converted to
41
+ only add the flag."""
42
+ command = (
43
+ f"{self.conda_binary} run --name {self.conda_env} {self.balsamic_binary} config case"
44
+ )
45
+
46
+ for flag, value in self._get_flags().items():
47
+ if isinstance(value, bool):
48
+ if value is True:
49
+ command += f" {flag}"
50
+ elif value is not None:
51
+ command += f" {flag} {value}"
52
+ return command
53
+
54
+ @abstractmethod
55
+ def _get_flags(self) -> dict[str, Any]:
56
+ pass
57
+
58
+
59
+ class BalsamicConfigInputPanel(BalsamicConfigInput):
60
+ cancer_somatic_snv_panel_observations: Path | None = None
61
+ exome: bool
62
+ panel_bed: Path
63
+ pon_cnn: Path | None = (
64
+ None # Equivalent to --gens-coverage-pon in wgs analysis, depends on the panel
65
+ )
66
+ soft_filter_normal: bool = False # True for all panel analyses with a normal sample
67
+
68
+ def _get_flags(self) -> dict[str, Any]:
69
+ return {
70
+ "--analysis-dir": self.analysis_dir,
71
+ "--analysis-workflow": self.analysis_workflow,
72
+ "--artefact-snv-observations": self.artefact_snv_observations,
73
+ "--balsamic-cache": self.balsamic_cache,
74
+ "--cadd-annotations": self.cadd_annotations,
75
+ "--cancer-germline-snv-observations": self.cancer_germline_snv_observations,
76
+ "--cancer-somatic-snv-observations": self.cancer_somatic_snv_observations,
77
+ "--cancer-somatic-snv-panel-observations": self.cancer_somatic_snv_panel_observations,
78
+ "--cancer-somatic-sv-observations": self.cancer_somatic_sv_observations,
79
+ "--case-id": self.case_id,
80
+ "--clinical-snv-observations": self.clinical_snv_observations,
81
+ "--clinical-sv-observations": self.clinical_sv_observations,
82
+ "--fastq-path": self.fastq_path,
83
+ "--gender": self.gender,
84
+ "--genome-version": self.genome_version,
85
+ "--gnomad-min-af5": self.gnomad_min_af5,
86
+ "--normal-sample-name": self.normal_sample_name,
87
+ "--panel-bed": self.panel_bed,
88
+ "--exome": self.exome, # MUST be after panel bed
89
+ "--pon-cnn": self.pon_cnn,
90
+ "--sentieon-install-dir": self.sentieon_install_dir,
91
+ "--sentieon-license": self.sentieon_license,
92
+ "--soft-filter-normal": self.soft_filter_normal,
93
+ "--swegen-snv": self.swegen_snv,
94
+ "--swegen-sv": self.swegen_sv,
95
+ "--tumor-sample-name": self.tumor_sample_name,
96
+ }
97
+
98
+
99
+ class BalsamicConfigInputWGS(BalsamicConfigInput):
100
+ artefact_sv_observations: Path
101
+ genome_interval: Path
102
+ gens_coverage_pon: Path # Equivalent to --pon-cnn in panel analysis, depends on the sex
103
+
104
+ def _get_flags(self) -> dict[str, Any]:
105
+ return {
106
+ "--analysis-dir": self.analysis_dir,
107
+ "--analysis-workflow": self.analysis_workflow,
108
+ "--artefact-snv-observations": self.artefact_snv_observations,
109
+ "--artefact-sv-observations": self.artefact_sv_observations,
110
+ "--balsamic-cache": self.balsamic_cache,
111
+ "--cadd-annotations": self.cadd_annotations,
112
+ "--cancer-germline-snv-observations": self.cancer_germline_snv_observations,
113
+ "--cancer-somatic-snv-observations": self.cancer_somatic_snv_observations,
114
+ "--cancer-somatic-sv-observations": self.cancer_somatic_sv_observations,
115
+ "--case-id": self.case_id,
116
+ "--clinical-snv-observations": self.clinical_snv_observations,
117
+ "--clinical-sv-observations": self.clinical_sv_observations,
118
+ "--fastq-path": self.fastq_path,
119
+ "--gender": self.gender,
120
+ "--genome-interval": self.genome_interval,
121
+ "--genome-version": self.genome_version,
122
+ "--gens-coverage-pon": self.gens_coverage_pon,
123
+ "--gnomad-min-af5": self.gnomad_min_af5,
124
+ "--normal-sample-name": self.normal_sample_name,
125
+ "--sentieon-install-dir": self.sentieon_install_dir,
126
+ "--sentieon-license": self.sentieon_license,
127
+ "--swegen-snv": self.swegen_snv,
128
+ "--swegen-sv": self.swegen_sv,
129
+ "--tumor-sample-name": self.tumor_sample_name,
130
+ }
131
+
132
+
133
+ class BalsamicCaseConfig(CaseConfig):
134
+ account: str
135
+ binary: Path
136
+ conda_binary: Path
137
+ environment: str
138
+ head_job_partition: str
139
+ qos: SlurmQos
140
+ sample_config: Path
141
+ workflow: Workflow = Workflow.BALSAMIC
142
+ workflow_profile: Path | None = None
143
+
144
+ def get_start_command(self) -> str:
145
+ command = (
146
+ "{conda_binary} run --name {environment} {binary} run analysis --account {account} "
147
+ "--qos {qos} --sample-config {sample_config} --headjob-partition {head_job_partition} "
148
+ "--run-analysis".format(**self.model_dump())
149
+ )
150
+ if self.workflow_profile:
151
+ command += f" --workflow-profile {self.workflow_profile}"
152
+ return command
@@ -1,5 +1,3 @@
1
- from pydantic import Field
2
-
3
1
  from cg.constants.constants import Workflow
4
2
  from cg.constants.priority import SlurmQos
5
3
  from cg.services.analysis_starter.configurator.abstract_model import CaseConfig
@@ -13,8 +11,8 @@ class MIPDNACaseConfig(CaseConfig):
13
11
  pipeline_command: str
14
12
  pipeline_config_path: str
15
13
  slurm_qos: SlurmQos
16
- start_after_recipe: str | None = Field(default=None, alias="start_after")
17
- start_with_recipe: str | None = Field(default=None, alias="start_with")
14
+ start_after: str | None = None
15
+ start_with: str | None = None
18
16
  workflow: Workflow = Workflow.MIP_DNA
19
17
  use_bwa_mem: bool
20
18
 
@@ -25,11 +23,11 @@ class MIPDNACaseConfig(CaseConfig):
25
23
  "{slurm_qos} --email {email}"
26
24
  ).format(**self.model_dump())
27
25
 
28
- if self.start_after_recipe:
29
- start_command += f" --start_after_recipe {self.start_after_recipe}"
26
+ if self.start_after:
27
+ start_command += f" --start_after_recipe {self.start_after}"
30
28
 
31
- if self.start_with_recipe:
32
- start_command += f" --start_with_recipe {self.start_with_recipe}"
29
+ if self.start_with:
30
+ start_command += f" --start_with_recipe {self.start_with}"
33
31
 
34
32
  if self.use_bwa_mem:
35
33
  start_command += " --bwa_mem 1 --bwa_mem2 0"
@@ -9,5 +9,14 @@ class NextflowCaseConfig(CaseConfig):
9
9
  params_file: str
10
10
  pipeline_repository: str
11
11
  pre_run_script: str
12
+ resume: bool = False
12
13
  revision: str
14
+ session_id: str | None = None
13
15
  work_dir: str
16
+ workflow_id: str | None = None
17
+
18
+ def get_session_id(self) -> str | None:
19
+ return self.session_id
20
+
21
+ def get_workflow_id(self) -> str | None:
22
+ return self.workflow_id
@@ -1,11 +1,13 @@
1
1
  from cg.constants import Workflow
2
2
 
3
3
  IMPLEMENTED_FASTQ_WORKFLOWS = [
4
+ Workflow.BALSAMIC,
4
5
  Workflow.MICROSALT,
5
6
  Workflow.MIP_DNA,
6
7
  Workflow.RAREDISEASE,
7
8
  Workflow.RNAFUSION,
8
9
  Workflow.TAXPROFILER,
10
+ Workflow.TOMTE,
9
11
  ]
10
12
 
11
13
  BAM_WORKFLOWS = [Workflow.NALLO]
@@ -4,11 +4,18 @@ from cg.apps.housekeeper.hk import HousekeeperAPI
4
4
  from cg.apps.lims import LimsAPI
5
5
  from cg.apps.scout.scoutapi import ScoutAPI
6
6
  from cg.constants import Workflow
7
- from cg.meta.workflow.fastq import MicrosaltFastqHandler, MipFastqHandler
7
+ from cg.meta.workflow.fastq import BalsamicFastqHandler, MicrosaltFastqHandler, MipFastqHandler
8
8
  from cg.models.cg_config import CGConfig, CommonAppConfig
9
9
  from cg.services.analysis_starter.configurator.configurator import Configurator
10
- from cg.services.analysis_starter.configurator.extensions.abstract import PipelineExtension
10
+ from cg.services.analysis_starter.configurator.extensions.nallo import NalloExtension
11
+ from cg.services.analysis_starter.configurator.extensions.pipeline_extension import (
12
+ PipelineExtension,
13
+ )
11
14
  from cg.services.analysis_starter.configurator.extensions.raredisease import RarediseaseExtension
15
+ from cg.services.analysis_starter.configurator.extensions.tomte_extension import TomteExtension
16
+ from cg.services.analysis_starter.configurator.file_creators.balsamic_config import (
17
+ BalsamicConfigFileCreator,
18
+ )
12
19
  from cg.services.analysis_starter.configurator.file_creators.gene_panel import GenePanelFileCreator
13
20
  from cg.services.analysis_starter.configurator.file_creators.managed_variants import (
14
21
  ManagedVariantsFileCreator,
@@ -25,6 +32,9 @@ from cg.services.analysis_starter.configurator.file_creators.nextflow.config_fil
25
32
  from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.abstract import (
26
33
  ParamsFileCreator,
27
34
  )
35
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.nallo import (
36
+ NalloParamsFileCreator,
37
+ )
28
38
  from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.raredisease import (
29
39
  RarediseaseParamsFileCreator,
30
40
  )
@@ -34,18 +44,28 @@ from cg.services.analysis_starter.configurator.file_creators.nextflow.params_fil
34
44
  from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.taxprofiler import (
35
45
  TaxprofilerParamsFileCreator,
36
46
  )
37
- from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.creator import (
38
- NextflowSampleSheetCreator,
47
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.tomte_params_file_creator import (
48
+ TomteParamsFileCreator,
49
+ )
50
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.nallo_sample_sheet_creator import (
51
+ NalloSampleSheetCreator,
39
52
  )
40
- from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.raredisease import (
53
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.protocol import (
54
+ SampleSheetCreator,
55
+ )
56
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.raredisease_sample_sheet_creator import (
41
57
  RarediseaseSampleSheetCreator,
42
58
  )
43
- from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.rnafusion import (
59
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.rnafusion_sample_sheet_creator import (
44
60
  RNAFusionSampleSheetCreator,
45
61
  )
46
- from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.taxprofiler import (
62
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.taxprofiler_sample_sheet_creator import (
47
63
  TaxprofilerSampleSheetCreator,
48
64
  )
65
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.tomte_sample_sheet_creator import (
66
+ TomteSampleSheetCreator,
67
+ )
68
+ from cg.services.analysis_starter.configurator.implementations.balsamic import BalsamicConfigurator
49
69
  from cg.services.analysis_starter.configurator.implementations.microsalt import (
50
70
  MicrosaltConfigurator,
51
71
  )
@@ -63,18 +83,30 @@ class ConfiguratorFactory:
63
83
  self.store: Store = cg_config.status_db
64
84
 
65
85
  def get_configurator(self, workflow: Workflow) -> Configurator:
66
- if workflow in [Workflow.RAREDISEASE, Workflow.RNAFUSION, Workflow.TAXPROFILER]:
67
- return self._get_nextflow_configurator(workflow)
68
- elif workflow == Workflow.MICROSALT:
69
- return self._get_microsalt_configurator()
70
- elif workflow == Workflow.MIP_DNA:
71
- return self._get_mip_dna_configurator()
72
- raise NotImplementedError
86
+ match workflow:
87
+ case Workflow.BALSAMIC | Workflow.BALSAMIC_UMI:
88
+ return self._get_balsamic_configurator()
89
+ case Workflow.MICROSALT:
90
+ return self._get_microsalt_configurator()
91
+ case Workflow.MIP_DNA:
92
+ return self._get_mip_dna_configurator()
93
+ case (
94
+ Workflow.NALLO
95
+ | Workflow.RAREDISEASE
96
+ | Workflow.RNAFUSION
97
+ | Workflow.TAXPROFILER
98
+ | Workflow.TOMTE
99
+ ):
100
+ return self._get_nextflow_configurator(workflow)
101
+ case _:
102
+ raise NotImplementedError
73
103
 
74
104
  def _get_nextflow_configurator(self, workflow: Workflow) -> NextflowConfigurator:
75
- config_file_creator = self._get_nextflow_config_file_creator(workflow)
105
+ config_file_creator: NextflowConfigFileCreator = self._get_nextflow_config_file_creator(
106
+ workflow
107
+ )
76
108
  params_file_creator: ParamsFileCreator = self._get_params_file_creator(workflow)
77
- sample_sheet_creator: NextflowSampleSheetCreator = self._get_sample_sheet_creator(workflow)
109
+ sample_sheet_creator: SampleSheetCreator = self._get_sample_sheet_creator(workflow)
78
110
  extension: PipelineExtension = self._get_pipeline_extension(workflow)
79
111
  return NextflowConfigurator(
80
112
  config_file_creator=config_file_creator,
@@ -96,47 +128,79 @@ class ConfiguratorFactory:
96
128
  )
97
129
 
98
130
  def _get_params_file_creator(self, workflow: Workflow) -> ParamsFileCreator:
99
- if workflow == Workflow.RAREDISEASE:
100
- pipeline_config: CommonAppConfig = self._get_pipeline_config(workflow)
101
- return RarediseaseParamsFileCreator(
102
- lims=self.lims_api, store=self.store, params=pipeline_config.params
103
- )
104
- elif workflow == Workflow.RNAFUSION:
105
- pipeline_config: CommonAppConfig = self._get_pipeline_config(workflow)
106
- return RNAFusionParamsFileCreator(pipeline_config.params)
107
- elif workflow == Workflow.TAXPROFILER:
108
- pipeline_config: CommonAppConfig = self._get_pipeline_config(workflow)
109
- return TaxprofilerParamsFileCreator(pipeline_config.params)
131
+ params: str = self._get_pipeline_config(workflow).params
132
+ match workflow:
133
+ case Workflow.NALLO:
134
+ return NalloParamsFileCreator(params)
135
+ case Workflow.RAREDISEASE:
136
+ return RarediseaseParamsFileCreator(
137
+ lims=self.lims_api, params=params, store=self.store
138
+ )
139
+ case Workflow.RNAFUSION:
140
+ return RNAFusionParamsFileCreator(params)
141
+ case Workflow.TAXPROFILER:
142
+ return TaxprofilerParamsFileCreator(params)
143
+ case Workflow.TOMTE:
144
+ return TomteParamsFileCreator(
145
+ lims_api=self.lims_api, params=params, status_db=self.store
146
+ )
147
+ case _:
148
+ raise NotImplementedError(f"There is no params file creator for {workflow}")
110
149
 
111
150
  def _get_pipeline_config(self, workflow: Workflow) -> CommonAppConfig:
112
151
  return getattr(self.cg_config, workflow)
113
152
 
114
- def _get_sample_sheet_creator(self, workflow: Workflow) -> NextflowSampleSheetCreator:
115
- if workflow == Workflow.RAREDISEASE:
116
- return RarediseaseSampleSheetCreator(
117
- housekeeper_api=self.cg_config.housekeeper_api,
118
- store=self.store,
119
- )
120
- elif workflow == Workflow.RNAFUSION:
121
- return RNAFusionSampleSheetCreator(
122
- housekeeper_api=self.housekeeper_api, store=self.store
123
- )
124
- elif workflow == Workflow.TAXPROFILER:
125
- return TaxprofilerSampleSheetCreator(
126
- housekeeper_api=self.housekeeper_api, store=self.store
127
- )
153
+ def _get_sample_sheet_creator(self, workflow: Workflow) -> SampleSheetCreator:
154
+ match workflow:
155
+ case Workflow.NALLO:
156
+ return NalloSampleSheetCreator(
157
+ housekeeper_api=self.housekeeper_api, status_db=self.store
158
+ )
159
+ case Workflow.RAREDISEASE:
160
+ return RarediseaseSampleSheetCreator(
161
+ housekeeper_api=self.cg_config.housekeeper_api,
162
+ store=self.store,
163
+ )
164
+ case Workflow.RNAFUSION:
165
+ return RNAFusionSampleSheetCreator(
166
+ housekeeper_api=self.housekeeper_api, store=self.store
167
+ )
168
+ case Workflow.TAXPROFILER:
169
+ return TaxprofilerSampleSheetCreator(
170
+ housekeeper_api=self.housekeeper_api, store=self.store
171
+ )
172
+ case Workflow.TOMTE:
173
+ return TomteSampleSheetCreator(
174
+ housekeeper_api=self.housekeeper_api, store=self.store
175
+ )
176
+ case _:
177
+ raise NotImplementedError(f"No sample sheet creator implemented for {workflow}")
128
178
 
129
179
  def _get_pipeline_extension(self, workflow: Workflow) -> PipelineExtension:
130
- if workflow == Workflow.RAREDISEASE:
131
- gene_panel_creator: GenePanelFileCreator = self._get_gene_panel_file_creator(workflow)
132
- managed_variants_creator: ManagedVariantsFileCreator = (
133
- self._get_managed_variants_file_creator(workflow)
134
- )
135
- return RarediseaseExtension(
136
- gene_panel_file_creator=gene_panel_creator,
137
- managed_variants_file_creator=managed_variants_creator,
138
- )
139
- return PipelineExtension()
180
+ match workflow:
181
+ case Workflow.NALLO:
182
+ gene_panel_creator: GenePanelFileCreator = self._get_gene_panel_file_creator(
183
+ workflow
184
+ )
185
+ return NalloExtension(gene_panel_file_creator=gene_panel_creator)
186
+ case Workflow.RAREDISEASE:
187
+ gene_panel_creator: GenePanelFileCreator = self._get_gene_panel_file_creator(
188
+ workflow
189
+ )
190
+ managed_variants_creator: ManagedVariantsFileCreator = (
191
+ self._get_managed_variants_file_creator(workflow)
192
+ )
193
+ return RarediseaseExtension(
194
+ gene_panel_file_creator=gene_panel_creator,
195
+ managed_variants_file_creator=managed_variants_creator,
196
+ )
197
+ case Workflow.TOMTE:
198
+ gene_panel_creator: GenePanelFileCreator = self._get_gene_panel_file_creator(
199
+ workflow
200
+ )
201
+ return TomteExtension(gene_panel_file_creator=gene_panel_creator)
202
+ case _:
203
+ return PipelineExtension()
140
204
 
141
205
  def _get_gene_panel_file_creator(self, workflow: Workflow) -> GenePanelFileCreator:
142
206
  return GenePanelFileCreator(scout_api=self._get_scout_api(workflow), store=self.store)
@@ -151,6 +215,22 @@ class ConfiguratorFactory:
151
215
  else self.cg_config.scout_api_37
152
216
  )
153
217
 
218
+ def _get_balsamic_configurator(self) -> BalsamicConfigurator:
219
+ return BalsamicConfigurator(
220
+ config_file_creator=BalsamicConfigFileCreator(
221
+ cg_balsamic_config=self.cg_config.balsamic,
222
+ lims_api=self.lims_api,
223
+ status_db=self.store,
224
+ ),
225
+ fastq_handler=BalsamicFastqHandler(
226
+ housekeeper_api=self.housekeeper_api,
227
+ root_dir=Path(self.cg_config.balsamic.root),
228
+ status_db=self.store,
229
+ ),
230
+ config=self.cg_config.balsamic,
231
+ store=self.store,
232
+ )
233
+
154
234
  def _get_microsalt_configurator(self) -> MicrosaltConfigurator:
155
235
  return MicrosaltConfigurator(
156
236
  config_file_creator=self._get_microsalt_config_file_creator(),