idmtools 0.0.0.dev0__py3-none-any.whl → 0.0.3__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.3.dist-info/METADATA +120 -0
  112. idmtools-0.0.3.dist-info/RECORD +116 -0
  113. idmtools-0.0.3.dist-info/entry_points.txt +9 -0
  114. idmtools-0.0.3.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.3.dist-info}/WHEEL +0 -0
  118. {idmtools-0.0.0.dev0.dist-info → idmtools-0.0.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,348 @@
1
+ """
2
+ idmtools SimulationBuilder definition.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ import inspect
7
+ import numpy as np
8
+ import pandas as pd
9
+ from functools import partial
10
+ from inspect import signature
11
+ from itertools import product
12
+ from typing import Callable, Any, Iterable, Union, Dict, Sized, NoReturn
13
+ from idmtools.entities.simulation import Simulation
14
+ from idmtools.utils.collections import duplicate_list_of_generators
15
+
16
+ TSweepFunction = Union[
17
+ Callable[[Simulation, Any], Dict[str, Any]],
18
+ partial
19
+ ]
20
+
21
+
22
+ class SimulationBuilder:
23
+ """
24
+ Class that represents an experiment builder.
25
+
26
+ Examples:
27
+ .. literalinclude:: ../../examples/builders/simulation_builder.py
28
+
29
+ Add tags with builder callbacks::
30
+
31
+ def update_sim(sim, parameter, value):
32
+ sim.task.set_parameter(parameter, value)
33
+ # set sim tasks,
34
+ return {'custom': 123, parameter:value)
35
+
36
+ builder = SimulationBuilder()
37
+ set_run_number = partial(update_sim, param="Run_Number")
38
+ builder.add_sweep_definition(set_run_number, range(0, 2))
39
+ # create experiment from builder
40
+ exp = Experiment.from_builder(builder, task, name=expname)
41
+ """
42
+ # The keyword searched in the function used for sweeps
43
+ SIMULATION_ATTR = 'simulation'
44
+
45
+ def __init__(self):
46
+ """
47
+ Constructor.
48
+ """
49
+ self.sweeps = []
50
+ self.__count = 0
51
+
52
+ @property
53
+ def count(self):
54
+ """
55
+ Get the count property.
56
+ Returns:
57
+ count
58
+ """
59
+ return self.__count
60
+
61
+ @count.setter
62
+ def count(self, cnt):
63
+ """
64
+ Set the count property.
65
+ Args:
66
+ cnt: count set
67
+ Returns:
68
+ int
69
+ """
70
+ if self.__count == 0:
71
+ self.__count = cnt
72
+ else:
73
+ self.__count = self.__count * cnt
74
+
75
+ def add_sweep_definition(self, function: TSweepFunction, *args, **kwargs):
76
+ """
77
+ Add a sweep definition callback that takes possible multiple parameters (None or many).
78
+
79
+ The sweep will be defined as a cross-product between the parameters passed.
80
+
81
+ Args:
82
+ function: The sweep function, which must include a **simulation** parameter (or
83
+ whatever is specified in :attr:`~idmtools.builders.ExperimentBuilder.SIMULATION_ATTR`).
84
+ args: List of arguments to be passed
85
+ kwargs: List of keyword arguments to be passed
86
+
87
+ Returns:
88
+ None. Updates the Sweeps
89
+
90
+ Examples:
91
+ Examples of valid functions::
92
+
93
+ # This function takes one parameter
94
+ def myFunction(simulation, parameter_a):
95
+ pass
96
+
97
+ # This function takes one parameter with default value
98
+ def myFunction(simulation, parameter_a=6):
99
+ pass
100
+
101
+ # This function takes two parameters (parameters may have default values)
102
+ def myFunction(simulation, parameter_a, parameter_b=9):
103
+ pass
104
+
105
+ # Function that takes three parameters (parameters may have default values)
106
+ def three_param_callback(simulation, parameter_a, parameter_b, parameter_c=10):
107
+ pass
108
+
109
+ Calling Sweeps that take multiple parameters::
110
+
111
+ # This example references the above valid function example
112
+ sb = SimulationBuilder()
113
+
114
+ # Add a sweep on the myFunction that takes parameter(s).
115
+ # Here we sweep the values 1-4 on parameter_a and a,b on parameter_b
116
+ sb.add_sweep_definition(myFunction, range(1,5), ["a", "b"])
117
+
118
+ sb2 = SimulationBuilder()
119
+ # Example calling using a dictionary instead
120
+ sb.add_sweep_definition(three_param_callback, dict(parameter_a=range(1,5), parameter_b=["a", "b"], parameter_c=range(4,5))
121
+ # The following is equivalent
122
+ sb.add_sweep_definition(three_param_callback, **dict(parameter_a=range(1,5), parameter_b=["a", "b"], parameter_c=range(4,5))
123
+
124
+ sb3 = SimulationBuilder()
125
+ # If all parameters have default values, we can even simply do
126
+ sb3.add_sweep_definition(three_param_callback)
127
+
128
+ Remark: in general::
129
+
130
+ def my_callback(simulation, parameter_1, parameter_2, ..., parameter_n):
131
+ pass
132
+
133
+ Calling Sweeps that take multiple parameters::
134
+
135
+ sb = SimulationBuilder()
136
+ sb.add_sweep_definition(my_callback, Iterable_1, Iterable_2, ..., Iterable_m)
137
+
138
+ # Note: the # of Iterable object must match the parameters # of my_callback, which don't have default values
139
+
140
+ # Or use the key (parameter names)
141
+
142
+ sb = SimulationBuilder()
143
+ sb.add_sweep_definition(my_callback, parameter_1=Iterable_1, parameter_2=Iterable_2, ..., parameter_m=Iterable_m)
144
+ # The following is equivalent
145
+ sb.add_sweep_definition(my_callback, dict(parameter_1=Iterable_1, parameter_2=Iterable_2, ..., parameter_m=Iterable_m))
146
+ # and
147
+ sb.add_sweep_definition(my_callback, **dict(parameter_1=Iterable_1, parameter_2=Iterable_2, ..., parameter_m=Iterable_m))
148
+ """
149
+ remaining_parameters = self._extract_remaining_parameters(function)
150
+
151
+ if len(args) > 0 and len(kwargs) > 0:
152
+ raise ValueError(
153
+ "Currently in multi-argument sweep definitions, you have to supply either a arguments or keyword arguments, but not both.")
154
+ if len(args) > 0:
155
+ # args is always a tuple
156
+ values = args
157
+ # Consider special case: make it easy to use
158
+ if len(values) == 1 and isinstance(values[0], dict):
159
+ values = values[0]
160
+ self.case_kwargs(function, remaining_parameters, values)
161
+ else:
162
+ self.case_args_tuple(function, remaining_parameters, values)
163
+ elif len(kwargs) > 0:
164
+ values = kwargs
165
+ self.case_kwargs(function, remaining_parameters, values)
166
+ else:
167
+ required_params = self._extract_required_parameters(remaining_parameters)
168
+ if len(required_params) > 0:
169
+ raise ValueError(f"Missing arguments: {list(required_params)}.")
170
+ self.sweeps.append((function,))
171
+ self.count = 1
172
+
173
+ def _extract_remaining_parameters(self, function):
174
+ # Retrieve all the parameters in the signature of the function
175
+ parameters = signature(function).parameters
176
+ # Ensure `simulation` is part of the parameter list
177
+ if self.SIMULATION_ATTR not in parameters:
178
+ raise ValueError(f"The callback function passed to SweepBuilder.add_sweep_definition "
179
+ f"needs to take a {self.SIMULATION_ATTR} argument!")
180
+ # Retrieve all the free parameters of the signature (other than `simulation`)
181
+ remaining_parameters = {name: param.default for name, param in parameters.items() if
182
+ name != self.SIMULATION_ATTR}
183
+ return remaining_parameters
184
+
185
+ def case_args_tuple(self, function: TSweepFunction, remaining_parameters, values) -> NoReturn:
186
+ """
187
+ Handle the case where the values are passed as a tuple.
188
+ Args:
189
+ function: sweep function
190
+ remaining_parameters: parameters
191
+ values: values
192
+ Returns:
193
+ No return
194
+ """
195
+ # this is len(values) > 0 case
196
+ required_params = self._extract_required_parameters(remaining_parameters)
197
+ _values = [self._validate_value(vals) for vals in values]
198
+
199
+ if len(required_params) > 0 and len(required_params) != len(values):
200
+ if len(remaining_parameters) != len(values):
201
+ raise ValueError(
202
+ f"Currently the callback has {len(required_params)} required parameters and callback has {len(remaining_parameters)} parameters but there were {len(values)} arguments passed.")
203
+ else:
204
+ # Handle special case
205
+ generated_values = product(*_values)
206
+ self.sweeps.append(
207
+ partial(function, **self._map_argument_array(list(remaining_parameters), v)) for v in
208
+ generated_values)
209
+ self.count = np.prod(list(map(len, _values)))
210
+ return
211
+
212
+ if len(required_params) == 0 and len(values) > 1:
213
+ raise ValueError(
214
+ f"Currently the callback {len(remaining_parameters)} parameters (all have default values) and there were {len(values)} arguments passed.")
215
+
216
+ if len(required_params) == 0 and len(remaining_parameters) != 1:
217
+ raise ValueError(
218
+ f"Currently the callback has {len(remaining_parameters)} parameters (all have default values) and there were {len(values)} arguments passed.")
219
+
220
+ # Now we come to two cases
221
+ # 1. len(required_params) > 0 and len(required_params) == len(values)
222
+ # 2. len(required_params) == 0 and len(remaining_parameters) == 1 and len(values) == 1
223
+ # create sweeps using the multi-index
224
+ generated_values = product(*_values)
225
+ if len(required_params) > 0:
226
+ self.sweeps.append(
227
+ partial(function, **self._map_argument_array(list(required_params), v)) for v in
228
+ generated_values)
229
+ else:
230
+ self.sweeps.append(
231
+ partial(function, **self._map_argument_array(list(remaining_parameters), v)) for v in
232
+ generated_values)
233
+
234
+ self.count = np.prod(list(map(len, _values)))
235
+
236
+ def case_kwargs(self, function: TSweepFunction, remaining_parameters, values) -> NoReturn:
237
+ """
238
+ Handle the case where the values are passed as a dictionary.
239
+ Args:
240
+ function: sweep function
241
+ remaining_parameters: parameters
242
+ values: values
243
+ Returns:
244
+ No return
245
+ """
246
+ required_params = self._extract_required_parameters(remaining_parameters)
247
+ extra_inputs = list(set(values) - set(remaining_parameters))
248
+ if len(extra_inputs) > 0:
249
+ raise ValueError(
250
+ f"Extra arguments passed: {extra_inputs if len(extra_inputs) > 1 else extra_inputs[0]}.")
251
+
252
+ missing_params = list(set(required_params) - set(values))
253
+ if len(missing_params) > 0:
254
+ raise ValueError(
255
+ f"Missing arguments: {missing_params if len(missing_params) > 1 else missing_params[0]}.")
256
+
257
+ # validate each values in a dict
258
+ _values = {key: self._validate_value(vals) for key, vals in values.items()}
259
+ generated_values = product(*_values.values())
260
+ self.sweeps.append(
261
+ partial(function, **self._map_argument_array(_values.keys(), v)) for v in generated_values)
262
+ self.count = np.prod(list(map(len, _values.values())))
263
+
264
+ def add_multiple_parameter_sweep_definition(self, function: TSweepFunction, *args, **kwargs):
265
+ """
266
+ Add a sweep definition callback that takes possible multiple parameters (None or many).
267
+
268
+ The sweep will be defined as a cross-product between the parameters passed.
269
+
270
+ Args:
271
+ function: The sweep function, which must include a **simulation** parameter (or
272
+ whatever is specified in :attr:`~idmtools.builders.ExperimentBuilder.SIMULATION_ATTR`).
273
+ args: List of arguments to be passed
274
+ kwargs: List of keyword arguments to be passed
275
+
276
+ Returns:
277
+ None. Updates the Sweeps
278
+
279
+ Examples:
280
+ Refer to the comments in the add_sweep_definition function for examples
281
+ """
282
+ self.add_sweep_definition(function, *args, **kwargs)
283
+
284
+ def _validate_value(self, value):
285
+ """
286
+ Validate inputs.
287
+ Args:
288
+ value: input
289
+ Returns:
290
+ validated value
291
+ """
292
+ if isinstance(value, str):
293
+ return [value]
294
+ elif not isinstance(value, Iterable):
295
+ return [value]
296
+ # elif hasattr(value, '__len__'):
297
+ elif isinstance(value, Sized):
298
+ if isinstance(value, (dict, pd.DataFrame)):
299
+ return [value]
300
+ else:
301
+ return value
302
+ else:
303
+ return list(value)
304
+
305
+ @staticmethod
306
+ def _map_argument_array(parameters, value_set, remainder: str = None) -> Dict[str, Iterable]:
307
+ """
308
+ Map multi-argument calls to parameters in a callback.
309
+ Args:
310
+ parameters: Parameters
311
+ value_set: List of values that should be sent to parameter in calls
312
+ remainder: Remainder
313
+ Returns:
314
+ Dictionary to map our call to our callbacks
315
+ """
316
+ call_args = dict()
317
+ for idx, parameter in enumerate(parameters):
318
+ call_args[parameter] = value_set[idx]
319
+
320
+ if remainder:
321
+ return {remainder: call_args}
322
+ else:
323
+ return call_args
324
+
325
+ def _extract_required_parameters(self, remaining_parameters: Dict) -> Dict:
326
+ required_params = {k: v for k, v in remaining_parameters.items() if
327
+ not isinstance(v, pd.DataFrame) and v == inspect.Parameter.empty}
328
+ return required_params
329
+
330
+ def __iter__(self):
331
+ """
332
+ Iterator of the simulation builder.
333
+ We duplicate the generators here so that we can loop over multiple times.
334
+ Returns:
335
+ The iterator
336
+ """
337
+ old_sw, new_sw = duplicate_list_of_generators(self.sweeps)
338
+
339
+ yield from product(*old_sw)
340
+ self.sweeps = new_sw
341
+
342
+ def __len__(self):
343
+ """
344
+ Total simulations to be built by builder. This is a Product of all total values for each sweep.
345
+ Returns:
346
+ Simulation count
347
+ """
348
+ return self.count
@@ -0,0 +1,109 @@
1
+ """
2
+ idmtools SimulationBuilder definition.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ from enum import Enum
7
+ from functools import partial
8
+ from itertools import product, tee
9
+ from typing import Callable, Any, Iterable, Union, List, Tuple, Dict
10
+ from idmtools.builders import SimulationBuilder
11
+ from idmtools.entities.simulation import Simulation
12
+
13
+ TSweepFunction = Union[
14
+ Callable[[Simulation, Any], Dict[str, Any]], partial
15
+ ]
16
+
17
+
18
+ class ArmType(Enum):
19
+ """
20
+ ArmTypes.
21
+ """
22
+ cross = 0
23
+ pair = 1
24
+
25
+
26
+ class SweepArm(SimulationBuilder):
27
+ """
28
+ Class that represents a section of simulation sweeping.
29
+ """
30
+
31
+ def __init__(self, type=ArmType.cross, funcs: List[Tuple[Callable, Iterable]] = None):
32
+ """
33
+ Constructor.
34
+ """
35
+ self.type = type
36
+ self.__count = 0
37
+ self.__functions = None
38
+ super().__init__()
39
+
40
+ if funcs is None:
41
+ funcs = []
42
+ for func, values in funcs:
43
+ self.add_sweep_definition(func, values)
44
+
45
+ @property
46
+ def count(self):
47
+ """Return simulations count."""
48
+ return self.__count
49
+
50
+ @count.setter
51
+ def count(self, cnt):
52
+ """
53
+ Set simulations count.
54
+ Args:
55
+ cnt: count to set
56
+ Returns:
57
+ None
58
+ """
59
+ if self.__count == 0:
60
+ self.__count = cnt
61
+ elif self.type == ArmType.cross:
62
+ self.__count = self.__count * cnt
63
+ elif self.type == ArmType.pair:
64
+ if self.__count != cnt:
65
+ raise ValueError(f"For pair case, all function inputs must have the same size/length: {cnt} != {self.__count}")
66
+ else:
67
+ self.__count = cnt
68
+
69
+ @property
70
+ def functions(self):
71
+ """
72
+ Get functions.
73
+ Returns:
74
+ functions
75
+ """
76
+ old_sw, new_sw = tee(self.__functions, 2)
77
+ self.__functions = new_sw
78
+ return old_sw
79
+
80
+ @functions.setter
81
+ def functions(self, funcs):
82
+ self.__functions = funcs
83
+
84
+ def _update_sweep_functions(self):
85
+ result = []
86
+ if len(self.sweeps) == 0:
87
+ result = []
88
+ elif self.type == ArmType.cross:
89
+ result = product(*self.sweeps)
90
+ elif self.type == ArmType.pair:
91
+ result = zip(*self.sweeps)
92
+
93
+ self.__functions = result
94
+
95
+ def _update_count(self, values):
96
+ """
97
+ Update count of sweeps.
98
+ Args:
99
+ values: Values to count
100
+ Returns:
101
+ None
102
+ """
103
+ if self.count == 0:
104
+ if len(values) == 0:
105
+ self.count = 1
106
+ else:
107
+ self.count = len(values)
108
+ else:
109
+ self.count = len(values)
@@ -0,0 +1,82 @@
1
+ """
2
+ idmtools YamlSimulationBuilder definition.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ import yaml
7
+ from logging import getLogger
8
+ from typing import Union, Callable, Dict, Any
9
+ from idmtools.builders import ArmSimulationBuilder, SweepArm
10
+
11
+ logger = getLogger(__name__)
12
+
13
+
14
+ class DefaultParamFuncDict(dict):
15
+ """
16
+ Enables a function that takes a single parameter and return another function.
17
+
18
+ Notes:
19
+ TODO Add Example and types
20
+ """
21
+
22
+ def __init__(self, default):
23
+ """
24
+ Initialize our DefaultParamFuncDict.
25
+ Args:
26
+ default: Default function to use
27
+ """
28
+ super().__init__()
29
+ self.__default = default
30
+
31
+ def __getitem__(self, item):
32
+ """
33
+ Get item from the DefaultParamFuncDict. It proxies most calls to the function we wrap.
34
+ Args:
35
+ item: Item to lookup
36
+ Returns:
37
+ None
38
+ """
39
+ if item in self:
40
+ return super().__getitem__(item)
41
+ else:
42
+ return self.__default(item)
43
+
44
+
45
+ class YamlSimulationBuilder(ArmSimulationBuilder):
46
+ """
47
+ Class that represents an experiment builder.
48
+ Examples:
49
+ .. literalinclude:: ../../examples/builders/yaml_builder_python.py
50
+ """
51
+
52
+ def add_sweeps_from_file(self, file_path, func_map: Union[Dict[str, Callable], Callable[[Any], Dict]] = None):
53
+ """
54
+ Add sweeps from a file.
55
+ Args:
56
+ file_path: Path to file
57
+ func_map: Optional function map
58
+ Returns:
59
+ None
60
+ """
61
+ if func_map is None:
62
+ func_map = {}
63
+ # if the user passing a single function, map it to all values
64
+ elif callable(func_map):
65
+ func_map = DefaultParamFuncDict(func_map)
66
+ with open(file_path, 'r') as stream:
67
+ try:
68
+ parsed = yaml.safe_load(stream)
69
+ except yaml.YAMLError as exc:
70
+ logger.exception(exc)
71
+ exit()
72
+
73
+ d_funcs = parsed.values()
74
+
75
+ for sweeps in list(d_funcs):
76
+ sweeps_tuples = ((list(d.keys())[0], list(d.values())[0]) for d in sweeps)
77
+ funcs = []
78
+ for func, values in sweeps_tuples:
79
+ funcs.append((func_map[func], values))
80
+
81
+ arm = SweepArm(funcs=funcs)
82
+ self.add_arm(arm)
@@ -0,0 +1,7 @@
1
+ """
2
+ idmtools Configuration tools/Manager.
3
+
4
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
5
+ """
6
+ # flake8: noqa F821
7
+ from idmtools.config.idm_config_parser import IdmConfigParser