cg 80.1.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 (91) hide show
  1. cg/__init__.py +1 -1
  2. cg/apps/housekeeper/hk.py +1 -1
  3. cg/apps/tb/api.py +1 -1
  4. cg/cli/upload/mutacc.py +16 -3
  5. cg/cli/upload/scout.py +2 -2
  6. cg/cli/upload/utils.py +10 -1
  7. cg/cli/workflow/balsamic/base.py +29 -4
  8. cg/cli/workflow/microsalt/base.py +3 -1
  9. cg/cli/workflow/nallo/base.py +18 -38
  10. cg/cli/workflow/nf_analysis.py +2 -203
  11. cg/cli/workflow/raredisease/base.py +33 -51
  12. cg/cli/workflow/rnafusion/base.py +28 -3
  13. cg/cli/workflow/taxprofiler/base.py +21 -13
  14. cg/cli/workflow/tomte/base.py +17 -19
  15. cg/constants/constants.py +3 -3
  16. cg/constants/devices.py +6 -1
  17. cg/constants/gene_panel.py +3 -1
  18. cg/constants/lims.py +4 -0
  19. cg/constants/orderforms.py +1 -1
  20. cg/constants/pacbio.py +1 -0
  21. cg/constants/scout.py +6 -4
  22. cg/exc.py +12 -4
  23. cg/meta/compress/compress.py +7 -2
  24. cg/meta/delivery_report/nallo.py +1 -1
  25. cg/meta/delivery_report/templates/macros/ticket_system.html +1 -1
  26. cg/meta/observations/balsamic_observations_api.py +1 -1
  27. cg/meta/observations/mip_dna_observations_api.py +1 -1
  28. cg/meta/observations/nallo_observations_api.py +1 -1
  29. cg/meta/observations/observations_api.py +1 -1
  30. cg/meta/observations/raredisease_observations_api.py +1 -1
  31. cg/meta/tar/tar.py +5 -2
  32. cg/meta/upload/coverage.py +5 -5
  33. cg/meta/upload/raredisease/raredisease.py +3 -0
  34. cg/meta/upload/scout/nallo_config_builder.py +14 -0
  35. cg/meta/workflow/nallo.py +22 -95
  36. cg/meta/workflow/nf_analysis.py +11 -262
  37. cg/meta/workflow/raredisease.py +3 -112
  38. cg/meta/workflow/rnafusion.py +2 -34
  39. cg/meta/workflow/taxprofiler.py +2 -38
  40. cg/meta/workflow/tomte.py +2 -42
  41. cg/models/deliverables/metric_deliverables.py +1 -1
  42. cg/models/nallo/nallo.py +14 -64
  43. cg/models/nf_analysis.py +1 -41
  44. cg/models/raredisease/raredisease.py +0 -62
  45. cg/models/rnafusion/rnafusion.py +0 -26
  46. cg/models/scout/scout_load_config.py +1 -0
  47. cg/models/taxprofiler/taxprofiler.py +0 -42
  48. cg/models/tomte/tomte.py +0 -69
  49. cg/resources/nallo_bundle_filenames.yaml +282 -22
  50. cg/resources/raredisease_bundle_filenames.yaml +11 -1
  51. cg/resources/taxprofiler_bundle_filenames.yaml +20 -0
  52. cg/server/admin.py +51 -24
  53. cg/server/app.py +15 -4
  54. cg/server/endpoints/sequencing_run/dtos.py +21 -3
  55. cg/server/endpoints/sequencing_run/pacbio_sequencing_run.py +29 -10
  56. cg/server/endpoints/sequencing_run/pacbio_smrt_cell_metrics.py +20 -0
  57. cg/services/analysis_starter/configurator/configurator.py +1 -1
  58. cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/models.py +40 -1
  59. cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/nallo.py +3 -1
  60. cg/services/analysis_starter/configurator/file_creators/nextflow/params_file/tomte_params_file_creator.py +3 -1
  61. cg/services/analysis_starter/factories/configurator_factory.py +4 -4
  62. cg/services/analysis_starter/tracker/implementations/balsamic.py +4 -1
  63. cg/services/analysis_starter/tracker/implementations/microsalt.py +4 -4
  64. cg/services/analysis_starter/tracker/implementations/mip_dna.py +4 -1
  65. cg/services/analysis_starter/tracker/implementations/nextflow_tracker.py +6 -4
  66. cg/services/analysis_starter/tracker/tracker.py +10 -6
  67. cg/services/illumina/backup/backup_service.py +29 -7
  68. cg/services/orders/validation/constants.py +3 -0
  69. cg/services/orders/validation/index_sequences.py +558 -0
  70. cg/services/run_devices/pacbio/data_storage_service/pacbio_store_service.py +39 -18
  71. cg/services/run_devices/pacbio/data_transfer_service/data_transfer_service.py +8 -2
  72. cg/services/run_devices/pacbio/data_transfer_service/dto.py +9 -3
  73. cg/services/run_devices/pacbio/data_transfer_service/utils.py +14 -7
  74. cg/services/run_devices/pacbio/metrics_parser/models.py +1 -0
  75. cg/services/run_devices/pacbio/sequencing_runs_service.py +35 -7
  76. cg/services/sequencing_qc_service/quality_checks/checks.py +18 -16
  77. cg/services/sequencing_qc_service/quality_checks/utils.py +82 -18
  78. cg/services/sequencing_qc_service/sequencing_qc_service.py +12 -10
  79. cg/store/crud/create.py +73 -42
  80. cg/store/crud/read.py +50 -2
  81. cg/store/crud/update.py +14 -3
  82. cg/store/models.py +88 -31
  83. cg/store/store.py +8 -1
  84. {cg-80.1.0.dist-info → cg-83.14.0.dist-info}/METADATA +1 -1
  85. {cg-80.1.0.dist-info → cg-83.14.0.dist-info}/RECORD +91 -90
  86. /cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{nallo.py → nallo_sample_sheet_creator.py} +0 -0
  87. /cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{raredisease.py → raredisease_sample_sheet_creator.py} +0 -0
  88. /cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{rnafusion.py → rnafusion_sample_sheet_creator.py} +0 -0
  89. /cg/services/analysis_starter/configurator/file_creators/nextflow/sample_sheet/{taxprofiler.py → taxprofiler_sample_sheet_creator.py} +0 -0
  90. {cg-80.1.0.dist-info → cg-83.14.0.dist-info}/WHEEL +0 -0
  91. {cg-80.1.0.dist-info → cg-83.14.0.dist-info}/entry_points.txt +0 -0
