xmipp3-installer 1.0.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 (70) hide show
  1. xmipp3_installer/__init__.py +1 -0
  2. xmipp3_installer/__main__.py +6 -0
  3. xmipp3_installer/api_client/api_client.py +50 -0
  4. xmipp3_installer/api_client/assembler/installation_info_assembler.py +181 -0
  5. xmipp3_installer/application/__init__.py +1 -0
  6. xmipp3_installer/application/cli/__init__.py +1 -0
  7. xmipp3_installer/application/cli/arguments/__init__.py +8 -0
  8. xmipp3_installer/application/cli/arguments/modes.py +130 -0
  9. xmipp3_installer/application/cli/arguments/params.py +76 -0
  10. xmipp3_installer/application/cli/cli.py +271 -0
  11. xmipp3_installer/application/cli/parsers/base_help_formatter.py +244 -0
  12. xmipp3_installer/application/cli/parsers/error_handler_parser.py +68 -0
  13. xmipp3_installer/application/cli/parsers/format.py +35 -0
  14. xmipp3_installer/application/cli/parsers/general_help_formatter.py +92 -0
  15. xmipp3_installer/application/cli/parsers/mode_help_formatter.py +115 -0
  16. xmipp3_installer/application/logger/__init__.py +0 -0
  17. xmipp3_installer/application/logger/errors.py +28 -0
  18. xmipp3_installer/application/logger/logger.py +230 -0
  19. xmipp3_installer/application/logger/predefined_messages.py +66 -0
  20. xmipp3_installer/application/user_interactions.py +16 -0
  21. xmipp3_installer/installer/__init__.py +1 -0
  22. xmipp3_installer/installer/constants/__init__.py +17 -0
  23. xmipp3_installer/installer/constants/paths.py +32 -0
  24. xmipp3_installer/installer/handlers/__init__.py +1 -0
  25. xmipp3_installer/installer/handlers/cmake/__init__.py +1 -0
  26. xmipp3_installer/installer/handlers/cmake/cmake_constants.py +27 -0
  27. xmipp3_installer/installer/handlers/cmake/cmake_handler.py +69 -0
  28. xmipp3_installer/installer/handlers/conda_handler.py +13 -0
  29. xmipp3_installer/installer/handlers/generic_package_handler.py +18 -0
  30. xmipp3_installer/installer/handlers/git_handler.py +185 -0
  31. xmipp3_installer/installer/handlers/shell_handler.py +114 -0
  32. xmipp3_installer/installer/handlers/versions_manager.py +98 -0
  33. xmipp3_installer/installer/installer_service.py +66 -0
  34. xmipp3_installer/installer/modes/__init__.py +1 -0
  35. xmipp3_installer/installer/modes/mode_all_executor.py +63 -0
  36. xmipp3_installer/installer/modes/mode_clean/__init__.py +1 -0
  37. xmipp3_installer/installer/modes/mode_clean/mode_clean_all_executor.py +44 -0
  38. xmipp3_installer/installer/modes/mode_clean/mode_clean_bin_executor.py +94 -0
  39. xmipp3_installer/installer/modes/mode_clean/mode_clean_executor.py +45 -0
  40. xmipp3_installer/installer/modes/mode_cmake/__init__.py +1 -0
  41. xmipp3_installer/installer/modes/mode_cmake/mode_cmake_executor.py +55 -0
  42. xmipp3_installer/installer/modes/mode_cmake/mode_compile_and_install_executor.py +49 -0
  43. xmipp3_installer/installer/modes/mode_cmake/mode_config_build_executor.py +64 -0
  44. xmipp3_installer/installer/modes/mode_config_executor.py +46 -0
  45. xmipp3_installer/installer/modes/mode_executor.py +43 -0
  46. xmipp3_installer/installer/modes/mode_get_sources_executor.py +132 -0
  47. xmipp3_installer/installer/modes/mode_git_executor.py +41 -0
  48. xmipp3_installer/installer/modes/mode_selector.py +25 -0
  49. xmipp3_installer/installer/modes/mode_sync/mode_add_model_executor.py +104 -0
  50. xmipp3_installer/installer/modes/mode_sync/mode_get_models_executor.py +51 -0
  51. xmipp3_installer/installer/modes/mode_sync/mode_sync_executor.py +48 -0
  52. xmipp3_installer/installer/modes/mode_sync/mode_test_executor.py +91 -0
  53. xmipp3_installer/installer/modes/mode_version_executor.py +164 -0
  54. xmipp3_installer/installer/orquestrator.py +37 -0
  55. xmipp3_installer/installer/urls.py +8 -0
  56. xmipp3_installer/repository/__init__.py +1 -0
  57. xmipp3_installer/repository/config.py +241 -0
  58. xmipp3_installer/repository/config_vars/__init__.py +0 -0
  59. xmipp3_installer/repository/config_vars/config_values_adapter.py +107 -0
  60. xmipp3_installer/repository/config_vars/default_values.py +36 -0
  61. xmipp3_installer/repository/config_vars/variables.py +48 -0
  62. xmipp3_installer/repository/invalid_config_line.py +15 -0
  63. xmipp3_installer/shared/file_operations.py +18 -0
  64. xmipp3_installer/shared/singleton.py +25 -0
  65. xmipp3_installer-1.0.0.dist-info/LICENSE +674 -0
  66. xmipp3_installer-1.0.0.dist-info/METADATA +729 -0
  67. xmipp3_installer-1.0.0.dist-info/RECORD +70 -0
  68. xmipp3_installer-1.0.0.dist-info/WHEEL +5 -0
  69. xmipp3_installer-1.0.0.dist-info/entry_points.txt +2 -0
  70. xmipp3_installer-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,241 @@
