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,207 @@
1
+ """
2
+ DockerTask provides a utility to run docker images.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ import os
7
+ import re
8
+ import sys
9
+ import unicodedata
10
+ from dataclasses import dataclass, field
11
+ from datetime import datetime, timezone, timedelta
12
+ from typing import Optional, Type
13
+ from idmtools import __version__ as idmtools_version, IdmConfigParser
14
+ from idmtools.assets import AssetCollection, json
15
+ from idmtools.core.logging import getLogger
16
+ from idmtools.entities.itask import ITask
17
+ from idmtools.entities.platform_requirements import PlatformRequirements
18
+ from idmtools.registry.task_specification import TaskSpecification
19
+
20
+ logger = getLogger(__name__)
21
+ user_logger = getLogger('user')
22
+
23
+
24
+ @dataclass
25
+ class DockerTask(ITask):
26
+ """
27
+ Provides a task to run or optionally build a docker container.
28
+ """
29
+ image_name: str = field(default=None, metadata={"md": True})
30
+ # Optional config to build the docker image
31
+ build: bool = field(default=False, metadata={"md": True})
32
+ build_path: Optional[str] = field(default=None, metadata={"md": True})
33
+ # This should in the build_path directory
34
+ Dockerfile: Optional[str] = field(default=None, metadata={"md": True})
35
+ pull_before_build: bool = field(default=True, metadata={"md": True})
36
+ use_nvidia_run: bool = field(default=False, metadata={"md": True})
37
+
38
+ __image_built: bool = field(default=False)
39
+
40
+ def __post_init__(self):
41
+ """
42
+ Set our platform requirements and optionally trigger image build.
43
+
44
+ Returns:
45
+ None
46
+ """
47
+ super().__post_init__()
48
+ self.add_platform_requirement(PlatformRequirements.DOCKER)
49
+ if self.build:
50
+ self.build_image()
51
+
52
+ def gather_common_assets(self) -> AssetCollection:
53
+ """
54
+ Gather common(experiment-level) assets from task.
55
+
56
+ Returns:
57
+ AssetCollection containing all the common assets
58
+ """
59
+ if self.image_name is None:
60
+ raise ValueError("Image Name is required")
61
+ return self.common_assets
62
+
63
+ def gather_transient_assets(self) -> AssetCollection:
64
+ """
65
+ Gather transient(simulation-level) assets from task.
66
+
67
+ Returns:
68
+ AssetCollection
69
+ """
70
+ return self.transient_assets
71
+
72
+ def build_image(self, spinner=None, **extra_build_args):
73
+ """
74
+ Build our docker image.
75
+
76
+ Args:
77
+ spinner: Should we display a CLI spinner
78
+ **extra_build_args: Extra build arguments to pass to docker
79
+
80
+ Returns:
81
+ None
82
+ """
83
+ if not self.__image_built:
84
+ import docker
85
+ from docker.errors import BuildError
86
+ if spinner:
87
+ spinner.text = f"Building {self.image_name}"
88
+ # if the build_path is none use current working directory
89
+ if self.build_path is None:
90
+ self.build_path = os.getcwd()
91
+
92
+ client = docker.client.from_env()
93
+ build_config = dict(
94
+ path=self.build_path,
95
+ dockerfile=self.Dockerfile,
96
+ tag=self.image_name,
97
+ labels=dict(
98
+ uildstamp=f'built-by idmtools {idmtools_version}',
99
+ builddate=str(datetime.now(timezone(timedelta(hours=-8)))))
100
+ )
101
+ if extra_build_args:
102
+ build_config.update(extra_build_args)
103
+ logger.debug(f"Build configuration used: {str(build_config)}")
104
+ self.__image_built = True
105
+ if not IdmConfigParser.is_progress_bar_disabled():
106
+ from tqdm import tqdm
107
+ prog = tqdm(
108
+ desc='Building docker image',
109
+ total=10,
110
+ bar_format='Building Docker Image: |{bar}| {percentage:3.0f}% [{n_fmt}/{total_fmt}] [{elapsed}] {desc}'
111
+ )
112
+ try:
113
+ build_step = None
114
+ # regular expression to grab progress
115
+ progress_grep = re.compile(r'Step ([0-9]+)/([0-9]+) : (.*)')
116
+ # regular expression to filter out ansi codes
117
+ ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
118
+ for line in client.api.build(**build_config):
119
+ line = json.loads(line)
120
+ if 'stream' in line:
121
+ line = line['stream']
122
+ line = ansi_escape.sub('', line).strip()
123
+ # strip unicode data
124
+ line = "".join(ch for ch in line if unicodedata.category(ch)[0] != "C")
125
+ logger.debug('Raw Docker Output: %s', line)
126
+ if line:
127
+ grps = progress_grep.match(line)
128
+ if grps:
129
+ try:
130
+ step = int(grps.group(1))
131
+ total_steps = int(grps.group(2))
132
+ if prog:
133
+ prog.n = step
134
+ prog.total = total_steps
135
+ line = grps.group(3)
136
+ except: # noqa E722
137
+ pass
138
+ if prog:
139
+ prog.set_description(line)
140
+ build_step = line
141
+ # update build step with output
142
+ elif build_step:
143
+ if len(line) > 40:
144
+ line = line[:40]
145
+ if prog:
146
+ prog.set_description(f'{build_step}: {line}')
147
+ elif 'status' in line:
148
+ line = line['status'].strip()
149
+ if prog:
150
+ prog.set_description(line)
151
+
152
+ logger.info('Build Successful)')
153
+ except BuildError as e:
154
+ logger.info(f"Build failed for {self.image_name} with message {e.msg}")
155
+ logger.info(f'Build log: {e.build_log}')
156
+ sys.exit(-1)
157
+ finally:
158
+ if prog:
159
+ prog.close()
160
+
161
+ def reload_from_simulation(self, simulation: 'Simulation'): # noqa E821
162
+ """
163
+ Method to reload task details from simulation object. Currently we do not do this for docker task.
164
+
165
+ Args:
166
+ simulation: Simulation to load data from
167
+
168
+ Returns:
169
+ None
170
+ """
171
+ pass
172
+
173
+
174
+ class DockerTaskSpecification(TaskSpecification):
175
+ """
176
+ DockerTaskSpecification provides the task plugin to idmtools for DockerTask.
177
+ """
178
+
179
+ def get(self, configuration: dict) -> DockerTask:
180
+ """
181
+ Get instance of DockerTask with configuration provided.
182
+
183
+ Args:
184
+ configuration: configuration for DockerTask
185
+
186
+ Returns:
187
+ DockerTask with configuration
188
+ """
189
+ return DockerTask(**configuration)
190
+
191
+ def get_description(self) -> str:
192
+ """
193
+ Get description of plugin.
194
+
195
+ Returns:
196
+ Plugin description
197
+ """
198
+ return "Defines a docker command"
199
+
200
+ def get_type(self) -> Type[DockerTask]:
201
+ """
202
+ Get type of task provided by plugin.
203
+
204
+ Returns:
205
+ DockerTask
206
+ """
207
+ return DockerTask
idmtools/core/enums.py ADDED
@@ -0,0 +1,51 @@
1
+ """
2
+ Define our common enums to be used through idmtools.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ from pathlib import Path
7
+
8
+ from enum import Enum
9
+
10
+ TRUTHY_VALUES = ['1', 'y', 'yes', 'on', 'true', 't', 1, True]
11
+ # Used to store idmtools user specific config/data
12
+ IDMTOOLS_USER_HOME = Path().home().joinpath(".idmtools")
13
+
14
+
15
+ class EntityStatus(Enum):
16
+ """
17
+ EntityStatus provides status values for Experiment/Simulations/WorkItems.
18
+ """
19
+ COMMISSIONING = 'commissioning'
20
+ CREATED = 'created'
21
+ RUNNING = 'running'
22
+ SUCCEEDED = 'succeeded'
23
+ FAILED = 'failed'
24
+
25
+
26
+ class FilterMode(Enum):
27
+ """
28
+ Allows user to specify AND/OR for the filtering system.
29
+ """
30
+ AND = 0
31
+ OR = 1
32
+
33
+
34
+ class ItemType(Enum):
35
+ """
36
+ ItemTypes supported by idmtools.
37
+ """
38
+ SUITE = "Suite"
39
+ EXPERIMENT = "Experiment"
40
+ SIMULATION = "Simulation"
41
+ WORKFLOW_ITEM = "WorkItem" # On Comps this is workitems
42
+ ASSETCOLLECTION = "Asset Collection"
43
+
44
+ def __str__(self):
45
+ """
46
+ Returns a string representation of our item type.
47
+
48
+ Returns:
49
+ The string version of our enum value
50
+ """
51
+ return str(self.value)
@@ -0,0 +1,91 @@
1
+ """
2
+ Define idmtools common exception as well as idmtools system exception handler.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ import sys
7
+ import typing
8
+ from logging import getLogger
9
+
10
+ if typing.TYPE_CHECKING:
11
+ from idmtools.entities.iplatform import TPlatform
12
+
13
+ user_logger = getLogger('user')
14
+ logger = getLogger(__name__)
15
+
16
+
17
+ class ExperimentNotFound(Exception):
18
+ """
19
+ Thrown when an experiment cannot be found on a platform.
20
+ """
21
+
22
+ def __init__(self, experiment_id: str, platform: 'TPlatform' = None):
23
+ """
24
+ Initialize our ExperimentNotFound.
25
+
26
+ Args:
27
+ experiment_id: Experiment id to say wasn't found
28
+ platform: Optional platform. Used in error message
29
+ """
30
+ if platform:
31
+ super().__init__(f"Experiment with id '{experiment_id}' could not be retrieved on platform {platform}.")
32
+ else:
33
+ super().__init__(f"Experiment with id '{experiment_id}' could not be retrieved.")
34
+
35
+
36
+ class UnknownItemException(Exception):
37
+ """
38
+ Thrown when an unknown item type is passed to idmtools.
39
+
40
+ This usually occurs within the platform operation area.
41
+ """
42
+ pass
43
+
44
+
45
+ class NoPlatformException(Exception):
46
+ """
47
+ Cannot find a platform matching the one requested by user.
48
+ """
49
+ pass
50
+
51
+
52
+ class TopLevelItem(Exception):
53
+ """
54
+ Thrown when a parent of a top-level item is requested by the platform.
55
+ """
56
+ pass
57
+
58
+
59
+ class UnsupportedPlatformType(Exception):
60
+ """
61
+ Occurs when an item is not supported by a platform but is requested.
62
+ """
63
+ pass
64
+
65
+
66
+ class NoTaskFound(Exception):
67
+ """
68
+ Thrown when a simulation has no task defined.
69
+ """
70
+ pass
71
+
72
+
73
+ def idmtools_error_handler(exctype, value: Exception, tb):
74
+ """
75
+ Global exception handler. This will write our errors in a nice format as well as find document links if attached to the exception.
76
+
77
+ Args:
78
+ exctype: Type of exception
79
+ value: Value of the exception
80
+ tb: Traceback
81
+
82
+ Returns:
83
+ None
84
+ """
85
+ if hasattr(value, 'doc_link'):
86
+ from idmtools.utils.info import get_help_version_url
87
+ user_logger.error(f"{value.args[0]}. For more details, see {get_help_version_url(value.doc_link)}")
88
+
89
+ logger.exception(value)
90
+ # Call native exception manager
91
+ sys.__excepthook__(exctype, value, tb)
@@ -0,0 +1,71 @@
1
+ """
2
+ Define ExperimentFactory.
3
+
4
+ This is used mostly internally. It does allow us to support specialized experiment types when needed.
5
+
6
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
7
+ """
8
+ from logging import getLogger, DEBUG
9
+ from idmtools.entities.experiment import Experiment
10
+ from idmtools.registry import experiment_specification
11
+
12
+ logger = getLogger(__name__)
13
+
14
+
15
+ class ExperimentFactory:
16
+ """
17
+ ExperimentFactory allows creating experiments that could be derived through plugins.
18
+
19
+ """
20
+ DEFAULT_KEY = 'idmtools.entities.experiment.Experiment'
21
+
22
+ def __init__(self):
23
+ """
24
+ Initialize our factory.
25
+
26
+ On initialize, we load our plugin and build a map of ids for experiments.
27
+ """
28
+ from idmtools.registry.experiment_specification import ExperimentPlugins
29
+ self._builders = ExperimentPlugins().get_plugin_map()
30
+ aliases = dict()
31
+ # register types as full paths as well
32
+ for _model, spec in self._builders.items():
33
+ aliases[f'{spec.get_type().__module__}.{spec.get_type().__name__}'] = spec
34
+ self._builders.update(aliases)
35
+
36
+ def create(self, key, fallback=None, **kwargs) -> Experiment: # noqa: F821
37
+ """
38
+ Create an experiment of type key.
39
+
40
+ Args:
41
+ key: Experiment Type
42
+ fallback: Fallback type. If none, uses DEFAULT_KEY
43
+ **kwargs: Options to pass to the experiment object
44
+
45
+ Returns:
46
+ Experiment object that was created
47
+ """
48
+ if logger.isEnabledFor(DEBUG):
49
+ logger.debug(f"Attempting to create experiment of type {key}")
50
+
51
+ if not key:
52
+ key = self.DEFAULT_KEY
53
+ else:
54
+ logger.warning(f'Experiment type: {key}')
55
+
56
+ if key not in self._builders:
57
+ if not fallback:
58
+ raise ValueError(f"The ExperimentFactory could not create an experiment of type {key}")
59
+ else:
60
+ logger.warning(f'Could not find experiment type {key}. Using Fallback type of {fallback.__class__}')
61
+ return fallback()
62
+
63
+ model_spec: experiment_specification = self._builders.get(key)
64
+ result = model_spec.get(kwargs)
65
+
66
+ if logger.isEnabledFor(DEBUG):
67
+ logger.debug(f"Experiment created for type {key}")
68
+ return result
69
+
70
+
71
+ experiment_factory = ExperimentFactory()
@@ -0,0 +1,70 @@
1
+ """
2
+ Utility method for writing and reading id files.
3
+
4
+ ID Files allow us to reload entities like Experiment, Simulations, AssetCollections, etc from a platform through files. This can
5
+ be enabling for workflows to chain steps together, or to self-document remote outputs in the local project directory.
6
+
7
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
8
+ """
9
+ import json
10
+ from os import PathLike
11
+ from typing import Union, Dict, TYPE_CHECKING
12
+
13
+ if TYPE_CHECKING:
14
+ from idmtools.core.interfaces.ientity import IEntity
15
+
16
+
17
+ def read_id_file(filename: Union[str, PathLike]):
18
+ """
19
+ Reads an id from an id file.
20
+
21
+ An id file is in the format of
22
+
23
+ <id>::<item_type>::<config block>::<extra args>
24
+ Args:
25
+ filename:
26
+
27
+ Returns:
28
+ None
29
+ """
30
+ if isinstance(filename, PathLike):
31
+ filename = str(filename)
32
+ platform_block = None
33
+ item_id = None
34
+ item_type = None
35
+ extra_args = None
36
+ with open(filename, 'r') as id_in:
37
+ item_id = id_in.read().strip()
38
+ if "::" in item_id:
39
+ parts = item_id.split("::")
40
+ if len(parts) == 2:
41
+ item_id, item_type = item_id.split("::")
42
+ elif len(parts) == 3:
43
+ item_id, item_type, platform_block = item_id.split("::")
44
+ elif len(parts) == 4:
45
+ item_id, item_type, platform_block, extra_args = item_id.split("::")
46
+ return item_id, item_type, platform_block, extra_args
47
+
48
+
49
+ def write_id_file(filename: Union[str, PathLike], item: 'IEntity', save_platform: bool = False, platform_args: Dict = None):
50
+ """
51
+ Write an item as and id file.
52
+
53
+ Args:
54
+ filename: Filename to write file to
55
+ item: Item to write out
56
+ save_platform: When true, writes platform details to the file
57
+ platform_args: Platform arguments to write out
58
+
59
+ Returns:
60
+ None
61
+ """
62
+ from idmtools.utils.json import IDMJSONEncoder
63
+ if isinstance(filename, PathLike):
64
+ filename = str(filename)
65
+ with open(filename, 'w') as filename:
66
+ filename.write(f'{item.id}::{item.item_type}')
67
+ if save_platform and hasattr(item.platform, '_config_block'):
68
+ filename.write(f"::{item.platform._config_block}")
69
+ if platform_args:
70
+ filename.write(json.dumps(platform_args, cls=IDMJSONEncoder))
@@ -0,0 +1,5 @@
1
+ """
2
+ idmtools List of core abstract interfaces that other core objects derive from.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
@@ -0,0 +1,64 @@
1
+ """
2
+ EntityContainer definition. EntityContainer provides an envelope for a Parent to container a list of sub-items.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ import typing
7
+
8
+
9
+ if typing.TYPE_CHECKING:
10
+ from idmtools.core.interfaces.ientity import IEntity
11
+ from idmtools.core.enums import EntityStatus
12
+ from typing import List
13
+
14
+
15
+ class EntityContainer(list):
16
+ """
17
+ EntityContainer is a wrapper classes used by Experiments and Suites to wrap their children.
18
+
19
+ It provides utilities to set status on entities
20
+ """
21
+
22
+ def __init__(self, children: 'List[IEntity]' = None):
23
+ """
24
+ Initialize the EntityContainer.
25
+
26
+ Args:
27
+ children: Children to initialize with
28
+ """
29
+ super().__init__()
30
+ self.extend(children or [])
31
+
32
+ def set_status(self, status: 'EntityStatus'):
33
+ """
34
+ Set status on all the children.
35
+
36
+ Args:
37
+ status: Status to set
38
+
39
+ Returns:
40
+ None
41
+ """
42
+ for entity in self:
43
+ entity.status = status
44
+
45
+ def set_status_for_item(self, item_id, status: 'EntityStatus'):
46
+ """
47
+ Set status for specific sub-item.
48
+
49
+ Args:
50
+ item_id: Item id to set status for
51
+ status: Status to set
52
+
53
+ Returns:
54
+ None
55
+
56
+ Raises:
57
+ ValueError when the item_id is not in the children list
58
+ """
59
+ for entity in self:
60
+ if str(entity.uid) == str(item_id):
61
+ entity.status = status
62
+ return
63
+
64
+ raise ValueError(f"Item with id {item_id} not found in the container")
@@ -0,0 +1,58 @@
1
+ """
2
+ IAssetsEnabled interface definition.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ from abc import ABCMeta, abstractmethod
7
+ from dataclasses import dataclass, field
8
+ from typing import NoReturn, Union
9
+ from idmtools.assets import TAsset, TAssetList
10
+ from idmtools.assets.asset_collection import AssetCollection
11
+
12
+
13
+ @dataclass
14
+ class IAssetsEnabled(metaclass=ABCMeta):
15
+ """
16
+ Base class for objects containing an asset collection.
17
+ """
18
+ assets: AssetCollection = field(default_factory=lambda: AssetCollection(), compare=False,
19
+ metadata={"pickle_ignore": True})
20
+
21
+ def __post_init__(self):
22
+ """
23
+ Post init. Nothing needed for IAssetsEnabled.
24
+
25
+ Returns:
26
+ None
27
+ """
28
+ pass
29
+
30
+ @abstractmethod
31
+ def gather_assets(self) -> NoReturn:
32
+ """
33
+ Function called at runtime to gather all assets in the collection.
34
+ """
35
+ pass
36
+
37
+ def add_assets(self, assets: Union[TAssetList, AssetCollection] = None, fail_on_duplicate: bool = True) -> NoReturn:
38
+ """
39
+ Add more assets to :class:`~idmtools.assets.asset_collection.AssetCollection`.
40
+ """
41
+ for asset in assets:
42
+ self.assets.add_asset(asset, fail_on_duplicate)
43
+
44
+ def add_asset(self, asset: Union[str, 'TAsset'] = None, fail_on_duplicate: bool = True) -> NoReturn:
45
+ """
46
+ Add an asset to our item.
47
+
48
+ Args:
49
+ asset: Asset to add. Asset can be a string in which case it is assumed to be a file path
50
+ fail_on_duplicate: Should we rain an exception if there is an existing file with same information
51
+
52
+ Returns:
53
+ None
54
+
55
+ Raise:
56
+ DuplicatedAssetError in cases where fail_on_duplicate are true
57
+ """
58
+ self.assets.add_asset(asset, fail_on_duplicate)