@@ -3,7 +3,7 @@ from datetime import datetime
3
3
  from pydantic import BaseModel
4
4
 
5
5
 
6
- class PacbioSequencingRunDTO(BaseModel):
6
+ class PacbioSmrtCellMetricsDTO(BaseModel):
7
7
  barcoded_hifi_mean_read_length: int
8
8
  barcoded_hifi_reads: int
9
9
  barcoded_hifi_reads_percentage: float
@@ -24,5 +24,23 @@ class PacbioSequencingRunDTO(BaseModel):
24
24
  well: str
25
25
 
26
26
 
27
- class PacbioSequencingRunsResponse(BaseModel):
28
- runs: list[PacbioSequencingRunDTO]
27
+ class PacbioSmrtCellMetricsResponse(BaseModel):
28
+ runs: list[PacbioSmrtCellMetricsDTO]
29
+
30
+
31
+ class PacbioSequencingRunDTO(BaseModel):
32
+ id: int
33
+ run_name: str
34
+ comment: str
35
+ processed: bool
36
+
37
+
38
+ class PacbioSequencingRunResponse(BaseModel):
39
+ pacbio_sequencing_runs: list[PacbioSequencingRunDTO]
40
+ total_count: int
41
+
42
+
43
+ class PacbioSequencingRunUpdateRequest(BaseModel):
44
+ id: int
45
+ comment: str | None = None
46
+ processed: bool | None = None
@@ -1,20 +1,39 @@
1
- from flask import Blueprint, jsonify
1
+ from http import HTTPStatus
2
+
3
+ from flask import Blueprint, Response, jsonify, request
4
+ from pydantic import ValidationError
2
5
 
