qq_lib.properties.transfer_mode
1# Released under MIT License. 2# Copyright (c) 2025-2026 Ladislav Bartos and Robert Vacha Lab 3 4import re 5from abc import ABC, abstractmethod 6from dataclasses import dataclass 7 8from qq_lib.core.error import QQError 9 10 11@dataclass(frozen=True) 12class TransferMode(ABC): 13 """ 14 Specifies when job data should be transferred from the working directory to 15 the input directory or archived from the working directory. 16 """ 17 18 @classmethod 19 def from_str(cls, s: str) -> "TransferMode": 20 """ 21 Convert a string to the corresponding TransferMode. 22 23 Args: 24 s (str): String representation of the transfer mode. 25 26 Returns: 27 TransferMode variant. 28 29 Raises: 30 QQError if the string corresponds to no transfer mode. 31 """ 32 match s.lower().strip(): 33 case "always": 34 return Always() 35 case "never": 36 return Never() 37 case "success": 38 return Success() 39 case "failure": 40 return Failure() 41 case _: 42 # if the string is a number (positive or negative) 43 if bool(re.match(r"^-?\d+$", s.strip())): 44 return ExitCode(int(s)) 45 46 raise QQError(f"Could not recognize a transfer mode variant '{s}'.") 47 48 @classmethod 49 def multi_from_str(cls, raw: str) -> list["TransferMode"]: 50 """ 51 Parse a string containing multiple transfer modes. 52 53 Args: 54 s: String containing transfer mode variants separated by a colon, comma, or space. 55 Example: "success:42", "1,2,3", or "failure success". 56 57 Returns: 58 list[TransferMode]: A list of parsed transfer modes. 59 60 Raises: 61 QQError: If any of the individual mode strings cannot be recognized. 62 """ 63 mode_strings = re.split(r"[:,\s]+", raw.strip()) 64 mode_strings = [ms for ms in mode_strings if ms] 65 66 return [TransferMode.from_str(mode_str) for mode_str in mode_strings] 67 68 @abstractmethod 69 def should_transfer(self, exit_code: int) -> bool: 70 """ 71 Determine whether data should be transferred/archived based on the exit code. 72 73 Args: 74 exit_code: The exit code of the completed job. 75 76 Returns: 77 True if data should be transferred/archived, False otherwise. 78 """ 79 80 @abstractmethod 81 def to_str(self) -> str: 82 """ 83 Convert the TransferMode variant to its string representation. 84 85 Returns: 86 A string representation of the transfer mode variant. 87 """ 88 89 90@dataclass(frozen=True) 91class Always(TransferMode): 92 """ 93 Data are always transferred/archived regardless the job's exit code. 94 """ 95 96 def should_transfer(self, exit_code: int) -> bool: 97 _ = exit_code 98 return True 99 100 def to_str(self) -> str: 101 return "always" 102 103 104@dataclass(frozen=True) 105class Never(TransferMode): 106 """ 107 Data are never transferred/archived. 108 """ 109 110 def should_transfer(self, exit_code: int) -> bool: 111 _ = exit_code 112 return False 113 114 def to_str(self) -> str: 115 return "never" 116 117 118@dataclass(frozen=True) 119class Success(TransferMode): 120 """ 121 Data are transferred/archived only if the job completes successfully. 122 """ 123 124 def should_transfer(self, exit_code: int) -> bool: 125 return exit_code == 0 126 127 def to_str(self) -> str: 128 return "success" 129 130 131@dataclass(frozen=True) 132class Failure(TransferMode): 133 """ 134 Data are transferred/archived only if the job fails. 135 """ 136 137 def should_transfer(self, exit_code: int) -> bool: 138 return exit_code != 0 139 140 def to_str(self) -> str: 141 return "failure" 142 143 144@dataclass(frozen=True) 145class ExitCode(TransferMode): 146 """ 147 Data are transferred/archived only if the job exits with a specific code. 148 149 Attributes: 150 code: The exit code that triggers data transfer. 151 """ 152 153 code: int 154 155 def should_transfer(self, exit_code: int) -> bool: 156 return exit_code == self.code 157 158 def to_str(self) -> str: 159 return f"{self.code}"
12@dataclass(frozen=True) 13class TransferMode(ABC): 14 """ 15 Specifies when job data should be transferred from the working directory to 16 the input directory or archived from the working directory. 17 """ 18 19 @classmethod 20 def from_str(cls, s: str) -> "TransferMode": 21 """ 22 Convert a string to the corresponding TransferMode. 23 24 Args: 25 s (str): String representation of the transfer mode. 26 27 Returns: 28 TransferMode variant. 29 30 Raises: 31 QQError if the string corresponds to no transfer mode. 32 """ 33 match s.lower().strip(): 34 case "always": 35 return Always() 36 case "never": 37 return Never() 38 case "success": 39 return Success() 40 case "failure": 41 return Failure() 42 case _: 43 # if the string is a number (positive or negative) 44 if bool(re.match(r"^-?\d+$", s.strip())): 45 return ExitCode(int(s)) 46 47 raise QQError(f"Could not recognize a transfer mode variant '{s}'.") 48 49 @classmethod 50 def multi_from_str(cls, raw: str) -> list["TransferMode"]: 51 """ 52 Parse a string containing multiple transfer modes. 53 54 Args: 55 s: String containing transfer mode variants separated by a colon, comma, or space. 56 Example: "success:42", "1,2,3", or "failure success". 57 58 Returns: 59 list[TransferMode]: A list of parsed transfer modes. 60 61 Raises: 62 QQError: If any of the individual mode strings cannot be recognized. 63 """ 64 mode_strings = re.split(r"[:,\s]+", raw.strip()) 65 mode_strings = [ms for ms in mode_strings if ms] 66 67 return [TransferMode.from_str(mode_str) for mode_str in mode_strings] 68 69 @abstractmethod 70 def should_transfer(self, exit_code: int) -> bool: 71 """ 72 Determine whether data should be transferred/archived based on the exit code. 73 74 Args: 75 exit_code: The exit code of the completed job. 76 77 Returns: 78 True if data should be transferred/archived, False otherwise. 79 """ 80 81 @abstractmethod 82 def to_str(self) -> str: 83 """ 84 Convert the TransferMode variant to its string representation. 85 86 Returns: 87 A string representation of the transfer mode variant. 88 """
Specifies when job data should be transferred from the working directory to the input directory or archived from the working directory.
19 @classmethod 20 def from_str(cls, s: str) -> "TransferMode": 21 """ 22 Convert a string to the corresponding TransferMode. 23 24 Args: 25 s (str): String representation of the transfer mode. 26 27 Returns: 28 TransferMode variant. 29 30 Raises: 31 QQError if the string corresponds to no transfer mode. 32 """ 33 match s.lower().strip(): 34 case "always": 35 return Always() 36 case "never": 37 return Never() 38 case "success": 39 return Success() 40 case "failure": 41 return Failure() 42 case _: 43 # if the string is a number (positive or negative) 44 if bool(re.match(r"^-?\d+$", s.strip())): 45 return ExitCode(int(s)) 46 47 raise QQError(f"Could not recognize a transfer mode variant '{s}'.")
Convert a string to the corresponding TransferMode.
Arguments:
- s (str): String representation of the transfer mode.
Returns:
TransferMode variant.
Raises:
- QQError if the string corresponds to no transfer mode.
49 @classmethod 50 def multi_from_str(cls, raw: str) -> list["TransferMode"]: 51 """ 52 Parse a string containing multiple transfer modes. 53 54 Args: 55 s: String containing transfer mode variants separated by a colon, comma, or space. 56 Example: "success:42", "1,2,3", or "failure success". 57 58 Returns: 59 list[TransferMode]: A list of parsed transfer modes. 60 61 Raises: 62 QQError: If any of the individual mode strings cannot be recognized. 63 """ 64 mode_strings = re.split(r"[:,\s]+", raw.strip()) 65 mode_strings = [ms for ms in mode_strings if ms] 66 67 return [TransferMode.from_str(mode_str) for mode_str in mode_strings]
Parse a string containing multiple transfer modes.
Arguments:
- s: String containing transfer mode variants separated by a colon, comma, or space. Example: "success:42", "1,2,3", or "failure success".
Returns:
list[TransferMode]: A list of parsed transfer modes.
Raises:
- QQError: If any of the individual mode strings cannot be recognized.
69 @abstractmethod 70 def should_transfer(self, exit_code: int) -> bool: 71 """ 72 Determine whether data should be transferred/archived based on the exit code. 73 74 Args: 75 exit_code: The exit code of the completed job. 76 77 Returns: 78 True if data should be transferred/archived, False otherwise. 79 """
Determine whether data should be transferred/archived based on the exit code.
Arguments:
- exit_code: The exit code of the completed job.
Returns:
True if data should be transferred/archived, False otherwise.
81 @abstractmethod 82 def to_str(self) -> str: 83 """ 84 Convert the TransferMode variant to its string representation. 85 86 Returns: 87 A string representation of the transfer mode variant. 88 """
Convert the TransferMode variant to its string representation.
Returns:
A string representation of the transfer mode variant.
91@dataclass(frozen=True) 92class Always(TransferMode): 93 """ 94 Data are always transferred/archived regardless the job's exit code. 95 """ 96 97 def should_transfer(self, exit_code: int) -> bool: 98 _ = exit_code 99 return True 100 101 def to_str(self) -> str: 102 return "always"
Data are always transferred/archived regardless the job's exit code.
Determine whether data should be transferred/archived based on the exit code.
Arguments:
- exit_code: The exit code of the completed job.
Returns:
True if data should be transferred/archived, False otherwise.
Convert the TransferMode variant to its string representation.
Returns:
A string representation of the transfer mode variant.
Inherited Members
105@dataclass(frozen=True) 106class Never(TransferMode): 107 """ 108 Data are never transferred/archived. 109 """ 110 111 def should_transfer(self, exit_code: int) -> bool: 112 _ = exit_code 113 return False 114 115 def to_str(self) -> str: 116 return "never"
Data are never transferred/archived.
Determine whether data should be transferred/archived based on the exit code.
Arguments:
- exit_code: The exit code of the completed job.
Returns:
True if data should be transferred/archived, False otherwise.
Convert the TransferMode variant to its string representation.
Returns:
A string representation of the transfer mode variant.
Inherited Members
119@dataclass(frozen=True) 120class Success(TransferMode): 121 """ 122 Data are transferred/archived only if the job completes successfully. 123 """ 124 125 def should_transfer(self, exit_code: int) -> bool: 126 return exit_code == 0 127 128 def to_str(self) -> str: 129 return "success"
Data are transferred/archived only if the job completes successfully.
Determine whether data should be transferred/archived based on the exit code.
Arguments:
- exit_code: The exit code of the completed job.
Returns:
True if data should be transferred/archived, False otherwise.
Convert the TransferMode variant to its string representation.
Returns:
A string representation of the transfer mode variant.
Inherited Members
132@dataclass(frozen=True) 133class Failure(TransferMode): 134 """ 135 Data are transferred/archived only if the job fails. 136 """ 137 138 def should_transfer(self, exit_code: int) -> bool: 139 return exit_code != 0 140 141 def to_str(self) -> str: 142 return "failure"
Data are transferred/archived only if the job fails.
Determine whether data should be transferred/archived based on the exit code.
Arguments:
- exit_code: The exit code of the completed job.
Returns:
True if data should be transferred/archived, False otherwise.
Convert the TransferMode variant to its string representation.
Returns:
A string representation of the transfer mode variant.
Inherited Members
145@dataclass(frozen=True) 146class ExitCode(TransferMode): 147 """ 148 Data are transferred/archived only if the job exits with a specific code. 149 150 Attributes: 151 code: The exit code that triggers data transfer. 152 """ 153 154 code: int 155 156 def should_transfer(self, exit_code: int) -> bool: 157 return exit_code == self.code 158 159 def to_str(self) -> str: 160 return f"{self.code}"
Data are transferred/archived only if the job exits with a specific code.
Attributes:
- code: The exit code that triggers data transfer.
Determine whether data should be transferred/archived based on the exit code.
Arguments:
- exit_code: The exit code of the completed job.
Returns:
True if data should be transferred/archived, False otherwise.
Convert the TransferMode variant to its string representation.
Returns:
A string representation of the transfer mode variant.