1
+ """### Contains the configuration file singleton that interact with the configuration file."""
2
+
3
+ import re
4
+ import os
5
+ from datetime import datetime
6
+ from typing import List, Optional, Tuple, Dict, Any
7
+
8
+ from xmipp3_installer.shared.singleton import Singleton
9
+ from xmipp3_installer.installer.constants import paths
10
+ from xmipp3_installer.application.logger.logger import logger
11
+ from xmipp3_installer.repository.config_vars import default_values, variables, config_values_adapter
12
+ from xmipp3_installer.repository.invalid_config_line import InvalidConfigLineError
13
+
14
+ class ConfigurationFileHandler(Singleton):
15
+ """
16
+ ### Configuration file class for loading and storing the installation configuration.
17
+ """
18
+ __COMMENT_ESCAPE = '#'
19
+ __ASSIGNMENT_SEPARATOR = '='
20
+ __LAST_MODIFIED_TEXT = "Config file automatically generated on"
21
+
22
+ def __init__(self, path: str=paths.CONFIG_FILE, show_errors: bool=True):
23
+ """
24
+ ### Constructor.
25
+
26
+ #### Params:
27
+ - path (str): Optional. Path to the configuration file.
28
+ """
29
+ self.__path = path
30
+ self.show_errors = show_errors
31
+ self.values = {}
32
+ self.read_config()
33
+ self.last_modified = self.__read_config_date()
34
+
35
+ def read_config(self):
36
+ """
37
+ ### Reads the config file and stores a dictionary with all the parsed variables.
38
+ """
39
+ file_lines = self.__get_file_content()
40
+ result = {}
41
+ for line_number, line in enumerate(file_lines):
42
+ new_result = self.__add_line_values(result.copy(), line, line_number + 1)
43
+ if new_result is None:
44
+ result = {}
45
+ break
46
+ result = new_result
47
+ self.values = {
48
+ **config_values_adapter.get_context_values_from_file_values(
49
+ default_values.CONFIG_DEFAULT_VALUES
50
+ ),
51
+ **config_values_adapter.get_context_values_from_file_values(
52
+ result,
53
+ show_warnings=self.show_errors
54
+ )
55
+ }
56
+
57
+ def write_config(self, overwrite: bool=False):
58
+ """
59
+ ### Writes a template config file with stored variables, leaving the rest with default values.
60
+
61
+ #### Params:
62
+ - overwrite (bool): Optional. If True, default values are written, overwriting the existing file.
63
+ """
64
+ if overwrite:
65
+ self.values = default_values.CONFIG_DEFAULT_VALUES
66
+ values = config_values_adapter.get_file_values_from_context_values(self.values.copy())
67
+ self.last_modified = datetime.today().strftime('%d-%m-%Y %H:%M.%S')
68
+
69
+ lines = ["##### TOGGLE SECTION #####\n"]
70
+ lines.append(f"# Activate or deactivate this features using values {default_values.ON}/{default_values.OFF}\n")
71
+ lines.extend(self.__get_section_lines(variables.TOGGLES, values))
72
+
73
+ lines.append("\n##### PACKAGE HOME SECTION #####\n")
74
+ lines.append("# Use this variables to use custom installation paths for the required packages.\n")
75
+ lines.append("# If left empty, CMake will search for those packages within your system.\n")
76
+ lines.extend(self.__get_section_lines(variables.LOCATIONS, values))
77
+
78
+ lines.append("\n##### COMPILATION FLAGS #####\n")
79
+ lines.append("# We recommend not modifying this variables unless you know what you are doing.\n")
80
+ lines.extend(self.__get_section_lines(variables.COMPILATION_FLAGS, values))
81
+
82
+ if values:
83
+ lines.append("\n##### UNKNOWN VARIABLES #####\n")
84
+ lines.append("# This variables were not expected, but are kept here in case they might be needed.\n")
85
+ lines.extend(self.__get_unkown_variable_lines(values))
86
+
87
+ lines.append(f"\n# {self.__LAST_MODIFIED_TEXT} {self.last_modified}\n")
88
+ with open(self.__path, 'w') as config_file:
89
+ config_file.writelines(lines)
90
+
91
+ def get_config_date(self) -> str:
92
+ """
93
+ ### Returns the date of the last modification of the configuration file.
94
+
95
+ #### Returns:
96
+ - (str): Date in dd-mm-yyyy format.
97
+ """
98
+ if not self.last_modified:
99
+ self.last_modified = self.__read_config_date()
100
+ return self.last_modified
101
+
102
+ def __get_file_content(self) -> List[str]:
103
+ """
104
+ ### Reads the whole unparsed content of the given file.
105
+
106
+ #### Returns:
107
+ - (list(str)): Content of the file, where each line is a string in the result list.
108
+ """
109
+ if not os.path.exists(self.__path):
110
+ return []
111
+ lines = []
112
+ with open(self.__path, "r") as config_file:
113
+ lines = config_file.readlines()
114
+ return lines
115
+
116
+ def __read_config_date(self) -> str:
117
+ """
118
+ ### Reads from the config file the date of its last modification.
119
+
120
+ #### Returns:
121
+ - (str): Date in dd-mm-yyyy format.
122
+ """
123
+ config_lines = self.__get_file_content()
124
+ for line in config_lines:
125
+ if self.__LAST_MODIFIED_TEXT not in line:
126
+ continue
127
+ match = re.search(r'\d{2}-\d{2}-\d{4} \d{2}:\d{2}.\d{2}', line)
128
+ if match:
129
+ return match.group()
130
+ return ""
131
+
132
+ def __add_line_values(self, config: Dict, line: str, line_number: int) -> Optional[Dict]:
133
+ """
134
+ ### Adds the config values present in the current line to the given dictionary.
135
+
136
+ #### Params:
137
+ - config (dict): Dictionary with all the present variables.
138
+ - line (str): Current line to extract values from.
139
+ - line_number (int): Line index in the list of lines that compose the file.
140
+
141
+ #### Returns:
142
+ - (dict | None): An updated dictionary with the newly obtained variable, or None if there was an error.
143
+ """
144
+ try:
145
+ key_value_pair = self.__parse_config_line(line, line_number)
146
+ except InvalidConfigLineError as error:
147
+ if self.show_errors:
148
+ logger(str(error))
149
+ config = {}
150
+ return
151
+ if key_value_pair:
152
+ key, value = key_value_pair
153
+ config[key] = value
154
+ return config
155
+
156
+ def __parse_config_line(self, line: str, line_number: int) -> Optional[Tuple[str, str]]:
157
+ """
158
+ ### Reads the given line from the config file and returns the key-value pair as a tuple.
159
+
160
+ #### Params:
161
+ - line_number (int): Line number inside the config file.
162
+ - line (str): Line to parse.
163
+
164
+ #### Returns:
165
+ - (tuple(str, str) | None): Tuple containing the read key-value pair if line contains valid data.
166
+
167
+ #### Raises:
168
+ - RuntimeError: Raised when a line has an invalid format and cannot be parsed.
169
+ """
170
+ line_without_comments = line.split(self.__COMMENT_ESCAPE, maxsplit=2)[0].strip()
171
+ if not line_without_comments:
172
+ return None
173
+
174
+ tokens = line_without_comments.split(self.__ASSIGNMENT_SEPARATOR, maxsplit=1)
175
+ if len(tokens) != 2:
176
+ raise InvalidConfigLineError(
177
+ InvalidConfigLineError.generate_error_message(
178
+ paths.CONFIG_FILE,
179
+ line_number,
180
+ line
181
+ )
182
+ )
183
+
184
+ return tokens[0].strip(), tokens[1].strip()
185
+
186
+ def __make_config_line(self, key: str, value: str, default_value: str) -> str:
187
+ """
188
+ ### Composes a config file line given a key-value pair to write.
189
+
190
+ #### Params:
191
+ - key (int): Name of the variable.
192
+ - value (str): Value of the variable found in the config file.
193
+ - default_value (str): Default value of the variable.
194
+
195
+ #### Returns:
196
+ - (str): String containing the appropiately formatted key-value pair.
197
+ """
198
+ default_value = '' if default_value is None else default_value
199
+ value = default_value if value is None else value
200
+ return f"{key}{self.__ASSIGNMENT_SEPARATOR}{value}" if key else ""
201
+
202
+ def __get_section_lines(self, section_type: str, config_variables: Dict[str, Any]) -> List[str]:
203
+ """
204
+ ### Returns the lines composed by the given section's variables in the dictionary, and deletes them from it.
205
+
206
+ #### Params:
207
+ - section_type (str): Section to extract variables from.
208
+ - config_variables (dict(str, any)): Dictionary containing all variables.
209
+
210
+ #### Returns:
211
+ - (list(str)): Config file lines created from the dictionary variables.
212
+ """
213
+ lines = []
214
+ for section_variable in variables.CONFIG_VARIABLES[section_type]:
215
+ lines.append(''.join([
216
+ self.__make_config_line(
217
+ section_variable,
218
+ config_variables.get(section_variable),
219
+ default_values.CONFIG_DEFAULT_VALUES[section_variable]
220
+ ),
221
+ "\n"
222
+ ]))
223
+ config_variables.pop(section_variable, None)
224
+ return lines
225
+
226
+ def __get_unkown_variable_lines(self, config_variables: Dict[str, Any]) -> List[str]:
227
+ """
228
+ ### Returns the lines composed by the unkown variables in the dictionary.
229
+
230
+ #### Params:
231
+ - config_variables (dict(str, any)): Dictionary containing all unknown variables.
232
+
233
+ #### Returns:
234
+ - (list(str)): Config file lines created from the dictionary variables.
235
+ """
236
+ lines = []
237
+ for variable in config_variables.keys():
238
+ lines.append(
239
+ f"{self.__make_config_line(variable, config_variables[variable], '')}\n"
240
+ )
241
+ return lines
File without changes
@@ -0,0 +1,107 @@
1
+ from typing import Dict, Union
2
+
3
+ from xmipp3_installer.application.logger.logger import logger
4
+ from xmipp3_installer.repository.config_vars import variables, default_values
5
+
6
+ def get_context_values_from_file_values(file_values: Dict[str, str], show_warnings: bool=True) -> Dict[str, Union[str, bool]]:
7
+ """
8
+ ### Converts configuration values from file format to context format.
9
+
10
+ Processes a dictionary of configuration values read from file, converting toggle values
11
+ from string ('ON'/'OFF') to boolean representation for use in the application context.
12
+
13
+ #### Params:
14
+ - file_values (dict(str, str)): Dictionary of configuration values as read from file.
15
+ - show_warnings (bool): Optional. If True, warning messages are shown when applicable.
16
+
17
+ #### Returns:
18
+ - (dict(str, str | bool)): Dictionary with values converted to their context format.
19
+ """
20
+ context_values = {}
21
+ for key, value in file_values.items():
22
+ context_values[key] = __get_context_value_from_file_value(key, value, show_warnings)
23
+ return context_values
24
+
25
+ def get_file_values_from_context_values(context_values: Dict[str, Union[str, bool]]) -> Dict[str, str]:
26
+ """
27
+ ### Converts configuration values from context format to file format.
28
+
29
+ Processes a dictionary of configuration values from the application context, converting toggle values
30
+ from boolean to string ('ON'/'OFF') representation for storage in configuration file.
31
+
32
+ #### Params:
33
+ - context_values (dict(str, str | bool)): Dictionary of configuration values from context.
34
+
35
+ #### Returns:
36
+ - (dict(str, str)): Dictionary with values converted to their file storage format.
37
+ """
38
+ file_values = {}
39
+ for key, value in context_values.items():
40
+ file_values[key] = __get_file_value_from_context_value(key, value)
41
+ return file_values
42
+
43
+ def __get_context_value_from_file_value(key: str, value: str, show_warnings: bool) -> Union[str, bool]:
44
+ """
45
+ ### Converts a single configuration value from file format to context format.
46
+
47
+ #### Params:
48
+ - key (str): Configuration variable key.
49
+ - value (str): Value as read from file.
50
+ - show_warnings (bool): Optional. If True, warning messages are shown when applicable.
51
+
52
+ #### Returns:
53
+ - (str | bool): Value converted to its context format.
54
+ """
55
+ if key in variables.CONFIG_VARIABLES[variables.TOGGLES]:
56
+ return __get_boolean_value_from_string(key, value, show_warnings)
57
+ return value
58
+
59
+ def __get_file_value_from_context_value(key: str, value: str) -> Union[str, bool]:
60
+ """
61
+ ### Converts a single configuration value from context format to file format.
62
+
63
+ #### Params:
64
+ - key (str): Configuration variable key.
65
+ - value (str | bool): Value from context.
66
+
67
+ #### Returns:
68
+ - (str): Value converted to its file storage format.
69
+ """
70
+ if key in variables.CONFIG_VARIABLES[variables.TOGGLES]:
71
+ return __get_string_value_from_boolean(value)
72
+ return value
73
+
74
+ def __get_boolean_value_from_string(key: str, value: str, show_warning: bool) -> bool:
75
+ """
76
+ ### Converts a toggle value from string ('ON'/'OFF') to boolean.
77
+
78
+ #### Params:
79
+ - key (str): Configuration variable key.
80
+ - value (str): String value to convert ('ON' or 'OFF').
81
+ - show_warnings (bool): Optional. If True, warning message is shown when applicable.
82
+
83
+ #### Returns:
84
+ - (bool): Boolean representation of the toggle value.
85
+ """
86
+ if value != default_values.ON and value != default_values.OFF:
87
+ default_value = default_values.CONFIG_DEFAULT_VALUES[key]
88
+ if show_warning:
89
+ logger(logger.yellow(
90
+ f"WARNING: config variable '{key}' has unrecognized value '{value}'. "
91
+ f"Toggle values must be either '{default_values.ON}' or '{default_values.OFF}'. "
92
+ f"Default value '{default_value}' will be used instead."
93
+ ))
94
+ value = default_value
95
+ return value == default_values.ON
96
+
97
+ def __get_string_value_from_boolean(value: bool) -> str:
98
+ """
99
+ ### Converts a toggle value from boolean to string ('ON'/'OFF').
100
+
101
+ #### Params:
102
+ - value (bool): Boolean value to convert.
103
+
104
+ #### Returns:
105
+ - (str): String representation of the toggle value ('ON' or 'OFF').
106
+ """
107
+ return default_values.ON if value else default_values.OFF
@@ -0,0 +1,36 @@
1
+ """### Contains the default values for the config variables."""
2
+
3
+ from xmipp3_installer.installer.constants import paths
4
+ from xmipp3_installer.installer.handlers import conda_handler
5
+ from xmipp3_installer.repository.config_vars import variables
6
+
7
+ __TUNE_FLAG = '-mtune=native'
8
+
9
+ ON = 'ON'
10
+ OFF = 'OFF'
11
+ CONFIG_DEFAULT_VALUES = {
12
+ variables.SEND_INSTALLATION_STATISTICS: ON,
13
+ variables.CMAKE: None,
14
+ variables.CUDA: ON,
15
+ variables.MPI: ON,
16
+ variables.CC: None,
17
+ variables.CXX: None,
18
+ variables.CMAKE_INSTALL_PREFIX: paths.INSTALL_PATH,
19
+ variables.CC_FLAGS: __TUNE_FLAG,
20
+ variables.CXX_FLAGS: __TUNE_FLAG,
21
+ variables.CUDA_COMPILER: None,
22
+ variables.PREFIX_PATH: conda_handler.get_conda_prefix_path(),
23
+ variables.MPI_HOME: None,
24
+ variables.PYTHON_HOME: None,
25
+ variables.FFTW_HOME: None,
26
+ variables.TIFF_HOME: None,
27
+ variables.HDF5_HOME: None,
28
+ variables.JPEG_HOME: None,
29
+ variables.SQLITE_HOME: None,
30
+ variables.CUDA_CXX: None,
31
+ variables.MATLAB: ON,
32
+ variables.LINK_SCIPION: ON,
33
+ variables.BUILD_TESTING: ON,
34
+ variables.SKIP_RPATH: ON,
35
+ variables.BUILD_TYPE: "Release"
36
+ }
@@ -0,0 +1,48 @@
1
+ """### Contains all the variables related to the configuration."""
2
+
3
+ SEND_INSTALLATION_STATISTICS = 'SEND_INSTALLATION_STATISTICS'
4
+ CMAKE = 'CMAKE'
5
+ CC = 'CMAKE_C_COMPILER'
6
+ CXX = 'CMAKE_CXX_COMPILER'
7
+ CC_FLAGS = 'CMAKE_C_FLAGS'
8
+ CXX_FLAGS = 'CMAKE_CXX_FLAGS'
9
+ CMAKE_INSTALL_PREFIX = 'CMAKE_INSTALL_PREFIX'
10
+ CUDA = 'XMIPP_USE_CUDA'
11
+ CUDA_COMPILER = 'CMAKE_CUDA_COMPILER'
12
+ MPI = 'XMIPP_USE_MPI'
13
+ PREFIX_PATH = 'CMAKE_PREFIX_PATH'
14
+ MPI_HOME = 'MPI_HOME'
15
+ PYTHON_HOME = 'Python3_ROOT_DIR'
16
+ FFTW_HOME = 'FFTW_ROOT'
17
+ TIFF_HOME = 'TIFF_ROOT'
18
+ HDF5_HOME = 'HDF5_ROOT'
19
+ JPEG_HOME = 'JPEG_ROOT'
20
+ SQLITE_HOME = 'SQLite_ROOT'
21
+ CUDA_CXX = 'CMAKE_CUDA_HOST_COMPILER'
22
+ MATLAB = 'XMIPP_USE_MATLAB'
23
+ LINK_SCIPION = 'XMIPP_LINK_TO_SCIPION'
24
+ BUILD_TESTING = 'BUILD_TESTING'
25
+ SKIP_RPATH='CMAKE_SKIP_RPATH'
26
+ BUILD_TYPE = "BUILD_TYPE"
27
+
28
+ # Not stored in ket=value format
29
+ LAST_MODIFIED_KEY = "last_modified"
30
+
31
+ # File structure
32
+ TOGGLES = 'toggles'
33
+ LOCATIONS = 'locations'
34
+ COMPILATION_FLAGS = 'flags'
35
+ CONFIG_VARIABLES = {
36
+ TOGGLES: [
37
+ SEND_INSTALLATION_STATISTICS, CUDA, MPI, MATLAB, LINK_SCIPION, BUILD_TESTING, SKIP_RPATH
38
+ ],
39
+ LOCATIONS: [
40
+ CMAKE, CC, CXX, CMAKE_INSTALL_PREFIX, PREFIX_PATH, MPI_HOME,
41
+ CUDA_COMPILER, PYTHON_HOME, FFTW_HOME, TIFF_HOME,
42
+ HDF5_HOME, JPEG_HOME, SQLITE_HOME, CUDA_CXX
43
+ ],
44
+ COMPILATION_FLAGS: [CC_FLAGS, CXX_FLAGS, BUILD_TYPE]
45
+ }
46
+
47
+ # Do not pass this variables to CMake, only for installer logic
48
+ INTERNAL_LOGIC_VARS = [SEND_INSTALLATION_STATISTICS, CMAKE, BUILD_TYPE]
@@ -0,0 +1,15 @@
1
+ """### Contains a custom exception for lines in the configuration file with invalid format."""
2
+
3
+ from xmipp3_installer.application.logger.logger import logger
4
+
5
+ class InvalidConfigLineError(RuntimeError):
6
+ @staticmethod
7
+ def generate_error_message(config_file, line_number, line):
8
+ return '\n'.join([
9
+ logger.yellow(f"WARNING: There was an error parsing {config_file} file: "),
10
+ logger.red(f'Unable to parse line {line_number}: {line}'),
11
+ logger.yellow(
12
+ "Contents of config file won't be read, default values will be used instead.\n"
13
+ f"You can create a new file template from scratch deleting file {config_file} and trying again."
14
+ )
15
+ ])
@@ -0,0 +1,18 @@
1
+ import os
2
+ import shutil
3
+ from typing import List
4
+
5
+ def delete_paths(paths: List[str]):
6
+ """
7
+ ### Deletes all the given paths (files or directories).
8
+
9
+ #### Params:
10
+ - path (list(str)): List of paths to delete.
11
+ """
12
+ for path in paths:
13
+ if not os.path.exists(path):
14
+ continue
15
+ if os.path.isdir(path):
16
+ shutil.rmtree(path, ignore_errors=True)
17
+ else:
18
+ os.remove(path)
@@ -0,0 +1,25 @@
1
+ """### Contains a generic singleton class."""
2
+
3
+ from typing_extensions import Self
4
+
5
+ class Singleton:
6
+ """
7
+ ### Generic singleton class.
8
+ """
9
+ __instance = None
10
+
11
+ def __new__(cls, *args, **kwrgs) -> Self:
12
+ """
13
+ ### Singleton instancer.
14
+
15
+ #### Params:
16
+ - cls (self): Current class.
17
+ - *args (any): Positional params.
18
+ - **kwargs (any): Argument params.
19
+
20
+ #### Returns:
21
+ - (self): Instance of current class.
22
+ """
23
+ if not cls.__instance:
24
+ cls.__instance = super().__new__(cls)
25
+ return cls.__instance