idmtools 0.0.0.dev0__py3-none-any.whl → 0.0.2__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 (118) hide show
  1. idmtools/__init__.py +27 -8
  2. idmtools/analysis/__init__.py +5 -0
  3. idmtools/analysis/add_analyzer.py +89 -0
  4. idmtools/analysis/analyze_manager.py +490 -0
  5. idmtools/analysis/csv_analyzer.py +103 -0
  6. idmtools/analysis/download_analyzer.py +96 -0
  7. idmtools/analysis/map_worker_entry.py +100 -0
  8. idmtools/analysis/platform_analysis_bootstrap.py +94 -0
  9. idmtools/analysis/platform_anaylsis.py +291 -0
  10. idmtools/analysis/tags_analyzer.py +93 -0
  11. idmtools/assets/__init__.py +9 -0
  12. idmtools/assets/asset.py +453 -0
  13. idmtools/assets/asset_collection.py +514 -0
  14. idmtools/assets/content_handlers.py +19 -0
  15. idmtools/assets/errors.py +23 -0
  16. idmtools/assets/file_list.py +191 -0
  17. idmtools/builders/__init__.py +11 -0
  18. idmtools/builders/arm_simulation_builder.py +152 -0
  19. idmtools/builders/csv_simulation_builder.py +76 -0
  20. idmtools/builders/simulation_builder.py +348 -0
  21. idmtools/builders/sweep_arm.py +109 -0
  22. idmtools/builders/yaml_simulation_builder.py +82 -0
  23. idmtools/config/__init__.py +7 -0
  24. idmtools/config/idm_config_parser.py +486 -0
  25. idmtools/core/__init__.py +10 -0
  26. idmtools/core/cache_enabled.py +114 -0
  27. idmtools/core/context.py +68 -0
  28. idmtools/core/docker_task.py +207 -0
  29. idmtools/core/enums.py +51 -0
  30. idmtools/core/exceptions.py +91 -0
  31. idmtools/core/experiment_factory.py +71 -0
  32. idmtools/core/id_file.py +70 -0
  33. idmtools/core/interfaces/__init__.py +5 -0
  34. idmtools/core/interfaces/entity_container.py +64 -0
  35. idmtools/core/interfaces/iassets_enabled.py +58 -0
  36. idmtools/core/interfaces/ientity.py +331 -0
  37. idmtools/core/interfaces/iitem.py +206 -0
  38. idmtools/core/interfaces/imetadata_operations.py +89 -0
  39. idmtools/core/interfaces/inamed_entity.py +17 -0
  40. idmtools/core/interfaces/irunnable_entity.py +159 -0
  41. idmtools/core/logging.py +387 -0
  42. idmtools/core/platform_factory.py +316 -0
  43. idmtools/core/system_information.py +104 -0
  44. idmtools/core/task_factory.py +145 -0
  45. idmtools/entities/__init__.py +10 -0
  46. idmtools/entities/command_line.py +229 -0
  47. idmtools/entities/command_task.py +155 -0
  48. idmtools/entities/experiment.py +787 -0
  49. idmtools/entities/generic_workitem.py +43 -0
  50. idmtools/entities/ianalyzer.py +163 -0
  51. idmtools/entities/iplatform.py +1106 -0
  52. idmtools/entities/iplatform_default.py +39 -0
  53. idmtools/entities/iplatform_ops/__init__.py +5 -0
  54. idmtools/entities/iplatform_ops/iplatform_asset_collection_operations.py +148 -0
  55. idmtools/entities/iplatform_ops/iplatform_experiment_operations.py +415 -0
  56. idmtools/entities/iplatform_ops/iplatform_simulation_operations.py +315 -0
  57. idmtools/entities/iplatform_ops/iplatform_suite_operations.py +322 -0
  58. idmtools/entities/iplatform_ops/iplatform_workflowitem_operations.py +301 -0
  59. idmtools/entities/iplatform_ops/utils.py +185 -0
  60. idmtools/entities/itask.py +316 -0
  61. idmtools/entities/iworkflow_item.py +167 -0
  62. idmtools/entities/platform_requirements.py +20 -0
  63. idmtools/entities/relation_type.py +14 -0
  64. idmtools/entities/simulation.py +255 -0
  65. idmtools/entities/suite.py +188 -0
  66. idmtools/entities/task_proxy.py +37 -0
  67. idmtools/entities/templated_simulation.py +325 -0
  68. idmtools/frozen/frozen_dict.py +71 -0
  69. idmtools/frozen/frozen_list.py +66 -0
  70. idmtools/frozen/frozen_set.py +86 -0
  71. idmtools/frozen/frozen_tuple.py +18 -0
  72. idmtools/frozen/frozen_utils.py +179 -0
  73. idmtools/frozen/ifrozen.py +66 -0
  74. idmtools/plugins/__init__.py +5 -0
  75. idmtools/plugins/git_commit.py +117 -0
  76. idmtools/registry/__init__.py +4 -0
  77. idmtools/registry/experiment_specification.py +105 -0
  78. idmtools/registry/functions.py +28 -0
  79. idmtools/registry/hook_specs.py +132 -0
  80. idmtools/registry/master_plugin_registry.py +51 -0
  81. idmtools/registry/platform_specification.py +138 -0
  82. idmtools/registry/plugin_specification.py +129 -0
  83. idmtools/registry/task_specification.py +104 -0
  84. idmtools/registry/utils.py +119 -0
  85. idmtools/services/__init__.py +5 -0
  86. idmtools/services/ipersistance_service.py +135 -0
  87. idmtools/services/platforms.py +13 -0
  88. idmtools/utils/__init__.py +5 -0
  89. idmtools/utils/caller.py +24 -0
  90. idmtools/utils/collections.py +246 -0
  91. idmtools/utils/command_line.py +45 -0
  92. idmtools/utils/decorators.py +300 -0
  93. idmtools/utils/display/__init__.py +22 -0
  94. idmtools/utils/display/displays.py +181 -0
  95. idmtools/utils/display/settings.py +25 -0
  96. idmtools/utils/dropbox_location.py +30 -0
  97. idmtools/utils/entities.py +127 -0
  98. idmtools/utils/file.py +72 -0
  99. idmtools/utils/file_parser.py +151 -0
  100. idmtools/utils/filter_simulations.py +182 -0
  101. idmtools/utils/filters/__init__.py +5 -0
  102. idmtools/utils/filters/asset_filters.py +88 -0
  103. idmtools/utils/general.py +286 -0
  104. idmtools/utils/gitrepo.py +336 -0
  105. idmtools/utils/hashing.py +239 -0
  106. idmtools/utils/info.py +124 -0
  107. idmtools/utils/json.py +82 -0
  108. idmtools/utils/language.py +107 -0
  109. idmtools/utils/local_os.py +40 -0
  110. idmtools/utils/time.py +22 -0
  111. idmtools-0.0.2.dist-info/METADATA +120 -0
  112. idmtools-0.0.2.dist-info/RECORD +116 -0
  113. idmtools-0.0.2.dist-info/entry_points.txt +9 -0
  114. idmtools-0.0.2.dist-info/licenses/LICENSE.TXT +3 -0
  115. idmtools-0.0.0.dev0.dist-info/METADATA +0 -41
  116. idmtools-0.0.0.dev0.dist-info/RECORD +0 -5
  117. {idmtools-0.0.0.dev0.dist-info → idmtools-0.0.2.dist-info}/WHEEL +0 -0
  118. {idmtools-0.0.0.dev0.dist-info → idmtools-0.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,316 @@
1
+ """
2
+ Manages the creation of our platforms.
3
+
4
+ The Platform allows us to lookup a platform via its plugin name, "COMPS" or via configuration aliases defined in a platform plugins, such as CALCULON.
5
+
6
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
7
+ """
8
+ import json
9
+ import os
10
+ from contextlib import contextmanager
11
+ from dataclasses import fields
12
+ from logging import getLogger, DEBUG
13
+ from typing import TYPE_CHECKING
14
+ from idmtools.config import IdmConfigParser
15
+ from idmtools.core import TRUTHY_VALUES
16
+ from idmtools.core.context import set_current_platform, remove_current_platform
17
+ from idmtools.utils.entities import validate_user_inputs_against_dataclass
18
+ from idmtools.utils.json import IDMJSONEncoder
19
+
20
+ if TYPE_CHECKING: # pragma: no cover
21
+ from idmtools.entities.iplatform import IPlatform
22
+
23
+ logger = getLogger(__name__)
24
+ user_logger = getLogger('user')
25
+
26
+
27
+ @contextmanager
28
+ def platform(*args, **kwargs):
29
+ """
30
+ Utility function to create platform.
31
+
32
+ Args:
33
+ *args: Arguments to pass to platform
34
+ **kwargs: Keyword args to pass to platform
35
+
36
+ Returns:
37
+ Platform created.
38
+ """
39
+ logger.debug(f'Acquiring platform context with options: {str(*args)}')
40
+ try:
41
+ # check if we are already in a platform context and if so add to stack
42
+ pl = Platform(*args, **kwargs)
43
+ set_current_platform(pl)
44
+ yield pl
45
+ finally:
46
+ # Code to release resource, e.g.:
47
+ logger.debug('Un-setting current platform context')
48
+ remove_current_platform()
49
+
50
+
51
+ class Platform:
52
+ """
53
+ Platform Factory.
54
+ """
55
+ _aliases = None
56
+ _platform_plugins = None
57
+
58
+ def __new__(cls, block: str = None, **kwargs):
59
+ """
60
+ Create a platform based on the block and all other inputs.
61
+
62
+ Args:
63
+ block(str, optional): The INI configuration file block name.
64
+
65
+ COMPSPlatform Keyword Args:
66
+ - endpoint (str, optional): URL of the COMPS endpoint to use. Default is 'https://comps.idmod.org'
67
+ - environment (str, optional): Name of the COMPS environment to target, Default is Calculon, Options are Calculon, IDMcloud, SlurmStage, Cumulus, etc
68
+ - priority (str, optional): Priority of the job. Default is 'Lowest'. Options are Lowest, BelowNormal, Normal, AboveNormal, Highest
69
+ - node_group (str, optional): node group to target. Default is None. Options are 'idm_abcd', 'idm_ab', idm_cd', 'idm_a', 'idm_b', 'idm_c', 'idm_d', 'idm_48cores'
70
+ - num_retries (int, optional): How retries if the simulation fails, Default is 0, max is 10
71
+ - num_cores (int, optional): How many cores per simulation. Default is 1, max is 32
72
+ - max_workers (int, optional): The number of processes to spawn locally. Defaults to 16, min is 1, max is 32
73
+ - batch_size (int, optional): How many simulations per batch. Default is 10, min is 1 and max is 100
74
+ - exclusive (bool, optional): Enable exclusive mode? (one simulation per node on the cluster). Default is False
75
+ - docker_image (str, optional): Docker image to use for the simulation. Default is None
76
+
77
+ SlurmPlatform Keyword Args:
78
+ - nodes (int, optional): How many nodes to be used. Default is None
79
+ - ntasks (int, optional): Num of tasks. Default is None
80
+ - cpus_per_task (int, optional): CPU # per task. Default is None
81
+ - ntasks_per_core (int, optional): Task # per core. Default is None
82
+ - max_running_jobs (int, optional): Maximum of running jobs(Per experiment). Default is None
83
+ - mem (int, optional): Memory per core: MB of memory. Default is None
84
+ - mem_per_cpu (int, optional): Memory per core: MB of memory. Default is None
85
+ - partition (str, optional): Which partition to use. Default is None
86
+ - constraint (str, optional): Specify compute node. Default is None
87
+ - time (str, optional): Limit time on this job hrs:min:sec. Default is None
88
+ - account (str, optional): if set to something, jobs will run with the specified account in slurm. Default is None
89
+ - exclusive (bool, optional): Allocated nodes can not be shared with other jobs/users. Default is False
90
+ - requeue (bool, optional): Specifies that the batch job should be eligible for re-queuing. Default is True
91
+ - retries (int, optional): Default retries for jobs. Default is 1
92
+ - sbatch_custom (str, optional): Pass custom commands to sbatch generation script. Default is None
93
+ - modules (list, optional): modules to be load, for example load 'mpi' module. Default is []
94
+ - dir_exist_ok (bool, optional): Specifies default setting of whether slurm should fail if item directory already exists. Default is False
95
+ - array_batch_size (int, optional): Set array max size for Slurm job. Default is None
96
+ - run_on_slurm (bool, optional): determine if run script as Slurm job. Default is False
97
+ - mpi_type (str, optional): MPI type to use in slurm. Default is pmi2. Options are pmi2, pmix, mpirun
98
+
99
+ ContainerPlatform Keyword Args:
100
+ - job_directory (str, optional): Job directory. Default is None
101
+ - docker_image (str, optional): Docker image to use for the simulation. Default is None
102
+ - extra_packages (list, optional): Extra packages to install. Default is None
103
+ - data_mount (str, optional): Data mount point. Default is None
104
+ - user_mounts (dict, optional): User mounts. Default is None
105
+ - container_prefix (str, optional): Prefix for container name. Default is None
106
+ - force_start (bool, optional): Force start container. Default is False
107
+ - new_container (bool, optional): Start a new container. Default is False
108
+ - include_stopped (bool, optional): Include stopped containers. Default is False
109
+ - container_id (str, optional): The ID of the container being used.
110
+ - max_job (int, optional): Max job. Default is 4
111
+ - modules (list, optional): Modules to load. Default is None
112
+ - debug (bool, optional): Debug mode. Default is False
113
+ - retries (int, optional): The number of retries to attempt for a job.
114
+ - ntasks (int, optional): Number of MPI processes. Default is 1
115
+
116
+ Returns:
117
+ The requested platform.
118
+
119
+ Raises:
120
+ ValueError or Exception: If the platform is of an unknown type.
121
+ """
122
+ from idmtools.registry.platform_specification import PlatformPlugins
123
+
124
+ IdmConfigParser.ensure_init()
125
+
126
+ # Load all Platform plugins
127
+ cls._platform_plugins = PlatformPlugins().get_plugin_map()
128
+ cls._aliases = PlatformPlugins().get_aliases()
129
+ cls._type_map = {key.upper(): key for key in cls._platform_plugins.keys()}
130
+
131
+ _platform = cls._create_platform_from_block(block, **kwargs)
132
+ set_current_platform(_platform)
133
+ _platform._config_block = block
134
+ _platform._kwargs = kwargs
135
+ return _platform
136
+
137
+ @classmethod
138
+ def _validate_platform_type(cls, platform_type):
139
+ """
140
+ Check if the requested platform exists.
141
+
142
+ Args:
143
+ platform_type: The platform type.
144
+
145
+ Returns:
146
+ None
147
+
148
+ Raise:
149
+ ValueError: when the platform is of an unknown type
150
+ """
151
+ if platform_type is None or platform_type.upper() not in cls._type_map:
152
+ raise ValueError(f"{platform_type} is an unknown Platform Type. "
153
+ f"Supported platforms are {', '.join(cls._platform_plugins.keys())}")
154
+
155
+ @classmethod
156
+ def _create_platform_from_block(cls, block: str, **kwargs) -> 'IPlatform':
157
+ """
158
+ Create a platform based on the block and all other inputs.
159
+
160
+ Args:
161
+ block: The section name in the configuration file or platform alias.
162
+ kwargs: Keyword args to pass to platform
163
+
164
+ Returns:
165
+ A platform instance.
166
+ """
167
+ # Get the type of the platform and the section from block and kwargs
168
+ platform_type, section, is_alias = cls._get_platform_type(block, **kwargs)
169
+ if 'type' in kwargs:
170
+ platform_type = kwargs['type']
171
+ kwargs.pop('type')
172
+
173
+ # Make sure we support platform_type
174
+ cls._validate_platform_type(platform_type)
175
+
176
+ # Find the correct Platform type
177
+ platform_type = cls._type_map[platform_type.upper()]
178
+ platform_spec = cls._platform_plugins.get(platform_type)
179
+ platform_cls = platform_spec.get_type()
180
+
181
+ # Collect fields types
182
+ fds = fields(platform_cls)
183
+ field_name = [f.name for f in fds if f.metadata and 'help' in f.metadata]
184
+ field_type = {f.name: f.type for f in fds}
185
+
186
+ # Make data to the requested type
187
+ inputs = IdmConfigParser.retrieve_dict_config_block(field_type, section)
188
+ inputs.pop('type', None) # Remove 'type' dict from inputs since it is not a field to create platform
189
+ # Make sure the user values have the requested type
190
+ fs_kwargs = validate_user_inputs_against_dataclass(field_type, kwargs) # noqa: F841
191
+
192
+ # Update attr based on priority: #1 Code, #2 INI, #3 Default
193
+ for fn in set(kwargs.keys()).intersection(set(field_name)):
194
+ inputs[fn] = kwargs[fn]
195
+
196
+ extra_kwargs = set(kwargs.keys()) - set(field_name)
197
+ if len(extra_kwargs) > 0:
198
+ field_not_used_display = [" - {} = {}".format(fn, kwargs[fn]) for fn in extra_kwargs]
199
+ logger.warning("\n/!\\ WARNING: The following User Inputs are not used:")
200
+ logger.warning("\n".join(field_not_used_display))
201
+
202
+ field_not_used = set(inputs.keys()) - set(field_type.keys())
203
+ if len(field_not_used) > 0:
204
+ field_not_used_display = [" - {} = {}".format(fn, inputs[fn]) for fn in field_not_used]
205
+ logger.warning(f"\n[{block}]: /!\\ WARNING: the following Config Settings are not used when creating "
206
+ f"Platform:")
207
+ logger.warning("\n".join(field_not_used_display))
208
+
209
+ # Remove extra fields
210
+ for f in field_not_used:
211
+ inputs.pop(f)
212
+
213
+ # Display input info
214
+ cls._display_inputs(platform_cls, inputs)
215
+
216
+ # Now create Platform using the data with the correct data types
217
+ return platform_cls(**inputs)
218
+
219
+ @classmethod
220
+ def _get_platform_type(cls, block: str, **kwargs):
221
+ """
222
+ Get the type of the platform from the INI configuration file, platform alias, or platform_kwargs.
223
+
224
+ Args:
225
+ block: The section name in the configuration file or alias name.
226
+ kwargs: Keyword args to pass to platform
227
+
228
+ Returns:
229
+ The type of the platform, section, and whether it is an alias.
230
+ """
231
+ # If block is an alias
232
+ if block and block.upper() in cls._aliases:
233
+ platform_type, section, is_alias = cls._get_type_from_platform_alias(block)
234
+
235
+ # Else if block is a section in the idmtools.ini file
236
+ elif block and IdmConfigParser.has_section(block):
237
+ platform_type, section, is_alias = cls._get_type_from_ini(block)
238
+
239
+ # Else, all other cases
240
+ else:
241
+ platform_type, section, is_alias = cls._get_type_from_platform_kwargs(**kwargs)
242
+
243
+ return platform_type, section, is_alias
244
+
245
+ @classmethod
246
+ def _get_type_from_ini(cls, block: str):
247
+ """
248
+ Get the type of the platform from the INI configuration file.
249
+
250
+ Args:
251
+ block: The section name in the configuration file.
252
+
253
+ Returns:
254
+ The type of the platform, section, and whether it is an alias.
255
+ """
256
+ section = IdmConfigParser.get_section(block)
257
+ platform_type = IdmConfigParser.get_option(block, 'type')
258
+ is_alias = False
259
+ return platform_type, section, is_alias
260
+
261
+ @classmethod
262
+ def _get_type_from_platform_alias(cls, block: str):
263
+ """
264
+ Get the type of the platform from the platform alias.
265
+
266
+ Args:
267
+ block: The alias name.
268
+
269
+ Returns:
270
+ The type of the platform, section, and whether it is an alias.
271
+ """
272
+ if logger.isEnabledFor(DEBUG):
273
+ logger.debug(f"Loading plugin from alias {block.upper()}")
274
+ props = cls._aliases[block.upper()]
275
+ platform_type = props[0].get_name()
276
+ section = props[1]
277
+ is_alias = True
278
+ return platform_type, section, is_alias
279
+
280
+ @classmethod
281
+ def _get_type_from_platform_kwargs(cls, **kwargs):
282
+ """
283
+ Get the type of the platform from platform_kwargs.
284
+
285
+ Args:
286
+ kwargs: Keyword args to pass to platform
287
+
288
+ Returns:
289
+ The type of the platform, section, and whether it is an alias.
290
+ """
291
+ section = kwargs
292
+ is_alias = False
293
+ platform_type = section.pop('type', None)
294
+ if not platform_type:
295
+ raise ValueError("Type must be specified in Platform constructor.")
296
+ return platform_type, section, is_alias
297
+
298
+ @classmethod
299
+ def _display_inputs(cls, platform_cls: object, inputs: dict):
300
+ """
301
+ Display inputs required for platform creation on the console.
302
+
303
+ Args:
304
+ platform_cls: The platform object.
305
+ inputs: The inputs.
306
+ """
307
+ from idmtools.core.logging import VERBOSE
308
+
309
+ if IdmConfigParser.is_output_enabled() and IdmConfigParser.get_option(None, "SHOW_PLATFORM_CONFIG",
310
+ 't').lower() in TRUTHY_VALUES:
311
+ if os.getenv("IDMTOOLS_NO_CONFIG_WARNING", "F").lower() not in TRUTHY_VALUES:
312
+ user_logger.log(VERBOSE, f"\nInitializing {platform_cls.__name__} with:")
313
+ user_logger.log(VERBOSE, json.dumps(inputs, indent=3, cls=IDMJSONEncoder))
314
+ else:
315
+ user_logger.debug(f"\nInitializing {platform_cls.__name__} with:")
316
+ user_logger.debug(json.dumps(inputs, indent=3, cls=IDMJSONEncoder))
@@ -0,0 +1,104 @@
1
+ """
2
+ Utilities functions/classes to fetch info that is useful for troubleshooting user issues.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ import getpass
7
+ from dataclasses import dataclass, field
8
+ from logging import getLogger
9
+ from pathlib import Path
10
+ import platform
11
+ from typing import Optional, List, Dict
12
+ import os
13
+ from idmtools.utils.info import get_packages_list
14
+
15
+ logger = getLogger(__name__)
16
+ default_base_sir = os.getenv('IDMTOOLS_DATA_BASE_DIR', str(Path.home()))
17
+
18
+
19
+ def get_data_directory() -> str:
20
+ """
21
+ Get our default data directory for a user.
22
+
23
+ Returns:
24
+ Default data directory for a user.
25
+ """
26
+ return os.path.join(default_base_sir, '.local_data')
27
+
28
+
29
+ def get_filtered_environment_vars(exclude=None) -> Dict[str, str]:
30
+ """
31
+ Get environment vars excluding a specific set.
32
+
33
+ Args:
34
+ exclude: If not provided, we default to using ['LS_COLORS', 'XDG_CONFIG_DIRS', 'PS1', 'XDG_DATA_DIRS']
35
+
36
+ Returns:
37
+ Environment vars filtered for items specified
38
+ """
39
+ ret = dict()
40
+ if exclude is None:
41
+ exclude = ['LS_COLORS', 'XDG_CONFIG_DIRS', 'PS1', 'XDG_DATA_DIRS']
42
+ for k, v in os.environ.items():
43
+ if k not in exclude:
44
+ ret[k] = v
45
+ return ret
46
+
47
+
48
+ @dataclass
49
+ class SystemInformation:
50
+ """
51
+ Utility class to provide details useful in troubleshooting issues.
52
+ """
53
+ data_directory: Optional[str] = field(default=get_data_directory())
54
+ user: Optional[str] = getpass.getuser()
55
+ python_version: str = platform.python_version()
56
+ python_build: str = platform.python_build()
57
+ python_implementation = platform.python_implementation()
58
+ python_packages: List[str] = field(default_factory=get_packages_list)
59
+ environment_variables: Dict[str, str] = field(default_factory=get_filtered_environment_vars)
60
+ os_name: str = platform.system()
61
+ hostname: str = platform.node()
62
+ system_version: str = platform.version()
63
+ system_architecture: str = platform.machine()
64
+ system_processor: str = platform.processor()
65
+ system_architecture_details: str = platform.architecture()
66
+ default_docket_socket_path: str = '/var/run/docker.sock'
67
+ cwd: str = os.getcwd()
68
+ user_group_str: str = os.getenv("CURRENT_UID", "1000:1000")
69
+ version: str = None
70
+
71
+ def __post_init__(self):
72
+ """
73
+ Load our version dynamically to prevent import issues.
74
+
75
+ Returns:
76
+ None
77
+ """
78
+ from idmtools import __version__
79
+ self.version = __version__
80
+
81
+
82
+ @dataclass
83
+ class LinuxSystemInformation(SystemInformation):
84
+ """
85
+ LinuxSystemInformation adds linux specific properties.
86
+ """
87
+ user_group_str: str = field(default_factory=lambda: os.getenv("CURRENT_UID", f'{os.getuid()}:{os.getgid()}'))
88
+
89
+
90
+ class WindowsSystemInformation(SystemInformation):
91
+ """
92
+ WindowsSystemInformation adds windows specific properties.
93
+ """
94
+ default_docket_socket_path: str = '//var/run/docker.sock'
95
+
96
+
97
+ def get_system_information() -> SystemInformation:
98
+ """
99
+ Fetch the system-appropriate information inspection object.
100
+
101
+ Returns:
102
+ :class:`SystemInformation` with platform-specific implementation.
103
+ """
104
+ return LinuxSystemInformation() if platform.system() in ["Linux", "Darwin"] else WindowsSystemInformation()
@@ -0,0 +1,145 @@
1
+ """
2
+ Define our tasks factory. This is crucial to build tasks when fetching from the server.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ from logging import getLogger
7
+ from typing import NoReturn, Type
8
+ from idmtools.entities.itask import ITask
9
+ from idmtools.registry.task_specification import TaskSpecification
10
+
11
+ logger = getLogger(__name__)
12
+ TASK_BUILDERS = None
13
+
14
+
15
+ class DynamicTaskSpecification(TaskSpecification):
16
+ """
17
+ This class allows users to quickly define a spec for special tasks.
18
+ """
19
+
20
+ def __init__(self, task_type: Type[ITask], description: str = ''):
21
+ """
22
+ Initialize our specification.
23
+
24
+ Args:
25
+ task_type: Task type to register
26
+ description: Description to register with task
27
+ """
28
+ self.task_type = task_type
29
+ self.description = description
30
+
31
+ def get(self, configuration: dict) -> ITask:
32
+ """
33
+ Get an instance of our task using configuration.
34
+
35
+ Args:
36
+ configuration: Configuration keyword args.
37
+
38
+ Returns:
39
+ Task with configuration specified
40
+ """
41
+ return self.task_type(**configuration)
42
+
43
+ def get_description(self) -> str:
44
+ """
45
+ Get description of our plugin.
46
+
47
+ Returns:
48
+ Returns the user-defined plugin description.
49
+ """
50
+ return self.description
51
+
52
+ def get_type(self) -> Type[ITask]:
53
+ """
54
+ Get our task type.
55
+
56
+ Returns:
57
+ Returns our task type
58
+ """
59
+ return self.task_type
60
+
61
+
62
+ class TaskFactory:
63
+ """
64
+ TaskFactory allows creation of tasks that are derived from plugins.
65
+
66
+ """
67
+
68
+ DEFAULT_KEY = 'idmtools.entities.command_task.CommandTask'
69
+
70
+ def __init__(self):
71
+ """
72
+ Initialize our Factory.
73
+ """
74
+ global TASK_BUILDERS
75
+ if TASK_BUILDERS is None:
76
+ from idmtools.registry.task_specification import TaskPlugins
77
+ TASK_BUILDERS = TaskPlugins().get_plugin_map()
78
+ self._builders = TASK_BUILDERS
79
+ aliases = dict()
80
+ # register types as full paths as well
81
+ for _model, spec in self._builders.items():
82
+ try:
83
+ aliases[f'{spec.get_type().__module__}.{spec.get_type().__name__}'] = spec
84
+ aliases[f'{spec.get_type().__name__}'] = spec
85
+ except Exception as e:
86
+ logger.warning(f"Could not load alias for {spec}")
87
+ logger.exception(e)
88
+ self._builders.update(aliases)
89
+
90
+ def register(self, spec: TaskSpecification) -> NoReturn:
91
+ """
92
+ Register a TaskSpecification dynamically.
93
+
94
+ Args:
95
+ spec: Specification to register
96
+
97
+ Returns:
98
+ None
99
+ """
100
+ type_name = spec.get_type().__name__
101
+ module_name = {spec.get_type().__module__}
102
+ logger.debug(f'Registering task: {type_name} as both {type_name} and as {module_name}.{type_name}')
103
+ self._builders[type_name] = spec
104
+ self._builders[f'{module_name}.{type_name}'] = spec
105
+
106
+ def register_task(self, task: Type[ITask]) -> NoReturn:
107
+ """
108
+ Dynamically register a class using the DynamicTaskSpecification.
109
+
110
+ Args:
111
+ task: Task to register
112
+
113
+ Returns:
114
+ None
115
+ """
116
+ spec = DynamicTaskSpecification(task)
117
+ self.register(spec)
118
+
119
+ def create(self, key, fallback=None, **kwargs) -> ITask: # noqa: F821
120
+ """
121
+ Create a task of type key.
122
+
123
+ Args:
124
+ key: Type of task to create
125
+ fallback: Fallback task type. Default to DEFAULT_KEY if not provided
126
+ **kwargs: Optional arguments to pass to the task
127
+
128
+ Returns:
129
+ Task with option specified
130
+ """
131
+ if key is None:
132
+ key = self.DEFAULT_KEY
133
+ logger.warning(f'No task type tag found, assuming type: {key}')
134
+
135
+ if key not in self._builders:
136
+ if not fallback:
137
+ raise ValueError(f"The TaskFactory could not create an task of type {key}")
138
+ else:
139
+ return fallback()
140
+
141
+ task_spec: TaskSpecification = self._builders.get(key)
142
+ return task_spec.get(kwargs)
143
+
144
+
145
+ task_factory = TaskFactory()
@@ -0,0 +1,10 @@
1
+ """
2
+ Entities is the core entities used to build experiments or used as abstracts for those classes.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ # flake8: noqa F821
7
+ from idmtools.entities.command_line import CommandLine
8
+ from idmtools.entities.ianalyzer import IAnalyzer
9
+ from idmtools.entities.suite import Suite
10
+