3
6
  from cg.server.endpoints.error_handler import handle_missing_entries
4
- from cg.server.endpoints.sequencing_run.dtos import PacbioSequencingRunsResponse
7
+ from cg.server.endpoints.sequencing_run.dtos import (
8
+ PacbioSequencingRunResponse,
9
+ PacbioSequencingRunUpdateRequest,
10
+ )
5
11
  from cg.server.endpoints.utils import before_request
6
12
  from cg.server.ext import pacbio_sequencing_runs_service
7
13
 
8
- PACBIO_SEQUENCING_RUN_BLUEPRINT = Blueprint(
9
- "pacbio_sequencing_run", __name__, url_prefix="/api/v1/pacbio_sequencing_run"
14
+ PACBIO_SEQUENCING_RUNS_BLUEPRINT = Blueprint(
15
+ "pacbio_sequencing_runs", __name__, url_prefix="/api/v1/"
10
16
  )
11
- PACBIO_SEQUENCING_RUN_BLUEPRINT.before_request(before_request)
17
+ PACBIO_SEQUENCING_RUNS_BLUEPRINT.before_request(before_request)
12
18
 
13
19
 
14
- @PACBIO_SEQUENCING_RUN_BLUEPRINT.route("/<run_name>", methods=["GET"])
20
+ @PACBIO_SEQUENCING_RUNS_BLUEPRINT.route("/pacbio_sequencing_runs", methods=["GET"])
15
21
  @handle_missing_entries
16
- def get_sequencing_runs(run_name: str):
17
- response: PacbioSequencingRunsResponse = (
18
- pacbio_sequencing_runs_service.get_sequencing_runs_by_name(run_name)
22
+ def get_sequencing_runs():
23
+ page: int = int(request.args.get("page", "0"))
24
+ page_size: int = int(request.args.get("pageSize", "0"))
25
+ sequencing_runs: PacbioSequencingRunResponse = (
26
+ pacbio_sequencing_runs_service.get_sequencing_runs(page=page, page_size=page_size)
19
27
  )
20
- return jsonify(response.model_dump())
28
+ return jsonify(sequencing_runs.model_dump())
29
+
30
+
31
+ @PACBIO_SEQUENCING_RUNS_BLUEPRINT.route("/pacbio_sequencing_runs/<id>", methods=["PATCH"])
32
+ @handle_missing_entries
33
+ def update_sequencing_run(id: str):
34
+ try:
35
+ update_request = PacbioSequencingRunUpdateRequest(id=id, **request.json)
36
+ except ValidationError:
37
+ return Response(status=HTTPStatus.UNPROCESSABLE_ENTITY)
38
+ pacbio_sequencing_runs_service.update_sequencing_run(update_request=update_request)
39
+ return Response(status=HTTPStatus.NO_CONTENT)
@@ -0,0 +1,20 @@
1
+ from flask import Blueprint, jsonify
2
+
3
+ from cg.server.endpoints.error_handler import handle_missing_entries
4
+ from cg.server.endpoints.sequencing_run.dtos import PacbioSmrtCellMetricsResponse
5
+ from cg.server.endpoints.utils import before_request
6
+ from cg.server.ext import pacbio_sequencing_runs_service
7
+
8
+ PACBIO_SMRT_CELL_METRICS_BLUEPRINT = Blueprint(
9
+ "pacbio_smrt_cell_metrics", __name__, url_prefix="/api/v1/pacbio_smrt_cell_metrics"
10
+ )
11
+ PACBIO_SMRT_CELL_METRICS_BLUEPRINT.before_request(before_request)
12
+
13
+
14
+ @PACBIO_SMRT_CELL_METRICS_BLUEPRINT.route("/<run_name>", methods=["GET"])
15
+ @handle_missing_entries
16
+ def get_smrt_cell_metrics(run_name: str):
17
+ response: PacbioSmrtCellMetricsResponse = (
18
+ pacbio_sequencing_runs_service.get_sequencing_runs_by_name(run_name)
19
+ )
20
+ return jsonify(response.model_dump())
@@ -20,7 +20,7 @@ class Configurator(ABC):
20
20
  @staticmethod
21
21
  def _set_flags(config: SpecificCaseConfig, **flags) -> SpecificCaseConfig:
22
22
  curated_flags: dict = {key: value for key, value in flags.items() if value is not None}
23
- return config.model_copy(update=curated_flags)
23
+ return config.model_validate(config.model_dump(by_alias=True) | curated_flags)
24
24
 
25
25
  @abstractmethod
26
26
  def _ensure_required_config_files_exist(self, **kwargs) -> None:
@@ -1,6 +1,21 @@
1
1
  from pathlib import Path
2
2
 
3
- from cg.models.nf_analysis import WorkflowParameters
3
+ from pydantic import BaseModel, field_validator
4
+
5
+ from cg.constants.constants import GenomeVersion
6
+ from cg.constants.sample_sources import SourceType
7
+ from cg.utils.utils import replace_non_alphanumeric
8
+
9
+
10
+ class WorkflowParameters(BaseModel):
11
+ input: Path
12
+ outdir: Path
13
+
14
+
15
+ class NalloParameters(WorkflowParameters):
16
+ """Model for Nallo parameters."""
17
+
18
+ filter_variants_hgnc_ids: str
4
19
 
5
20
 
6
21
  class RarediseaseParameters(WorkflowParameters):
@@ -20,3 +35,27 @@ class RNAFusionParameters(WorkflowParameters):
20
35
 
21
36
  class TaxprofilerParameters(WorkflowParameters):
22
37
  """Taxprofiler parameters."""
38
+
39
+
40
+ class TomteParameters(WorkflowParameters):
41
+ """Model for Tomte parameters."""
42
+
43
+ gene_panel_clinical_filter: Path
44
+ tissue: str
45
+ genome: str = GenomeVersion.HG38
46
+
47
+ @field_validator("tissue", mode="before")
48
+ @classmethod
49
+ def restrict_tissue_values(cls, tissue: str | None) -> str:
50
+ if tissue:
51
+ return replace_non_alphanumeric(string=tissue)
52
+ else:
53
+ return SourceType.UNKNOWN
54
+
55
+ @field_validator("genome", mode="before")
56
+ @classmethod
57
+ def restrict_genome_values(cls, genome: str) -> str:
58
+ if genome == GenomeVersion.HG38:
59
+ return GenomeVersion.GRCh38.value
60
+ elif genome == GenomeVersion.HG19:
61
+ return GenomeVersion.GRCh37.value
@@ -4,10 +4,12 @@ from typing import Any
4
4
 
5
5
  from cg.constants.scout import ScoutExportFileName
6
6
  from cg.io.yaml import read_yaml, write_yaml_nextflow_style
7
- from cg.models.nallo.nallo import NalloParameters
8
7
  from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.abstract import (
9
8
  ParamsFileCreator,
10
9
  )
10
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.models import (
11
+ NalloParameters,
12
+ )
11
13
  from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.utils import (
12
14
  replace_values_in_params_file,
13
15
  )
@@ -6,10 +6,12 @@ from cg.constants.constants import GenomeVersion
6
6
  from cg.constants.scout import ScoutExportFileName
7
7
  from cg.exc import CgError
8
8
  from cg.io.yaml import read_yaml, write_yaml_nextflow_style
9
- from cg.models.tomte.tomte import TomteParameters
10
9
  from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.abstract import (
11
10
  ParamsFileCreator,
12
11
  )
12
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.models import (
13
+ TomteParameters,
14
+ )
13
15
  from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.utils import (
14
16
  replace_values_in_params_file,
15
17
  )
@@ -47,19 +47,19 @@ from cg.services.analysis_starter.configurator.file_creators.nextflow.params_fil
47
47
  from cg.services.analysis_starter.configurator.file_creators.nextflow.params_file.tomte_params_file_creator import (
48
48
  TomteParamsFileCreator,
49
49
  )
50
- from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.nallo import (
50
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.nallo_sample_sheet_creator import (
51
51
  NalloSampleSheetCreator,
52
52
  )
53
53
  from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.protocol import (
54
54
  SampleSheetCreator,
55
55
  )
56
- from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.raredisease import (
56
+ from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.raredisease_sample_sheet_creator import (
57
57
  RarediseaseSampleSheetCreator,
58
58
  )
59
- 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 (
60
60
  RNAFusionSampleSheetCreator,
61
61
  )
62
- 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 (
63
63
  TaxprofilerSampleSheetCreator,
64
64
  )
65
65
  from cg.services.analysis_starter.configurator.file_creators.nextflow.sample_sheet.tomte_sample_sheet_creator import (
@@ -12,7 +12,10 @@ class BalsamicTracker(Tracker):
12
12
  return WorkflowManager.Slurm
13
13
 
14
14
  def _get_job_ids_path(self, case_id: str) -> Path:
15
- return Path(self.workflow_root, case_id, "analysis", "slurm_jobids.yaml")
15
+ return Path(self._get_out_dir_path(case_id), "slurm_jobids.yaml")
16
+
17
+ def _get_out_dir_path(self, case_id: str) -> Path:
18
+ return Path(self.workflow_root, case_id, "analysis")
16
19
 
17
20
  def _get_workflow_version(self, case_config: BalsamicCaseConfig) -> str:
18
21
  config_data: dict = read_json(case_config.sample_config)
@@ -27,13 +27,13 @@ class MicrosaltTracker(Tracker):
27
27
  def _get_job_ids_path(self, case_id: str) -> Path:
28
28
  project_id: str = self._get_file_name_start(case_id)
29
29
  return Path(
30
- self.workflow_root,
31
- "results",
32
- "reports",
33
- "trailblazer",
30
+ self._get_out_dir_path(case_id),
34
31
  f"{project_id}_slurm_ids{FileExtensions.YAML}",
35
32
  )
36
33
 
34
+ def _get_out_dir_path(self, case_id: str) -> Path:
35
+ return Path(self.workflow_root, "results", "reports", "trailblazer")
36
+
37
37
  def _get_file_name_start(self, case_id: str) -> str:
38
38
  """Returns the LIMS project id if the case contains multiple samples, else the sample id."""
39
39
  case: Case = self.store.get_case_by_internal_id(case_id)
@@ -12,7 +12,10 @@ class MIPDNATracker(Tracker):
12
12
  return WorkflowManager.Slurm
13
13
 
14
14
  def _get_job_ids_path(self, case_id: str) -> Path:
15
- return Path(self.workflow_root, case_id, "analysis", "slurm_job_ids.yaml")
15
+ return Path(self._get_out_dir_path(case_id), "slurm_job_ids.yaml")
16
+
17
+ def _get_out_dir_path(self, case_id: str) -> Path:
18
+ return Path(self.workflow_root, case_id, "analysis")
16
19
 
17
20
  def _get_sample_info_path(self, case_id: str) -> Path:
18
21
  return Path(self.workflow_root, case_id, "analysis", f"{case_id}_qc_sample_info.yaml")
@@ -1,6 +1,6 @@
1
1
  from pathlib import Path
2
2
 
3
- from cg.constants.constants import FileExtensions, WorkflowManager
3
+ from cg.constants.constants import WorkflowManager
4
4
  from cg.services.analysis_starter.configurator.models.nextflow import NextflowCaseConfig
5
5
  from cg.services.analysis_starter.tracker.tracker import Tracker
6
6
 
@@ -9,9 +9,11 @@ class NextflowTracker(Tracker):
9
9
  def _workflow_manager(self) -> WorkflowManager:
10
10
  return WorkflowManager.Tower
11
11
 
12
- def _get_job_ids_path(self, case_id: str) -> Path:
13
- """Return the path to a Trailblazer config file containing Tower IDs."""
14
- return Path(self.workflow_root, case_id, "tower_ids").with_suffix(FileExtensions.YAML)
12
+ def _get_job_ids_path(self, case_id: str) -> Path | None:
13
+ return None
14
+
15
+ def _get_out_dir_path(self, case_id: str) -> Path:
16
+ return Path(self.workflow_root, case_id)
15
17
 
16
18
  def _get_workflow_version(self, case_config: NextflowCaseConfig) -> str:
17
19
  return case_config.revision
@@ -6,7 +6,7 @@ from pathlib import Path
6
6
  from cg.apps.environ import environ_email
7
7
  from cg.apps.tb import TrailblazerAPI
8
8
  from cg.apps.tb.models import TrailblazerAnalysis
9
- from cg.constants.constants import CaseActions, CustomerId, Workflow
9
+ from cg.constants.constants import CaseActions, CustomerId, Workflow, WorkflowManager
10
10
  from cg.constants.priority import TrailblazerPriority
11
11
  from cg.constants.sequencing import SeqLibraryPrepCategory
12
12
  from cg.constants.tb import AnalysisType
@@ -61,17 +61,17 @@ class Tracker(ABC):
61
61
  self, case_id: str, tower_workflow_id: str | None
62
62
  ) -> TrailblazerAnalysis:
63
63
  analysis_type: str = self._get_analysis_type(case_id)
64
- config_path: Path = self._get_job_ids_path(case_id)
64
+ config_path: Path | None = self._get_job_ids_path(case_id)
65
65
  email: str = environ_email()
66
66
  order_id: int = self.store.get_case_by_internal_id_strict(case_id).latest_order.id
67
- out_dir: str = config_path.parent.as_posix()
67
+ out_dir: str = self._get_out_dir_path(case_id).as_posix()
68
68
  priority: TrailblazerPriority = self._get_trailblazer_priority(case_id)
69
69
  ticket: str = self.store.get_latest_ticket_from_case(case_id)
70
70
  is_case_for_development: bool = self._is_case_for_development(case_id)
71
71
  return self.trailblazer_api.add_pending_analysis(
72
72
  analysis_type=analysis_type,
73
73
  case_id=case_id,
74
- config_path=config_path.as_posix(),
74
+ config_path=config_path.as_posix() if config_path else None,
75
75
  email=email,
76
76
  order_id=order_id,
77
77
  out_dir=out_dir,
@@ -133,11 +133,15 @@ class Tracker(ABC):
133
133
  return case.customer.internal_id == CustomerId.CG_INTERNAL_CUSTOMER
134
134
 
135
135
  @abstractmethod
136
- def _workflow_manager(self):
136
+ def _workflow_manager(self) -> WorkflowManager:
137
137
  pass
138
138
 
139
139
  @abstractmethod
140
- def _get_job_ids_path(self, case_id: str):
140
+ def _get_job_ids_path(self, case_id: str) -> Path | None:
141
+ pass
142
+
143
+ @abstractmethod
144
+ def _get_out_dir_path(self, case_id: str) -> Path:
141
145
  pass
142
146
 
143
147
  @abstractmethod
@@ -114,7 +114,10 @@ class IlluminaBackupService:
114
114
  """Process a flow cell from backup. Return elapsed time."""
115
115
  start_time: float = get_start_time()
116
116
  run_dir = Path(self.sequencing_runs_dir)
117
- sequencing_run_output_dir = Path(run_dir, archived_run.name.split(".")[0])
117
+ is_current: bool = self._is_archiving_directory_current(archived_run)
118
+ sequencing_run_output_dir: Path = self._get_sequencing_run_output_dir(
119
+ archived_run=archived_run, is_current=is_current
120
+ )
118
121
  self.retrieve_archived_key(
119
122
  archived_key=archived_key, sequencing_run=sequencing_run, run_dir=run_dir
120
123
  )
@@ -128,9 +131,12 @@ class IlluminaBackupService:
128
131
  encryption_key,
129
132
  retrieved_run,
130
133
  retrieved_key,
131
- ) = self.decrypt_sequencing_run(archived_run, archived_key, run_dir)
132
-
133
- self.extract_sequencing_run(decrypted_run, run_dir)
134
+ ) = self.decrypt_sequencing_run(
135
+ archived_run=archived_run, archived_key=archived_key, run_dir=run_dir
136
+ )
137
+ self.extract_sequencing_run(
138
+ decrypted_run=decrypted_run, is_current=is_current, run_dir=run_dir
139
+ )
134
140
  self.create_rta_complete(sequencing_run_output_dir)
135
141
  self.create_copy_complete(sequencing_run_output_dir)
136
142
  self.unlink_files(decrypted_run, encryption_key, retrieved_run, retrieved_key)
@@ -145,6 +151,20 @@ class IlluminaBackupService:
145
151
 
146
152
  return get_elapsed_time(start_time=start_time)
147
153
 
154
+ def _get_sequencing_run_output_dir(self, archived_run: Path, is_current: bool) -> Path:
155
+ """Return the path to the sequencing run based on the archived run path."""
156
+ if is_current:
157
+ run_full_name: str = archived_run.parent.name
158
+ else:
159
+ run_full_name: str = archived_run.name.split(".")[0]
160
+ return Path(self.sequencing_runs_dir, run_full_name)
161
+
162
+ def _is_archiving_directory_current(self, archived_run: Path) -> bool:
163
+ """Check if the archived run is in the current archiving directory."""
164
+ return archived_run.as_posix().startswith(
165
+ Path(self.pdc_archiving_directory.current).parent.as_posix()
166
+ )
167
+
148
168
  def unlink_files(
149
169
  self,
150
170
  decrypted_run: Path,
@@ -184,10 +204,12 @@ class IlluminaBackupService:
184
204
  """Create a CopyComplete.txt file in the flow cell run directory."""
185
205
  Path(flow_cell_directory, DemultiplexingDirsAndFiles.COPY_COMPLETE).touch()
186
206
 
187
- def extract_sequencing_run(self, decrypted_run, run_dir):
207
+ def extract_sequencing_run(self, decrypted_run: Path, is_current: bool, run_dir: Path) -> None:
188
208
  """Extract the sequencing run tar archive."""
189
- extraction_command = self.tar_api.get_extract_file_command(
190
- input_file=decrypted_run, output_dir=run_dir
209
+ extraction_command: list[str] = self.tar_api.get_extract_file_command(
210
+ input_file=decrypted_run,
211
+ output_dir=run_dir,
212
+ is_current=is_current,
191
213
  )
192
214
  LOG.debug(f"Extract sequencing run command: {extraction_command}")
193
215
  self.tar_api.run_tar_command(extraction_command)
@@ -30,6 +30,7 @@ class ExtractionMethod(StrEnum):
30
30
 
31
31
 
32
32
  class IndexEnum(StrEnum):
33
+ ARCHER_SET_B = "Archer Set B"
33
34
  AVIDA_INDEX_PLATE = "Avida Index plate"
34
35
  AVIDA_INDEX_STRIP = "Avida Index strip"
35
36
  IDT_DS_B = "IDT DupSeq 10 bp Set B"
@@ -37,6 +38,7 @@ class IndexEnum(StrEnum):
37
38
  IDT_XGEN_UDI = "IDT xGen UDI Adapters"
38
39
  IDT10_UDI_NIPT = "IDT10 UDI NIPT"
39
40
  KAPA_UDI_NIPT = "KAPA UDI NIPT"
41
+ NEBNEXT_LV_Unique_Dual_2A = "NEBNext LV Unique Dual Index Primers Set 2A"
40
42
  NEXTERA_XT = "Nextera XT Dual"
41
43
  NEXTFLEX_UDI_96 = "NEXTflex® Unique Dual Index Barcodes 1 - 96"
42
44
  NEXTFLEX_V2_UDI_96 = "NEXTflex® v2 UDI Barcodes 1 - 96"
@@ -46,4 +48,5 @@ class IndexEnum(StrEnum):
46
48
  TWIST_UDI_B = "TWIST UDI Set B"
47
49
  TWIST_UDI_C = "TWIST UDI Set C"
48
50
  TRUSEQ_DNA_HT = "TruSeq DNA HT Dual-index (D7-D5)"
51
+ XGEN_UDI_10_1_4 = "xGen UDI 10nt Primer Plates 1-4"
49
52
  NO_INDEX = "NoIndex"