diff --git a/cg/apps/demultiplex/sample_sheet/models.py b/cg/apps/demultiplex/sample_sheet/models.py index 9ecfa301fd..f41ec197b6 100644 --- a/cg/apps/demultiplex/sample_sheet/models.py +++ b/cg/apps/demultiplex/sample_sheet/models.py @@ -26,43 +26,39 @@ class FlowCellSample(BaseModel): class FlowCellSampleBcl2Fastq(FlowCellSample): """Base class for NovaSeq6000 flow cell samples.""" - flowcell_id: str = Field("", alias=SampleSheetBcl2FastqSections.Data.FLOW_CELL_ID.value) - lane: int = Field(..., alias=SampleSheetBcl2FastqSections.Data.LANE.value) + flowcell_id: str = Field("", alias=SampleSheetBcl2FastqSections.Data.FLOW_CELL_ID) + lane: int = Field(..., alias=SampleSheetBcl2FastqSections.Data.LANE) sample_ref: str = Field( - GenomeVersion.hg19.value, alias=SampleSheetBcl2FastqSections.Data.SAMPLE_REFERENCE.value + GenomeVersion.hg19, alias=SampleSheetBcl2FastqSections.Data.SAMPLE_REFERENCE ) - index: str = Field(..., alias=SampleSheetBcl2FastqSections.Data.INDEX_1.value) - index2: str = Field("", alias=SampleSheetBcl2FastqSections.Data.INDEX_2.value) - sample_name: str = Field(..., alias=SampleSheetBcl2FastqSections.Data.SAMPLE_NAME.value) - control: str = Field("N", alias=SampleSheetBcl2FastqSections.Data.CONTROL.value) - recipe: str = Field("R1", alias=SampleSheetBcl2FastqSections.Data.RECIPE.value) - operator: str = Field("script", alias=SampleSheetBcl2FastqSections.Data.OPERATOR.value) + index: str = Field(..., alias=SampleSheetBcl2FastqSections.Data.INDEX_1) + index2: str = Field("", alias=SampleSheetBcl2FastqSections.Data.INDEX_2) + sample_name: str = Field(..., alias=SampleSheetBcl2FastqSections.Data.SAMPLE_NAME) + control: str = Field("N", alias=SampleSheetBcl2FastqSections.Data.CONTROL) + recipe: str = Field("R1", alias=SampleSheetBcl2FastqSections.Data.RECIPE) + operator: str = Field("script", alias=SampleSheetBcl2FastqSections.Data.OPERATOR) sample_id: SampleId = Field( - ..., alias=SampleSheetBcl2FastqSections.Data.SAMPLE_INTERNAL_ID_BCL2FASTQ.value - ) - project: str = Field( - ..., alias=SampleSheetBcl2FastqSections.Data.SAMPLE_PROJECT_BCL2FASTQ.value + ..., alias=SampleSheetBcl2FastqSections.Data.SAMPLE_INTERNAL_ID_BCL2FASTQ ) + project: str = Field(..., alias=SampleSheetBcl2FastqSections.Data.SAMPLE_PROJECT_BCL2FASTQ) class FlowCellSampleBCLConvert(FlowCellSample): """Class that represents a NovaSeqX flow cell sample.""" - lane: int = Field(..., alias=SampleSheetBCLConvertSections.Data.LANE.value) - sample_id: SampleId = Field( - ..., alias=SampleSheetBCLConvertSections.Data.SAMPLE_INTERNAL_ID.value - ) - index: str = Field(..., alias=SampleSheetBCLConvertSections.Data.INDEX_1.value) - index2: str = Field("", alias=SampleSheetBCLConvertSections.Data.INDEX_2.value) - override_cycles: str = Field("", alias=SampleSheetBCLConvertSections.Data.OVERRIDE_CYCLES.value) - adapter_read_1: str = Field("", alias=SampleSheetBCLConvertSections.Data.ADAPTER_READ_1.value) - adapter_read_2: str = Field("", alias=SampleSheetBCLConvertSections.Data.ADAPTER_READ_2.value) + lane: int = Field(..., alias=SampleSheetBCLConvertSections.Data.LANE) + sample_id: SampleId = Field(..., alias=SampleSheetBCLConvertSections.Data.SAMPLE_INTERNAL_ID) + index: str = Field(..., alias=SampleSheetBCLConvertSections.Data.INDEX_1) + index2: str = Field("", alias=SampleSheetBCLConvertSections.Data.INDEX_2) + override_cycles: str = Field("", alias=SampleSheetBCLConvertSections.Data.OVERRIDE_CYCLES) + adapter_read_1: str = Field("", alias=SampleSheetBCLConvertSections.Data.ADAPTER_READ_1) + adapter_read_2: str = Field("", alias=SampleSheetBCLConvertSections.Data.ADAPTER_READ_2) barcode_mismatches_1: int = Field( - 1, alias=SampleSheetBCLConvertSections.Data.BARCODE_MISMATCHES_1.value + 1, alias=SampleSheetBCLConvertSections.Data.BARCODE_MISMATCHES_1 ) barcode_mismatches_2: int = Field( - 1, alias=SampleSheetBCLConvertSections.Data.BARCODE_MISMATCHES_2.value + 1, alias=SampleSheetBCLConvertSections.Data.BARCODE_MISMATCHES_2 ) diff --git a/cg/apps/demultiplex/sample_sheet/read_sample_sheet.py b/cg/apps/demultiplex/sample_sheet/read_sample_sheet.py index 512e276407..e1d011862f 100644 --- a/cg/apps/demultiplex/sample_sheet/read_sample_sheet.py +++ b/cg/apps/demultiplex/sample_sheet/read_sample_sheet.py @@ -62,10 +62,10 @@ def get_sample_type(sample_sheet_path: Path) -> Type[FlowCellSample]: for row in sample_sheet_content: if not row: continue - if SampleSheetBCLConvertSections.Data.HEADER.value in row[0]: + if SampleSheetBCLConvertSections.Data.HEADER in row[0]: LOG.info("Sample sheet was generated for BCL Convert") return FlowCellSampleBCLConvert - if SampleSheetBcl2FastqSections.Data.HEADER.value in row[0]: + if SampleSheetBcl2FastqSections.Data.HEADER in row[0]: LOG.info("Sample sheet was generated for BCL2FASTQ") return FlowCellSampleBcl2Fastq raise SampleSheetError("Could not determine sample sheet type") diff --git a/cg/apps/demultiplex/sample_sheet/sample_sheet_creator.py b/cg/apps/demultiplex/sample_sheet/sample_sheet_creator.py index f931057783..baf1d747aa 100644 --- a/cg/apps/demultiplex/sample_sheet/sample_sheet_creator.py +++ b/cg/apps/demultiplex/sample_sheet/sample_sheet_creator.py @@ -164,16 +164,16 @@ def add_override_cycles_to_samples(self) -> None: def get_additional_sections_sample_sheet(self) -> list[list[str]]: """Return all sections of the sample sheet that are not the data section.""" return [ - [SampleSheetBcl2FastqSections.Settings.HEADER.value], - SampleSheetBcl2FastqSections.Settings.BARCODE_MISMATCH_INDEX1.value, - SampleSheetBcl2FastqSections.Settings.BARCODE_MISMATCH_INDEX2.value, + [SampleSheetBcl2FastqSections.Settings.HEADER], + SampleSheetBcl2FastqSections.Settings.barcode_mismatch_index_1(), + SampleSheetBcl2FastqSections.Settings.barcode_mismatch_index_2(), ] def get_data_section_header_and_columns(self) -> list[list[str]]: """Return the header and column names of the data section of the sample sheet.""" return [ [SampleSheetBcl2FastqSections.Data.HEADER.value], - SampleSheetBcl2FastqSections.Data.COLUMN_NAMES.value, + SampleSheetBcl2FastqSections.Data.column_names(), ] @@ -226,15 +226,15 @@ def get_additional_sections_sample_sheet(self) -> list[list[str]]: """Return all sections of the sample sheet that are not the data section.""" header_section: list[list[str]] = [ [SampleSheetBCLConvertSections.Header.HEADER.value], - SampleSheetBCLConvertSections.Header.FILE_FORMAT.value, + SampleSheetBCLConvertSections.Header.file_format(), [SampleSheetBCLConvertSections.Header.RUN_NAME.value, self.flow_cell_id], [ SampleSheetBCLConvertSections.Header.INSTRUMENT_PLATFORM_TITLE.value, - SampleSheetBCLConvertSections.Header.INSTRUMENT_PLATFORM_VALUE.value[ + SampleSheetBCLConvertSections.Header.instrument_platform_sequencer().get( self.flow_cell.sequencer_type - ], + ), ], - SampleSheetBCLConvertSections.Header.INDEX_ORIENTATION_FORWARD.value, + SampleSheetBCLConvertSections.Header.index_orientation_forward(), ] reads_section: list[list[str]] = [ [SampleSheetBCLConvertSections.Reads.HEADER], @@ -256,9 +256,9 @@ def get_additional_sections_sample_sheet(self) -> list[list[str]]: ], ] settings_section: list[list[str]] = [ - [SampleSheetBCLConvertSections.Settings.HEADER.value], - SampleSheetBCLConvertSections.Settings.SOFTWARE_VERSION.value, - SampleSheetBCLConvertSections.Settings.FASTQ_COMPRESSION_FORMAT.value, + [SampleSheetBCLConvertSections.Settings.HEADER], + SampleSheetBCLConvertSections.Settings.software_version(), + SampleSheetBCLConvertSections.Settings.fastq_compression_format(), ] return header_section + reads_section + settings_section @@ -266,5 +266,5 @@ def get_data_section_header_and_columns(self) -> list[list[str]]: """Return the header and column names of the data section of the sample sheet.""" return [ [SampleSheetBCLConvertSections.Data.HEADER.value], - SampleSheetBCLConvertSections.Data.COLUMN_NAMES.value, + SampleSheetBCLConvertSections.Data.column_names(), ] diff --git a/cg/apps/mip/confighandler.py b/cg/apps/mip/confighandler.py index 65b527a9d2..11eb9da129 100644 --- a/cg/apps/mip/confighandler.py +++ b/cg/apps/mip/confighandler.py @@ -24,8 +24,8 @@ class SampleSchema(Schema): ] ), ) - father = fields.Str(dump_default=RelationshipStatus.HAS_NO_PARENT.value) - mother = fields.Str(dump_default=RelationshipStatus.HAS_NO_PARENT.value) + father = fields.Str(dump_default=RelationshipStatus.HAS_NO_PARENT) + mother = fields.Str(dump_default=RelationshipStatus.HAS_NO_PARENT) phenotype = fields.Str( required=True, validate=validate.OneOf(choices=["affected", "unaffected", "unknown"]), @@ -80,10 +80,10 @@ def parse_pedigree_config(data: dict) -> dict: LOG.info("setting 'unknown' phenotype to 'unaffected'") data_copy["samples"][0]["phenotype"] = "unaffected" for sample_data in data_copy["samples"]: - sample_data["mother"] = ( + sample_data["mother"]: str = ( sample_data.get("mother") or RelationshipStatus.HAS_NO_PARENT.value ) - sample_data["father"] = ( + sample_data["father"]: str = ( sample_data.get("father") or RelationshipStatus.HAS_NO_PARENT.value ) if sample_data["analysis_type"] == "wgs" and sample_data.get("capture_kit") is None: diff --git a/cg/apps/sequencing_metrics_parser/models/bcl_convert.py b/cg/apps/sequencing_metrics_parser/models/bcl_convert.py index 32142b733f..13d8bd25a1 100644 --- a/cg/apps/sequencing_metrics_parser/models/bcl_convert.py +++ b/cg/apps/sequencing_metrics_parser/models/bcl_convert.py @@ -9,23 +9,21 @@ class BclConvertQualityMetrics(BaseModel): """Model for the BCL Convert quality metrics.""" - lane: int = Field(..., alias=BclConvertQualityMetricsColumnNames.LANE.value) + lane: int = Field(..., alias=BclConvertQualityMetricsColumnNames.LANE) sample_internal_id: str = Field( - ..., alias=BclConvertQualityMetricsColumnNames.SAMPLE_INTERNAL_ID.value + ..., alias=BclConvertQualityMetricsColumnNames.SAMPLE_INTERNAL_ID ) mean_quality_score_q30: float = Field( - ..., alias=BclConvertQualityMetricsColumnNames.MEAN_QUALITY_SCORE_Q30.value + ..., alias=BclConvertQualityMetricsColumnNames.MEAN_QUALITY_SCORE_Q30 ) q30_bases_percent: float = Field( - ..., alias=BclConvertQualityMetricsColumnNames.Q30_BASES_PERCENT.value + ..., alias=BclConvertQualityMetricsColumnNames.Q30_BASES_PERCENT ) class BclConvertDemuxMetrics(BaseModel): """Model for the BCL Convert demultiplexing metrics.""" - lane: int = Field(..., alias=BclConvertDemuxMetricsColumnNames.LANE.value) - sample_internal_id: str = Field( - ..., alias=BclConvertDemuxMetricsColumnNames.SAMPLE_INTERNAL_ID.value - ) - read_pair_count: int = Field(..., alias=BclConvertDemuxMetricsColumnNames.READ_PAIR_COUNT.value) + lane: int = Field(..., alias=BclConvertDemuxMetricsColumnNames.LANE) + sample_internal_id: str = Field(..., alias=BclConvertDemuxMetricsColumnNames.SAMPLE_INTERNAL_ID) + read_pair_count: int = Field(..., alias=BclConvertDemuxMetricsColumnNames.READ_PAIR_COUNT) diff --git a/cg/apps/slurm/slurm_api.py b/cg/apps/slurm/slurm_api.py index 78ec8b6974..5ee2384c79 100644 --- a/cg/apps/slurm/slurm_api.py +++ b/cg/apps/slurm/slurm_api.py @@ -30,7 +30,7 @@ def set_dry_run(self, dry_run: bool) -> None: @staticmethod def generate_sbatch_content(sbatch_parameters: Sbatch) -> str: """Take a parameters object and generate a string with sbatch information.""" - if hasattr(sbatch_parameters, Slurm.PARTITION.value): + if hasattr(sbatch_parameters, Slurm.PARTITION): sbatch_header: str = SlurmAPI.generate_dragen_sbatch_header( sbatch_parameters=sbatch_parameters ) diff --git a/cg/cli/clean.py b/cg/cli/clean.py index 59061f422a..92dd9af787 100644 --- a/cg/cli/clean.py +++ b/cg/cli/clean.py @@ -24,7 +24,7 @@ ) from cg.constants import EXIT_FAIL, EXIT_SUCCESS from cg.constants.constants import DRY_RUN, SKIP_CONFIRMATION, Pipeline -from cg.constants.housekeeper_tags import ALIGNMENT_FILE_TAGS, ScoutTag +from cg.constants.housekeeper_tags import AlignmentFileTag, ScoutTag from cg.exc import CleanFlowCellFailedError from cg.meta.clean.api import CleanAPI from cg.meta.clean.clean_flow_cells import CleanFlowCellAPI @@ -81,7 +81,7 @@ def hk_alignment_files( ) -> None: """Clean up alignment files in Housekeeper bundle.""" housekeeper_api: HousekeeperAPI = context.housekeeper_api - for tag in ALIGNMENT_FILE_TAGS: + for tag in AlignmentFileTag.file_tags(): tag_files = set(housekeeper_api.get_files(bundle=bundle, tags=[tag])) if not tag_files: @@ -121,7 +121,7 @@ def scout_finished_cases( """Clean up of solved and archived Scout cases.""" scout_api: ScoutAPI = context.obj.scout_api bundles: list[str] = [] - for status in [ScoutTag.ARCHIVED.value, ScoutTag.SOLVED.value]: + for status in [ScoutTag.ARCHIVED, ScoutTag.SOLVED]: cases: list[ScoutExportCase] = scout_api.get_cases(status=status, reruns=False) cases_added: int = 0 for case in cases: diff --git a/cg/cli/compress/helpers.py b/cg/cli/compress/helpers.py index 135d452116..ecb8051f61 100644 --- a/cg/cli/compress/helpers.py +++ b/cg/cli/compress/helpers.py @@ -10,7 +10,7 @@ from cg.apps.housekeeper.hk import HousekeeperAPI from cg.constants.compression import CRUNCHY_MIN_GB_PER_PROCESS, MAX_READS_PER_GB -from cg.constants.slurm import Slurm +from cg.constants.slurm import SlurmProcessing from cg.exc import CaseNotFoundError from cg.meta.compress import CompressAPI from cg.meta.compress.files import get_spring_paths @@ -51,7 +51,7 @@ def get_fastq_individuals(store: Store, case_id: str = None) -> Iterator[str]: def set_memory_according_to_reads( sample_id: str, sample_reads: int | None = None, sample_process_mem: int | None = None ) -> int | None: - """Set SLURM sample process memory depending on number of sample reads if sample_process_mem is not set.""" + """Set SLURM sample process memory depending on the number of sample reads if sample_process_mem is not set.""" if sample_process_mem: return sample_process_mem if not sample_reads: @@ -60,9 +60,9 @@ def set_memory_according_to_reads( sample_process_mem: int = ceil((sample_reads / MAX_READS_PER_GB)) if sample_process_mem < CRUNCHY_MIN_GB_PER_PROCESS: return CRUNCHY_MIN_GB_PER_PROCESS - if CRUNCHY_MIN_GB_PER_PROCESS <= sample_process_mem < Slurm.MAX_NODE_MEMORY.value: + if CRUNCHY_MIN_GB_PER_PROCESS <= sample_process_mem < SlurmProcessing.MAX_NODE_MEMORY: return sample_process_mem - return Slurm.MAX_NODE_MEMORY.value + return SlurmProcessing.MAX_NODE_MEMORY def update_compress_api( diff --git a/cg/cli/set/base.py b/cg/cli/set/base.py index 69987bc4e2..15c6c81404 100644 --- a/cg/cli/set/base.py +++ b/cg/cli/set/base.py @@ -8,7 +8,7 @@ from cg.cli.set.case import set_case from cg.cli.set.cases import set_cases -from cg.constants import FLOWCELL_STATUS +from cg.constants import FlowCellStatus from cg.exc import LimsDataError from cg.models.cg_config import CGConfig from cg.store import Store @@ -283,7 +283,7 @@ def _update_comment(comment, obj): @set_cmd.command() -@click.option("-s", "--status", type=click.Choice(FLOWCELL_STATUS)) +@click.option("-s", "--status", type=click.Choice(FlowCellStatus.statuses())) @click.argument("flow_cell_name") @click.pass_obj def flowcell(context: CGConfig, flow_cell_name: str, status: str | None): diff --git a/cg/cli/set/case.py b/cg/cli/set/case.py index a4a73d9c9d..6f8b5034b4 100644 --- a/cg/cli/set/case.py +++ b/cg/cli/set/case.py @@ -3,7 +3,8 @@ import click -from cg.constants import CASE_ACTIONS, DataDelivery, Pipeline, Priority +from cg.constants import DataDelivery, Pipeline, Priority +from cg.constants.constants import CaseActions from cg.models.cg_config import CGConfig from cg.store import Store from cg.store.models import Case, Customer, Panel @@ -13,7 +14,7 @@ @click.command("case") -@click.option("-a", "--action", type=click.Choice(CASE_ACTIONS), help="update case action") +@click.option("-a", "--action", type=click.Choice(CaseActions.actions()), help="update case action") @click.option("-c", "--customer-id", type=click.STRING, help="update customer") @click.option( "-d", diff --git a/cg/cli/set/cases.py b/cg/cli/set/cases.py index cdf388aeb8..b28bc52f28 100644 --- a/cg/cli/set/cases.py +++ b/cg/cli/set/cases.py @@ -3,7 +3,8 @@ import click from cg.cli.set.case import set_case -from cg.constants import CASE_ACTIONS, Priority +from cg.constants import Priority +from cg.constants.constants import CaseActions from cg.store import Store from cg.store.models import Case, Sample from cg.utils.click.EnumChoice import EnumChoice @@ -40,7 +41,7 @@ def _get_cases(identifiers: click.Tuple([str, str]), store: Store) -> list[Case] help="Give an identifier on sample and the value to use it with, e.g. --sample-identifier " "name Prov52", ) -@click.option("-a", "--action", type=click.Choice(CASE_ACTIONS), help="update case action") +@click.option("-a", "--action", type=click.Choice(CaseActions.actions()), help="update case action") @click.option("-c", "--customer-id", type=click.STRING, help="update customer") @click.option("-g", "--panel", "panel_abbreviations", multiple=True, help="update gene panels") @click.option( diff --git a/cg/cli/upload/clinical_delivery.py b/cg/cli/upload/clinical_delivery.py index 6f48c8295c..33c3b65e00 100644 --- a/cg/cli/upload/clinical_delivery.py +++ b/cg/cli/upload/clinical_delivery.py @@ -6,10 +6,9 @@ import click from cg.apps.tb import TrailblazerAPI -from cg.constants import EXIT_FAIL, EXIT_SUCCESS, Pipeline +from cg.constants import EXIT_FAIL, EXIT_SUCCESS, Pipeline, Priority from cg.constants.constants import DRY_RUN from cg.constants.delivery import PIPELINE_ANALYSIS_TAG_MAP -from cg.constants.priority import PRIORITY_TO_SLURM_QOS from cg.constants.tb import AnalysisTypes from cg.meta.deliver import DeliverAPI from cg.meta.rsync import RsyncAPI @@ -70,7 +69,7 @@ def upload_clinical_delivery(context: click.Context, case_id: str, dry_run: bool analysis_type=AnalysisTypes.OTHER, config_path=rsync_api.trailblazer_config_path.as_posix(), out_dir=rsync_api.log_dir.as_posix(), - slurm_quality_of_service=PRIORITY_TO_SLURM_QOS[case.priority], + slurm_quality_of_service=Priority.priority_to_slurm_qos().get(case.priority), data_analysis=Pipeline.RSYNC, ticket=case.latest_ticket, ) diff --git a/cg/cli/workflow/rnafusion/options.py b/cg/cli/workflow/rnafusion/options.py index 91ccefa02d..41564dfc08 100644 --- a/cg/cli/workflow/rnafusion/options.py +++ b/cg/cli/workflow/rnafusion/options.py @@ -13,7 +13,7 @@ OPTION_STRANDEDNESS = click.option( "--strandedness", type=str, - default=Strandedness.REVERSE.value, + default=Strandedness.REVERSE, show_default=True, help="Strandedness: forward, unstranded or reverse (default)", ) diff --git a/cg/constants/__init__.py b/cg/constants/__init__.py index f4ef21472d..fca01ccdd6 100644 --- a/cg/constants/__init__.py +++ b/cg/constants/__init__.py @@ -1,15 +1,17 @@ """Import all constants here for easy access""" -from cg.constants.compression import FASTQ_DELTA, FASTQ_FIRST_READ_SUFFIX, FASTQ_SECOND_READ_SUFFIX +from cg.constants.compression import ( + FASTQ_DELTA, + FASTQ_FIRST_READ_SUFFIX, + FASTQ_SECOND_READ_SUFFIX, +) from cg.constants.constants import ( CAPTUREKIT_CANCER_OPTIONS, CAPTUREKIT_OPTIONS, - CASE_ACTIONS, COLLABORATORS, COMBOS, CONTAINER_OPTIONS, DEFAULT_CAPTURE_KIT, - FLOWCELL_STATUS, PREP_CATEGORIES, SEX_OPTIONS, STATUS_OPTIONS, @@ -18,7 +20,11 @@ FlowCellStatus, ) from cg.constants.gene_panel import GenePanelMasterList -from cg.constants.housekeeper_tags import HK_FASTQ_TAGS, HK_MULTIQC_HTML_TAG, SequencingFileTag +from cg.constants.housekeeper_tags import ( + HK_FASTQ_TAGS, + HK_MULTIQC_HTML_TAG, + SequencingFileTag, +) from cg.constants.paths import TMP_DIR from cg.constants.priority import Priority from cg.constants.process import EXIT_FAIL, EXIT_SUCCESS diff --git a/cg/constants/bcl_convert_metrics.py b/cg/constants/bcl_convert_metrics.py index 91dd6d8b39..476b110370 100644 --- a/cg/constants/bcl_convert_metrics.py +++ b/cg/constants/bcl_convert_metrics.py @@ -1,6 +1,6 @@ """This module contains constants for the BCLConvert metrics files.""" -from enum import Enum +from enum import StrEnum from cg.constants.demultiplexing import ( BclConverter, @@ -9,7 +9,7 @@ ) -class BclConvertQualityMetricsColumnNames(Enum): +class BclConvertQualityMetricsColumnNames(StrEnum): """Column names for the BCLConvert quality metrics file.""" LANE: str = "Lane" @@ -18,32 +18,32 @@ class BclConvertQualityMetricsColumnNames(Enum): Q30_BASES_PERCENT: str = "% Q30" -SAMPLE_SHEET_HEADER = { +SAMPLE_SHEET_HEADER: dict[str, str] = { BclConverter.BCL2FASTQ: ",".join( [ column - for column in SampleSheetBcl2FastqSections.Data.COLUMN_NAMES.value + for column in SampleSheetBcl2FastqSections.Data.column_names() if column != "index2" ] ), BclConverter.BCLCONVERT: ",".join( [ column - for column in SampleSheetBCLConvertSections.Data.COLUMN_NAMES.value + for column in SampleSheetBCLConvertSections.Data.column_names() if column != "index2" ] ), BclConverter.DRAGEN: ",".join( [ column - for column in SampleSheetBCLConvertSections.Data.COLUMN_NAMES.value + for column in SampleSheetBCLConvertSections.Data.column_names() if column != "index2" ] ), } -class BclConvertDemuxMetricsColumnNames(Enum): +class BclConvertDemuxMetricsColumnNames(StrEnum): """Column names for the BCLConvert demultiplexing metrics file.""" LANE: str = "Lane" @@ -51,6 +51,6 @@ class BclConvertDemuxMetricsColumnNames(Enum): READ_PAIR_COUNT: str = "# Reads" -DEMUX_METRICS_FILE_NAME = "Demultiplex_Stats.csv" -QUALITY_METRICS_FILE_NAME = "Quality_Metrics.csv" -ADAPTER_METRICS_FILE_NAME = "Adapter_Metrics.csv" +DEMUX_METRICS_FILE_NAME: str = "Demultiplex_Stats.csv" +QUALITY_METRICS_FILE_NAME: str = "Quality_Metrics.csv" +ADAPTER_METRICS_FILE_NAME: str = "Adapter_Metrics.csv" diff --git a/cg/constants/constants.py b/cg/constants/constants.py index 8e3f20cba9..c6817aab3d 100644 --- a/cg/constants/constants.py +++ b/cg/constants/constants.py @@ -38,8 +38,10 @@ class CaseActions(StrEnum): HOLD: str = "hold" RUNNING: str = "running" + @classmethod + def actions(cls) -> list[str]: + return list(cls) -CASE_ACTIONS = [action.value for action in CaseActions] COLLABORATORS = ("cust000", "cust002", "cust003", "cust004", "cust042") @@ -63,8 +65,9 @@ class FlowCellStatus(StrEnum): PROCESSING: str = "processing" RETRIEVED: str = "retrieved" - -FLOWCELL_STATUS = [status.value for status in FlowCellStatus] + @classmethod + def statuses(cls) -> list[str]: + return list(cls) class AnalysisType(StrEnum): diff --git a/cg/constants/demultiplexing.py b/cg/constants/demultiplexing.py index a0b021e8fa..0231667374 100644 --- a/cg/constants/demultiplexing.py +++ b/cg/constants/demultiplexing.py @@ -1,5 +1,5 @@ """Constants related to demultiplexing.""" -from enum import Enum, StrEnum +from enum import StrEnum from pathlib import Path import click @@ -80,12 +80,18 @@ class RunParametersXMLNodes(StrEnum): class SampleSheetBcl2FastqSections: """Class with all necessary constants for building a NovaSeqX sample sheet.""" - class Settings(Enum): + class Settings(StrEnum): HEADER: str = "[Settings]" - BARCODE_MISMATCH_INDEX1: list[str] = ["BarcodeMismatchesIndex1", "0"] - BARCODE_MISMATCH_INDEX2: list[str] = ["BarcodeMismatchesIndex2", "0"] - class Data(Enum): + @classmethod + def barcode_mismatch_index_1(cls) -> list[str]: + return ["BarcodeMismatchesIndex1", "0"] + + @classmethod + def barcode_mismatch_index_2(cls) -> list[str]: + return ["BarcodeMismatchesIndex2", "0"] + + class Data(StrEnum): HEADER: str = "[Data]" FLOW_CELL_ID: str = "FCID" LANE: str = "Lane" @@ -99,34 +105,45 @@ class Data(Enum): OPERATOR: str = "Operator" SAMPLE_PROJECT_BCL2FASTQ: str = "Project" - COLUMN_NAMES: list[str] = [ - FLOW_CELL_ID, - LANE, - SAMPLE_INTERNAL_ID_BCL2FASTQ, - SAMPLE_REFERENCE, - INDEX_1, - INDEX_2, - SAMPLE_NAME, - CONTROL, - RECIPE, - OPERATOR, - SAMPLE_PROJECT_BCL2FASTQ, - ] + @classmethod + def column_names(cls) -> list[str]: + return [ + cls.FLOW_CELL_ID, + cls.LANE, + cls.SAMPLE_INTERNAL_ID_BCL2FASTQ, + cls.SAMPLE_REFERENCE, + cls.INDEX_1, + cls.INDEX_2, + cls.SAMPLE_NAME, + cls.CONTROL, + cls.RECIPE, + cls.OPERATOR, + cls.SAMPLE_PROJECT_BCL2FASTQ, + ] class SampleSheetBCLConvertSections: """Class with all necessary constants for building a version 2 sample sheet.""" - class Header(Enum): + class Header(StrEnum): HEADER: str = "[Header]" - FILE_FORMAT: list[str] = ["FileFormatVersion", "2"] RUN_NAME: str = "RunName" INSTRUMENT_PLATFORM_TITLE: str = "InstrumentPlatform" - INSTRUMENT_PLATFORM_VALUE: dict[str, str] = { - Sequencers.NOVASEQ: "NovaSeq6000", - Sequencers.NOVASEQX: "NovaSeqXSeries", - } - INDEX_ORIENTATION_FORWARD: list[str] = ["IndexOrientation", "Forward"] + + @classmethod + def file_format(cls) -> list[str]: + return ["FileFormatVersion", "2"] + + @classmethod + def instrument_platform_sequencer(cls) -> dict[str, str]: + return { + Sequencers.NOVASEQ: "NovaSeq6000", + Sequencers.NOVASEQX: "NovaSeqXSeries", + } + + @classmethod + def index_orientation_forward(cls) -> list[str]: + return ["IndexOrientation", "Forward"] class Reads(StrEnum): HEADER: str = "[Reads]" @@ -135,12 +152,18 @@ class Reads(StrEnum): INDEX_CYCLES_1: str = "Index1Cycles" INDEX_CYCLES_2: str = "Index2Cycles" - class Settings(Enum): + class Settings(StrEnum): HEADER: str = "[BCLConvert_Settings]" - SOFTWARE_VERSION: list[str] = ["SoftwareVersion", "4.1.7"] - FASTQ_COMPRESSION_FORMAT: list[str] = ["FastqCompressionFormat", "gzip"] - class Data(Enum): + @classmethod + def software_version(cls) -> list[str]: + return ["SoftwareVersion", "4.1.7"] + + @classmethod + def fastq_compression_format(cls) -> list[str]: + return ["FastqCompressionFormat", "gzip"] + + class Data(StrEnum): HEADER: str = "[BCLConvert_Data]" LANE: str = "Lane" SAMPLE_INTERNAL_ID: str = "Sample_ID" @@ -152,17 +175,19 @@ class Data(Enum): BARCODE_MISMATCHES_1: str = "BarcodeMismatchesIndex1" BARCODE_MISMATCHES_2: str = "BarcodeMismatchesIndex2" - COLUMN_NAMES: list[str] = [ - LANE, - SAMPLE_INTERNAL_ID, - INDEX_1, - INDEX_2, - OVERRIDE_CYCLES, - ADAPTER_READ_1, - ADAPTER_READ_2, - BARCODE_MISMATCHES_1, - BARCODE_MISMATCHES_2, - ] + @classmethod + def column_names(cls) -> list[str]: + return [ + cls.LANE, + cls.SAMPLE_INTERNAL_ID, + cls.INDEX_1, + cls.INDEX_2, + cls.OVERRIDE_CYCLES, + cls.ADAPTER_READ_1, + cls.ADAPTER_READ_2, + cls.BARCODE_MISMATCHES_1, + cls.BARCODE_MISMATCHES_2, + ] OPTION_BCL_CONVERTER = click.option( @@ -175,7 +200,7 @@ class Data(Enum): ) -DEMUX_STATS_PATH = { +DEMUX_STATS_PATH: dict[str, dict[str, Path | None]] = { "bcl2fastq": { "demultiplexing_stats": Path("Stats", "DemultiplexingStats.xml"), "conversion_stats": Path("Stats", "ConversionStats.xml"), @@ -190,9 +215,9 @@ class Data(Enum): }, } -BCL2FASTQ_METRICS_DIRECTORY_NAME = "Stats" -BCL2FASTQ_METRICS_FILE_NAME = "Stats.json" -DRAGEN_PASSED_FILTER_PCT = 100.00000 -FASTQ_FILE_SUFFIXES = [".fastq", ".gz"] -INDEX_CHECK = "indexcheck" -UNDETERMINED = "Undetermined" +BCL2FASTQ_METRICS_DIRECTORY_NAME: str = "Stats" +BCL2FASTQ_METRICS_FILE_NAME: str = "Stats.json" +DRAGEN_PASSED_FILTER_PCT: float = 100.00000 +FASTQ_FILE_SUFFIXES: list[str] = [".fastq", ".gz"] +INDEX_CHECK: str = "indexcheck" +UNDETERMINED: str = "Undetermined" diff --git a/cg/constants/gene_panel.py b/cg/constants/gene_panel.py index 0d7402b02d..dc565eafc3 100644 --- a/cg/constants/gene_panel.py +++ b/cg/constants/gene_panel.py @@ -3,8 +3,8 @@ from enum import StrEnum -GENOME_BUILD_37 = "37" -GENOME_BUILD_38 = "GRCh38" +GENOME_BUILD_37: str = "37" +GENOME_BUILD_38: str = "GRCh38" class GenePanelMasterList(StrEnum): @@ -42,9 +42,5 @@ class GenePanelMasterList(StrEnum): @classmethod def get_panel_names(cls, panels=None) -> list[str]: - """Return requested panel names from Master list, or all panels if none are specified.""" - return ( - [panel_name.value for panel_name in panels] - if panels - else list(map(lambda panel: panel.value, cls)) - ) + """Return requested panel names from the Master list, or all panels if none are specified.""" + return list(panels) if panels else list(cls) diff --git a/cg/constants/housekeeper_tags.py b/cg/constants/housekeeper_tags.py index ff584e766a..ebd72b906e 100644 --- a/cg/constants/housekeeper_tags.py +++ b/cg/constants/housekeeper_tags.py @@ -16,8 +16,9 @@ class AlignmentFileTag(StrEnum): CRAM_CRAI: str = "crai" CRAM_INDEX: str = "cram-index" - -ALIGNMENT_FILE_TAGS: list[str] = [tag.value for tag in AlignmentFileTag] + @classmethod + def file_tags(cls) -> list[str]: + return list(cls) class ArchiveTag(StrEnum): diff --git a/cg/constants/indexes.py b/cg/constants/indexes.py deleted file mode 100644 index 28893ef08a..0000000000 --- a/cg/constants/indexes.py +++ /dev/null @@ -1,9 +0,0 @@ -"""Constants for accessing elements in arrays""" -from enum import Enum - - -class ListIndexes(Enum): - """indexes used when accessing elements of a list""" - - FIRST: int = 0 - LAST: int = -1 diff --git a/cg/constants/priority.py b/cg/constants/priority.py index 41c5e62084..42503e14bb 100644 --- a/cg/constants/priority.py +++ b/cg/constants/priority.py @@ -25,14 +25,15 @@ class Priority(IntEnum): express: int = 3 clinical_trials: int = 4 - -PRIORITY_TO_SLURM_QOS = { - Priority.research: SlurmQos.LOW, - Priority.standard: SlurmQos.NORMAL, - Priority.priority: SlurmQos.HIGH, - Priority.express: SlurmQos.EXPRESS, - Priority.clinical_trials: SlurmQos.NORMAL, -} + @classmethod + def priority_to_slurm_qos(cls) -> dict[int, str]: + return { + Priority.research: SlurmQos.LOW, + Priority.standard: SlurmQos.NORMAL, + Priority.priority: SlurmQos.HIGH, + Priority.express: SlurmQos.EXPRESS, + Priority.clinical_trials: SlurmQos.NORMAL, + } class SlurmAccount(StrEnum): diff --git a/cg/constants/slurm.py b/cg/constants/slurm.py index 502ca1509b..99f1570ecf 100644 --- a/cg/constants/slurm.py +++ b/cg/constants/slurm.py @@ -1,6 +1,9 @@ -from enum import Enum +from enum import IntEnum, StrEnum -class Slurm(Enum): +class Slurm(StrEnum): PARTITION: str = "partition" + + +class SlurmProcessing(IntEnum): MAX_NODE_MEMORY: int = 180 diff --git a/cg/constants/subject.py b/cg/constants/subject.py index 9e7ea8a63b..bbd28b37be 100644 --- a/cg/constants/subject.py +++ b/cg/constants/subject.py @@ -1,4 +1,4 @@ -from enum import Enum, IntEnum, StrEnum +from enum import IntEnum, StrEnum class Gender(StrEnum): @@ -15,9 +15,6 @@ class PhenotypeStatus(StrEnum): AFFECTED = "affected" MISSING = "" - def __repr__(self): - return self.value - class PlinkPhenotypeStatus(IntEnum): UNKNOWN = 0 @@ -25,17 +22,11 @@ class PlinkPhenotypeStatus(IntEnum): AFFECTED = 2 -class PlinkGender(str, Enum): - UNKNOWN = 0 - MALE = 1 - FEMALE = 2 - - def __str__(self) -> str: - return str.__str__(self.value) - +class PlinkGender(StrEnum): + UNKNOWN = str(0) + MALE = str(1) + FEMALE = str(2) -class RelationshipStatus(str, Enum): - HAS_NO_PARENT = 0 - def __str__(self) -> str: - return str.__str__(self.value) +class RelationshipStatus(StrEnum): + HAS_NO_PARENT = str(0) diff --git a/cg/meta/backup/backup.py b/cg/meta/backup/backup.py index d3e867188d..daa5c18f1a 100644 --- a/cg/meta/backup/backup.py +++ b/cg/meta/backup/backup.py @@ -9,7 +9,6 @@ from cg.constants.backup import MAX_PROCESSING_FLOW_CELLS from cg.constants.constants import FileExtensions, FlowCellStatus from cg.constants.demultiplexing import DemultiplexingDirsAndFiles -from cg.constants.indexes import ListIndexes from cg.constants.symbols import NEW_LINE from cg.exc import ChecksumFailedError, PdcError, PdcNoFilesMatchingSearchError from cg.meta.backup.pdc import PdcAPI @@ -264,7 +263,7 @@ def get_archived_flow_cell_path(cls, dsmc_output: list[str]) -> Path | None: if FileExtensions.TAR in row and FileExtensions.GZIP in row and FileExtensions.GPG in row - ][ListIndexes.FIRST.value] + ][0] archived_flow_cell = Path(flow_cell_line.split()[4]) if archived_flow_cell: @@ -280,7 +279,7 @@ def get_archived_encryption_key_path(cls, dsmc_output: list[str]) -> Path | None if FileExtensions.KEY in row and FileExtensions.GPG in row and FileExtensions.GZIP not in row - ][ListIndexes.FIRST.value] + ][0] archived_encryption_key = Path(encryption_key_line.split()[4]) if archived_encryption_key: diff --git a/cg/meta/observations/observations_api.py b/cg/meta/observations/observations_api.py index 80f1f0ada4..39d485c01f 100644 --- a/cg/meta/observations/observations_api.py +++ b/cg/meta/observations/observations_api.py @@ -101,7 +101,7 @@ def update_statusdb_loqusdb_id(self, samples: list[Case], loqusdb_id: str | None def check_customer_loqusdb_permissions(self, customer: Customer) -> None: """Verifies that the customer is whitelisted for Loqusdb uploads.""" - if customer.internal_id not in [cust_id.value for cust_id in self.get_loqusdb_customers()]: + if customer.internal_id not in [cust_id for cust_id in self.get_loqusdb_customers()]: LOG.error( f"Customer {customer.internal_id} is not whitelisted for Loqusdb uploads. Cancelling upload." ) diff --git a/cg/meta/rsync/rsync_api.py b/cg/meta/rsync/rsync_api.py index 8304386ad8..8e19977059 100644 --- a/cg/meta/rsync/rsync_api.py +++ b/cg/meta/rsync/rsync_api.py @@ -39,7 +39,7 @@ def __init__(self, config: CGConfig): @property def slurm_quality_of_service(self) -> str: """Return the slurm quality of service depending on the slurm account.""" - return SlurmQos.HIGH if self.account == SlurmAccount.PRODUCTION.value else SlurmQos.LOW + return SlurmQos.HIGH if self.account == SlurmAccount.PRODUCTION else SlurmQos.LOW @property def trailblazer_config_path(self) -> Path: diff --git a/cg/meta/upload/scout/mip_config_builder.py b/cg/meta/upload/scout/mip_config_builder.py index 0a141efd2d..40009bbeb5 100644 --- a/cg/meta/upload/scout/mip_config_builder.py +++ b/cg/meta/upload/scout/mip_config_builder.py @@ -90,12 +90,12 @@ def build_config_sample(self, case_sample: CaseSample) -> ScoutMipIndividual: config_sample.father = ( case_sample.father.internal_id if case_sample.father - else RelationshipStatus.HAS_NO_PARENT.value + else RelationshipStatus.HAS_NO_PARENT ) config_sample.mother = ( case_sample.mother.internal_id if case_sample.mother - else RelationshipStatus.HAS_NO_PARENT.value + else RelationshipStatus.HAS_NO_PARENT ) return config_sample diff --git a/cg/meta/workflow/analysis.py b/cg/meta/workflow/analysis.py index d4e1b2e86c..8f27973c23 100644 --- a/cg/meta/workflow/analysis.py +++ b/cg/meta/workflow/analysis.py @@ -9,9 +9,8 @@ from housekeeper.store.models import Bundle, Version from cg.apps.environ import environ_email -from cg.constants import CASE_ACTIONS, EXIT_FAIL, EXIT_SUCCESS, Pipeline, Priority +from cg.constants import EXIT_FAIL, EXIT_SUCCESS, Pipeline, Priority from cg.constants.constants import AnalysisType, CaseActions, WorkflowManager -from cg.constants.priority import PRIORITY_TO_SLURM_QOS from cg.exc import AnalysisNotReadyError, BundleAlreadyAddedError, CgDataError, CgError from cg.meta.meta import MetaAPI from cg.meta.workflow.fastq import FastqHandler @@ -79,13 +78,13 @@ def verify_case_path_exists(self, case_id: str) -> None: def get_priority_for_case(self, case_id: str) -> int: """Get priority from the status db case priority""" - case_obj: Case = self.status_db.get_case_by_internal_id(internal_id=case_id) - return case_obj.priority.value or Priority.research + case: Case = self.status_db.get_case_by_internal_id(internal_id=case_id) + return case.priority or Priority.research def get_slurm_qos_for_case(self, case_id: str) -> str: """Get Quality of service (SLURM QOS) for the case.""" priority: int = self.get_priority_for_case(case_id=case_id) - return PRIORITY_TO_SLURM_QOS[priority] + return Priority.priority_to_slurm_qos().get(priority) def get_workflow_manager(self) -> str: """Get workflow manager for a given pipeline.""" @@ -233,9 +232,9 @@ def set_statusdb_action(self, case_id: str, action: str | None, dry_run: bool = if dry_run: LOG.info(f"Dry-run: Action {action} would be set for case {case_id}") return - if action in [None, *CASE_ACTIONS]: - case_obj: Case = self.status_db.get_case_by_internal_id(internal_id=case_id) - case_obj.action = action + if action in [None, *CaseActions.actions()]: + case: Case = self.status_db.get_case_by_internal_id(internal_id=case_id) + case.action = action self.status_db.session.commit() LOG.info("Action %s set for case %s", action, case_id) return diff --git a/cg/meta/workflow/balsamic.py b/cg/meta/workflow/balsamic.py index 4e91d55fd8..f20f459cc5 100644 --- a/cg/meta/workflow/balsamic.py +++ b/cg/meta/workflow/balsamic.py @@ -9,7 +9,6 @@ from cg.constants import Pipeline from cg.constants.constants import FileFormat, SampleType from cg.constants.housekeeper_tags import BalsamicAnalysisTag -from cg.constants.indexes import ListIndexes from cg.constants.observations import ObservationsFileWildcards from cg.constants.sequencing import Variants from cg.constants.subject import Gender @@ -272,7 +271,7 @@ def get_latest_pon_file(self, panel_bed: str) -> str | None: pon_list = Path(self.pon_path).glob(f"*{Path(panel_bed).stem}_{self.PON_file_suffix}") sorted_pon_files = sorted( pon_list, - key=lambda file: int(file.stem.split("_v")[ListIndexes.LAST.value]), + key=lambda file: int(file.stem.split("_v")[-1]), reverse=True, ) diff --git a/cg/meta/workflow/balsamic_pon.py b/cg/meta/workflow/balsamic_pon.py index 93d825e613..739c3d0a99 100644 --- a/cg/meta/workflow/balsamic_pon.py +++ b/cg/meta/workflow/balsamic_pon.py @@ -4,7 +4,6 @@ from pathlib import Path from cg.constants.constants import Pipeline -from cg.constants.indexes import ListIndexes from cg.exc import BalsamicStartError from cg.meta.workflow.balsamic import BalsamicAnalysisAPI from cg.models.cg_config import CGConfig @@ -64,9 +63,5 @@ def get_case_config_path(self, case_id: str) -> Path: def get_next_pon_version(self, panel_bed: str) -> str: """Returns the next PON version to be generated.""" latest_pon_file: str = self.get_latest_pon_file(panel_bed=panel_bed) - next_version = ( - int(Path(latest_pon_file).stem.split("_v")[ListIndexes.LAST.value]) + 1 - if latest_pon_file - else 1 - ) + next_version = int(Path(latest_pon_file).stem.split("_v")[-1]) + 1 if latest_pon_file else 1 return "v" + str(next_version) diff --git a/cg/meta/workflow/fluffy.py b/cg/meta/workflow/fluffy.py index 98b3110863..6d8ed462a4 100644 --- a/cg/meta/workflow/fluffy.py +++ b/cg/meta/workflow/fluffy.py @@ -1,7 +1,7 @@ import datetime as dt import logging import shutil -from enum import Enum +from enum import StrEnum from pathlib import Path from pydantic import BaseModel @@ -22,7 +22,7 @@ LOG = logging.getLogger(__name__) -class FluffySampleSheetHeaders(Enum): +class FluffySampleSheetHeaders(StrEnum): flow_cell_id: str = "FCID" lane: str = "Lane" sample_internal_id: str = "Sample_ID" @@ -38,6 +38,10 @@ class FluffySampleSheetHeaders(Enum): library_nM: str = "Library_nM" sequencing_date: str = "SequencingDate" + @classmethod + def headers(cls) -> list[str]: + return list(cls) + class FluffySample(BaseModel): flow_cell_id: str @@ -61,9 +65,8 @@ class FluffySampleSheet(BaseModel): def write_sample_sheet(self, out_path: Path) -> None: LOG.info(f"Writing fluffy sample sheet to {out_path}") - headers = [header.value for header in FluffySampleSheetHeaders] entries = [entry.model_dump().values() for entry in self.samples] - content = [headers] + entries + content = [FluffySampleSheetHeaders.headers()] + entries WriteFile.write_file_from_content(content, FileFormat.CSV, out_path) diff --git a/cg/store/api/find_business_data.py b/cg/store/api/find_business_data.py index a9279a1e26..fe9dbba5db 100644 --- a/cg/store/api/find_business_data.py +++ b/cg/store/api/find_business_data.py @@ -7,7 +7,6 @@ from cg.constants import FlowCellStatus, Pipeline from cg.constants.constants import PrepCategory, SampleType -from cg.constants.indexes import ListIndexes from cg.exc import CaseNotFoundError, CgError from cg.store.api.base import BaseHandler from cg.store.filters.status_analysis_filters import ( @@ -85,7 +84,7 @@ def get_application_by_case(self, case_id: str) -> Application: return ( self.get_case_by_internal_id(internal_id=case_id) - .links[ListIndexes.FIRST.value] + .links[0] .sample.application_version.application ) diff --git a/cg/store/api/status.py b/cg/store/api/status.py index 786ab8fb46..86dd69c31b 100644 --- a/cg/store/api/status.py +++ b/cg/store/api/status.py @@ -4,7 +4,7 @@ from sqlalchemy.orm import Query, Session from typing_extensions import Literal -from cg.constants import CASE_ACTIONS, FlowCellStatus, Pipeline +from cg.constants import FlowCellStatus, Pipeline from cg.constants.constants import CaseActions from cg.constants.invoice import CustomerNames from cg.store.api.base import BaseHandler @@ -201,7 +201,9 @@ def cases( return sorted(cases, key=lambda k: k["tat"], reverse=True) - def set_case_action(self, action: Literal[CASE_ACTIONS], case_internal_id: str) -> None: + def set_case_action( + self, action: Literal[CaseActions.actions()], case_internal_id: str + ) -> None: """Sets the action of provided cases to None or the given action.""" case: Case = self.get_case_by_internal_id(internal_id=case_internal_id) case.action = action diff --git a/cg/store/models.py b/cg/store/models.py index 67cb3a6f27..57b8c3cefe 100644 --- a/cg/store/models.py +++ b/cg/store/models.py @@ -7,16 +7,15 @@ from sqlalchemy.util import deprecated from cg.constants import ( - CASE_ACTIONS, - FLOWCELL_STATUS, PREP_CATEGORIES, SEX_OPTIONS, STATUS_OPTIONS, DataDelivery, + FlowCellStatus, Pipeline, Priority, ) -from cg.constants.constants import CONTROL_OPTIONS, PrepCategory +from cg.constants.constants import CONTROL_OPTIONS, CaseActions, PrepCategory Model = declarative_base() @@ -379,7 +378,7 @@ class Case(Model, PriorityMixin): __tablename__ = "case" __table_args__ = (UniqueConstraint("customer_id", "name", name="_customer_name_uc"),) - action = Column(types.Enum(*CASE_ACTIONS)) + action = Column(types.Enum(*CaseActions.actions())) _cohorts = Column(types.Text) comment = Column(types.Text) created_at = Column(types.DateTime, default=dt.datetime.now) @@ -559,7 +558,7 @@ class Flowcell(Model): sequencer_type = Column(types.Enum("hiseqga", "hiseqx", "novaseq", "novaseqx")) sequencer_name = Column(types.String(32)) sequenced_at = Column(types.DateTime) - status = Column(types.Enum(*FLOWCELL_STATUS), default="ondisk") + status = Column(types.Enum(*FlowCellStatus.statuses()), default="ondisk") archived_at = Column(types.DateTime) has_backup = Column(types.Boolean, nullable=False, default=False) updated_at = Column(types.DateTime, onupdate=dt.datetime.now) diff --git a/tests/apps/scout/test_scout_models.py b/tests/apps/scout/test_scout_models.py index d548bddfc2..132d039f2e 100644 --- a/tests/apps/scout/test_scout_models.py +++ b/tests/apps/scout/test_scout_models.py @@ -20,9 +20,7 @@ def test_validate_case_father_none(none_case_raw: dict): case_dict = case_obj.model_dump() # THEN assert father is set to string 0 - assert case_dict["individuals"][0][Pedigree.FATHER] == str( - RelationshipStatus.HAS_NO_PARENT.value - ) + assert case_dict["individuals"][0][Pedigree.FATHER] == RelationshipStatus.HAS_NO_PARENT # THEN assert that '_id' has been changed to 'id' assert "_id" not in case_dict @@ -41,9 +39,7 @@ def test_validate_case_father_int(none_case_raw: dict): case_dict = case_obj.model_dump() # THEN assert father is set to string 0 - assert case_dict["individuals"][0][Pedigree.FATHER] == str( - RelationshipStatus.HAS_NO_PARENT.value - ) + assert case_dict["individuals"][0][Pedigree.FATHER] == RelationshipStatus.HAS_NO_PARENT # THEN assert that '_id' has been changed to 'id' assert "_id" not in case_dict @@ -61,11 +57,11 @@ def test_validate_case_parents_none(none_case_raw: dict): case_obj = ScoutExportCase.model_validate(none_case_raw) # THEN assert father and mother is set to string 0 - assert case_obj.model_dump()["individuals"][0][Pedigree.FATHER] == str( - RelationshipStatus.HAS_NO_PARENT.value + assert ( + case_obj.model_dump()["individuals"][0][Pedigree.FATHER] == RelationshipStatus.HAS_NO_PARENT ) - assert case_obj.model_dump()["individuals"][0][Pedigree.MOTHER] == str( - RelationshipStatus.HAS_NO_PARENT.value + assert ( + case_obj.model_dump()["individuals"][0][Pedigree.MOTHER] == RelationshipStatus.HAS_NO_PARENT ) @@ -174,7 +170,7 @@ def test_set_parent_when_not_provided(): validated_parent: str = set_parent_if_missing(parent=parent) # THEN the returned string should have been set to RelationshipStatus.HAS_NO_PARENT - assert validated_parent == str(RelationshipStatus.HAS_NO_PARENT.value) + assert validated_parent == RelationshipStatus.HAS_NO_PARENT def test_set_gender_if_provided(): diff --git a/tests/cli/set/test_cli_set_flowcell.py b/tests/cli/set/test_cli_set_flowcell.py index 23a7562996..f1a6ac566e 100644 --- a/tests/cli/set/test_cli_set_flowcell.py +++ b/tests/cli/set/test_cli_set_flowcell.py @@ -2,7 +2,7 @@ from click.testing import CliRunner from cg.cli.set.base import flowcell -from cg.constants import FLOWCELL_STATUS +from cg.constants import FlowCellStatus from cg.models.cg_config import CGConfig from cg.store import Store from cg.store.models import Flowcell @@ -43,7 +43,7 @@ def test_set_flowcell_status( """Test that the updated flow_cell get the status we send in.""" # GIVEN a database with a flow cell flow_cell_name = helpers.add_flow_cell(base_store).name - status = FLOWCELL_STATUS[2] + status = FlowCellStatus.statuses()[2] flow_cell_query = base_store._get_query(table=Flowcell) assert flow_cell_query.first().status != status diff --git a/tests/store/api/find/test_find_business_data.py b/tests/store/api/find/test_find_business_data.py index d9057bff21..df5ad28621 100644 --- a/tests/store/api/find/test_find_business_data.py +++ b/tests/store/api/find/test_find_business_data.py @@ -7,7 +7,6 @@ from cg.constants import FlowCellStatus from cg.constants.constants import CaseActions, Pipeline -from cg.constants.indexes import ListIndexes from cg.exc import CgError from cg.store import Store from cg.store.models import ( @@ -358,7 +357,7 @@ def test_get_ready_made_library_expected_reads(case_id: str, rml_pool_store: Sto # GIVEN a case with a sample with an application version application_version: ApplicationVersion = ( rml_pool_store.get_case_by_internal_id(internal_id=case_id) - .links[ListIndexes.FIRST.value] + .links[0] .sample.application_version ) @@ -374,7 +373,7 @@ def test_get_application_by_case(case_id: str, rml_pool_store: Store): # GIVEN a case with a sample with an application version application_version: ApplicationVersion = ( rml_pool_store.get_case_by_internal_id(internal_id=case_id) - .links[ListIndexes.FIRST.value] + .links[0] .sample.application_version ) diff --git a/tests/store/api/status/test_store_api_status_cases.py b/tests/store/api/status/test_store_api_status_cases.py index db4cf540f8..a260e30a80 100644 --- a/tests/store/api/status/test_store_api_status_cases.py +++ b/tests/store/api/status/test_store_api_status_cases.py @@ -1,6 +1,7 @@ from datetime import datetime, timedelta -from cg.constants import CASE_ACTIONS, DataDelivery, Pipeline, Priority +from cg.constants import DataDelivery, Pipeline, Priority +from cg.constants.constants import CaseActions from cg.store import Store from cg.store.models import Analysis, Case, CaseSample @@ -752,10 +753,10 @@ def test_excluded_by_action(base_store: Store, helpers): """Test to that cases can be excluded by action""" # GIVEN a database with a case with an action - add_case(helpers, base_store, action=CASE_ACTIONS[0]) + add_case(helpers, base_store, action=CaseActions.actions()[0]) # WHEN getting active cases by action - cases = base_store.cases(case_action=CASE_ACTIONS[1]) + cases = base_store.cases(case_action=CaseActions.actions()[1]) # THEN cases should not contain this case assert not cases @@ -765,7 +766,7 @@ def test_included_by_action(base_store: Store, helpers): """Test to that cases can be included by action""" # GIVEN a database with a case with an action - new_case = add_case(helpers, base_store, action=CASE_ACTIONS[0]) + new_case = add_case(helpers, base_store, action=CaseActions.actions()[0]) # WHEN getting active cases by action cases = base_store.cases(case_action=new_case.action)