idmtools-test 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 (141) hide show
  1. idmtools_test/__init__.py +16 -8
  2. idmtools_test/inputs/__init__.py +0 -0
  3. idmtools_test/inputs/assets/collections/1/a.txt +0 -0
  4. idmtools_test/inputs/assets/collections/1/b.txt +0 -0
  5. idmtools_test/inputs/assets/collections/2/c.txt +0 -0
  6. idmtools_test/inputs/assets/collections/d.txt +0 -0
  7. idmtools_test/inputs/builder/sweeps.csv +6 -0
  8. idmtools_test/inputs/builder/sweeps.yaml +8 -0
  9. idmtools_test/inputs/compsplatform/__init__.py +0 -0
  10. idmtools_test/inputs/compsplatform/failing_model.py +5 -0
  11. idmtools_test/inputs/compsplatform/mixed_model.py +10 -0
  12. idmtools_test/inputs/compsplatform/working_model.py +5 -0
  13. idmtools_test/inputs/configuration/idmtools_test.ini +71 -0
  14. idmtools_test/inputs/custom/Eradication.exe +0 -0
  15. idmtools_test/inputs/custom/Local_Migration.bin +0 -0
  16. idmtools_test/inputs/custom/Local_Migration.bin.json +12 -0
  17. idmtools_test/inputs/custom/Regional_Migration.bin +0 -0
  18. idmtools_test/inputs/custom/Regional_Migration.bin.json +12 -0
  19. idmtools_test/inputs/custom/Zambia_30arcsec_air_temperature_daily.bin +0 -0
  20. idmtools_test/inputs/custom/Zambia_30arcsec_air_temperature_daily.bin.json +26 -0
  21. idmtools_test/inputs/custom/Zambia_30arcsec_rainfall_daily.bin +0 -0
  22. idmtools_test/inputs/custom/Zambia_30arcsec_rainfall_daily.bin.json +26 -0
  23. idmtools_test/inputs/custom/Zambia_30arcsec_relative_humidity_daily.bin +0 -0
  24. idmtools_test/inputs/custom/Zambia_30arcsec_relative_humidity_daily.bin.json +26 -0
  25. idmtools_test/inputs/custom/campaign.json +95384 -0
  26. idmtools_test/inputs/custom/config.json +943 -0
  27. idmtools_test/inputs/custom/custom_reports.json +163 -0
  28. idmtools_test/inputs/custom/demo.json +1258 -0
  29. idmtools_test/inputs/custom/emodules_map.json +9 -0
  30. idmtools_test/inputs/custom/reporter_plugins/libReportMalariaFiltered.dll +0 -0
  31. idmtools_test/inputs/custom/reporter_plugins/libSpatialReportMalariaFiltered.dll +0 -0
  32. idmtools_test/inputs/custom/reporter_plugins/libreporteventcounter.dll +0 -0
  33. idmtools_test/inputs/duplicated_model/exe/Eradication +0 -0
  34. idmtools_test/inputs/duplicated_model/f1 +0 -0
  35. idmtools_test/inputs/emod/Eradication.exe +0 -0
  36. idmtools_test/inputs/emod_files/campaign.json +21 -0
  37. idmtools_test/inputs/emod_files/config.json +125 -0
  38. idmtools_test/inputs/emod_files/demographics.json +81 -0
  39. idmtools_test/inputs/fakemodels/AnotherOne +0 -0
  40. idmtools_test/inputs/fakemodels/Eradication +0 -0
  41. idmtools_test/inputs/fakemodels/Eradication-2.11.custom.exe +0 -0
  42. idmtools_test/inputs/fakemodels/Eradication.exe +0 -0
  43. idmtools_test/inputs/files/campaign.json +21 -0
  44. idmtools_test/inputs/files/config.json +119 -0
  45. idmtools_test/inputs/files/demographics.json +82 -0
  46. idmtools_test/inputs/files/hello.txt +1 -0
  47. idmtools_test/inputs/id_files/slurm.example_python_experiment.id +1 -0
  48. idmtools_test/inputs/malaria_brazil_central_west_spatial/Assets/Brazil_Central_West_Brazil_Central_West_2.5arcmin_air_temperature_daily.bin +0 -0
  49. idmtools_test/inputs/malaria_brazil_central_west_spatial/Assets/Brazil_Central_West_Brazil_Central_West_2.5arcmin_air_temperature_daily.bin.json +26 -0
  50. idmtools_test/inputs/malaria_brazil_central_west_spatial/Assets/Brazil_Central_West_Brazil_Central_West_2.5arcmin_demographics.json +559 -0
  51. idmtools_test/inputs/malaria_brazil_central_west_spatial/Assets/Brazil_Central_West_Brazil_Central_West_2.5arcmin_rainfall_daily.bin +0 -0
  52. idmtools_test/inputs/malaria_brazil_central_west_spatial/Assets/Brazil_Central_West_Brazil_Central_West_2.5arcmin_rainfall_daily.bin.json +26 -0
  53. idmtools_test/inputs/malaria_brazil_central_west_spatial/Assets/Brazil_Central_West_Brazil_Central_West_2.5arcmin_relative_humidity_daily.bin +0 -0
  54. idmtools_test/inputs/malaria_brazil_central_west_spatial/Assets/Brazil_Central_West_Brazil_Central_West_2.5arcmin_relative_humidity_daily.bin.json +26 -0
  55. idmtools_test/inputs/malaria_brazil_central_west_spatial/Assets/Eradication +0 -0
  56. idmtools_test/inputs/malaria_brazil_central_west_spatial/Assets/Eradication.exe +0 -0
  57. idmtools_test/inputs/malaria_brazil_central_west_spatial/campaign.json +4 -0
  58. idmtools_test/inputs/malaria_brazil_central_west_spatial/config.json +667 -0
  59. idmtools_test/inputs/malaria_brazil_central_west_spatial/malaria_brazil_central_west_spatial-ERA5Input_demo.csv +37 -0
  60. idmtools_test/inputs/python/Assets/MyExternalLibrary/__init__.py +0 -0
  61. idmtools_test/inputs/python/Assets/MyExternalLibrary/functions.py +15 -0
  62. idmtools_test/inputs/python/Assets/MyLib/functions.py +2 -0
  63. idmtools_test/inputs/python/Assets/MyLib/temp.py +271 -0
  64. idmtools_test/inputs/python/Assets/__init__.py +0 -0
  65. idmtools_test/inputs/python/__init__.py +0 -0
  66. idmtools_test/inputs/python/folder_dup_file/__init__.py +0 -0
  67. idmtools_test/inputs/python/folder_dup_file/model1.py +19 -0
  68. idmtools_test/inputs/python/hello_world.py +1 -0
  69. idmtools_test/inputs/python/model.py +26 -0
  70. idmtools_test/inputs/python/model1.py +20 -0
  71. idmtools_test/inputs/python/model3.py +21 -0
  72. idmtools_test/inputs/python/newmodel2.py +20 -0
  73. idmtools_test/inputs/python/output_generator/generate.py +39 -0
  74. idmtools_test/inputs/python/realpath_verify.py +6 -0
  75. idmtools_test/inputs/python/ye_seir_model/Assets/MyExternalLibrary/Python36/dtk_generic_intrahost.pyd +0 -0
  76. idmtools_test/inputs/python/ye_seir_model/Assets/MyExternalLibrary/Python36/dtk_nodedemog.pyd +0 -0
  77. idmtools_test/inputs/python/ye_seir_model/Assets/MyExternalLibrary/Python37/dtk_generic_intrahost.pyd +0 -0
  78. idmtools_test/inputs/python/ye_seir_model/Assets/MyExternalLibrary/Python37/dtk_nodedemog.pyd +0 -0
  79. idmtools_test/inputs/python/ye_seir_model/Assets/SEIR_model.py +252 -0
  80. idmtools_test/inputs/python/ye_seir_model/Assets/SEIR_model_slurm.py +242 -0
  81. idmtools_test/inputs/python/ye_seir_model/Assets/config_sim.py +48 -0
  82. idmtools_test/inputs/python/ye_seir_model/Assets/custom_csv_analyzer.py +133 -0
  83. idmtools_test/inputs/python/ye_seir_model/Assets/python.sh +4 -0
  84. idmtools_test/inputs/python/ye_seir_model/Assets/requirements.txt +4 -0
  85. idmtools_test/inputs/python/ye_seir_model/Assets/templates/config.json +68 -0
  86. idmtools_test/inputs/python/ye_seir_model/Assets/templates/demographics_template.json +44 -0
  87. idmtools_test/inputs/python/ye_seir_model/__init__.py +0 -0
  88. idmtools_test/inputs/python_experiments/__init__.py +0 -0
  89. idmtools_test/inputs/python_experiments/model.py +10 -0
  90. idmtools_test/inputs/r/model1.R +1 -0
  91. idmtools_test/inputs/r/ncov_analysis/individual_dynamics_estimates/estimate_incubation_period.R +89 -0
  92. idmtools_test/inputs/regression/107/Assets/__init__.py +0 -0
  93. idmtools_test/inputs/regression/107/Assets/model.py +1 -0
  94. idmtools_test/inputs/regression/107/__init__.py +0 -0
  95. idmtools_test/inputs/regression/125/Assets/__init__.py +0 -0
  96. idmtools_test/inputs/regression/125/Assets/model.py +1 -0
  97. idmtools_test/inputs/regression/125/Assets2/__init__.py +0 -0
  98. idmtools_test/inputs/regression/125/Assets2/dir1/__init__.py +0 -0
  99. idmtools_test/inputs/regression/125/Assets2/dir1/model.py +1 -0
  100. idmtools_test/inputs/regression/125/Assets2/dir2/__init__.py +0 -0
  101. idmtools_test/inputs/regression/125/Assets2/dir2/model.py +1 -0
  102. idmtools_test/inputs/regression/125/__init__.py +0 -0
  103. idmtools_test/inputs/regression/__init__.py +0 -0
  104. idmtools_test/inputs/scheduling/hpc/WorkOrder.json +7 -0
  105. idmtools_test/inputs/scheduling/slurm/WorkOrder.json +11 -0
  106. idmtools_test/inputs/scheduling/slurm/WorkOrder1.json +11 -0
  107. idmtools_test/inputs/scheduling/slurm/WorkOrder2.json +13 -0
  108. idmtools_test/inputs/scheduling/slurm/commandline_model.py +22 -0
  109. idmtools_test/inputs/serialization/Eradication.exe +0 -0
  110. idmtools_test/inputs/serialization/single_node_demographics.json +82 -0
  111. idmtools_test/inputs/singularity/alpine_simple/Singularity.def +28 -0
  112. idmtools_test/inputs/singularity/alpine_simple/run_model.py +41 -0
  113. idmtools_test/inputs/singularity/alpine_template/Singularity.jinja +22 -0
  114. idmtools_test/test_precreate_hooks.py +25 -0
  115. idmtools_test/utils/__init__.py +0 -0
  116. idmtools_test/utils/cli.py +41 -0
  117. idmtools_test/utils/common_experiments.py +79 -0
  118. idmtools_test/utils/comps.py +152 -0
  119. idmtools_test/utils/decorators.py +208 -0
  120. idmtools_test/utils/execute_operations/__init__.py +0 -0
  121. idmtools_test/utils/execute_operations/experiment_operations.py +237 -0
  122. idmtools_test/utils/execute_operations/simulate_operations.py +368 -0
  123. idmtools_test/utils/itest_with_persistence.py +25 -0
  124. idmtools_test/utils/operations/__init__.py +0 -0
  125. idmtools_test/utils/operations/experiment_operations.py +64 -0
  126. idmtools_test/utils/operations/simulation_operations.py +114 -0
  127. idmtools_test/utils/shared_functions.py +25 -0
  128. idmtools_test/utils/test_asset.py +89 -0
  129. idmtools_test/utils/test_asset_collection.py +223 -0
  130. idmtools_test/utils/test_execute_platform.py +137 -0
  131. idmtools_test/utils/test_platform.py +94 -0
  132. idmtools_test/utils/test_task.py +69 -0
  133. idmtools_test/utils/utils.py +146 -0
  134. idmtools_test-0.0.2.dist-info/METADATA +48 -0
  135. idmtools_test-0.0.2.dist-info/RECORD +139 -0
  136. idmtools_test-0.0.2.dist-info/entry_points.txt +9 -0
  137. idmtools_test-0.0.2.dist-info/licenses/LICENSE.TXT +3 -0
  138. idmtools_test-0.0.0.dev0.dist-info/METADATA +0 -41
  139. idmtools_test-0.0.0.dev0.dist-info/RECORD +0 -5
  140. {idmtools_test-0.0.0.dev0.dist-info → idmtools_test-0.0.2.dist-info}/WHEEL +0 -0
  141. {idmtools_test-0.0.0.dev0.dist-info → idmtools_test-0.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,223 @@
1
+ import os
2
+ import typing
3
+ from typing import NoReturn
4
+
5
+ from idmtools.assets import TAssetList, TAssetFilterList, TAsset
6
+ from idmtools.assets.errors import DuplicatedAssetError
7
+ from idmtools.core import FilterMode
8
+ from idmtools.core.interfaces.ientity import IEntity
9
+ from idmtools.frozen.frozen_utils import IFrozen
10
+ from idmtools.utils.file import scan_directory
11
+ from idmtools.utils.filters.asset_filters import default_asset_file_filter
12
+ from idmtools_test.utils.test_asset import Asset
13
+
14
+
15
+ class AssetCollection(IEntity, IFrozen):
16
+ """
17
+ A class that represents a collection of assets.
18
+ """
19
+
20
+ # region Constructors
21
+ def __init__(self, assets: 'TAssetList' = None): # noqa: F821
22
+ """
23
+ A constructor.
24
+
25
+ Args:
26
+ assets: An optional list of assets to create the collection with.
27
+ """
28
+ super().__init__()
29
+ self.assets = assets or []
30
+
31
+ @classmethod
32
+ def from_directory(cls, assets_directory: str, recursive: bool = True, flatten: bool = False,
33
+ filters: 'TAssetFilterList' = None, filters_mode: 'FilterMode' = FilterMode.OR, # noqa: F821
34
+ relative_path: str = None) -> 'TAssetCollection':
35
+ """
36
+ Fill up an :class:`AssetCollection` from the specified directory. See
37
+ :meth:`~AssetCollection.assets_from_directory` for arguments.
38
+
39
+ Returns:
40
+ A created :class:`AssetCollection` object.
41
+ """
42
+ assets = cls.assets_from_directory(assets_directory, recursive, flatten, filters, filters_mode, relative_path)
43
+ return cls(assets=assets)
44
+
45
+ # endregion
46
+
47
+ @staticmethod
48
+ def assets_from_directory(assets_directory: 'str', recursive: 'bool' = True, flatten: 'bool' = False,
49
+ filters: 'TAssetFilterList' = None, # noqa: F821
50
+ filters_mode: 'FilterMode' = FilterMode.OR,
51
+ forced_relative_path: 'str' = None) -> 'TAssetList': # noqa: F821
52
+ """
53
+ Create assets for files in a given directory.
54
+
55
+ Args:
56
+ assets_directory: The root directory of the assets.
57
+ recursive: True to recursively traverse the subdirectory.
58
+ flatten: Put all the files in root regardless of whether they were in a subdirectory or not.
59
+ filters: A list of filters to apply to the assets. The filters are functions taking an
60
+ :class:`~idmtools.assets.asset.Asset`
61
+ as argument and returning true or false. True adds the asset to the collection; False filters
62
+ it out. See :meth:`~idmtools.utils.filters.asset_filters`.
63
+ filters_mode: When given multiple filters, either OR or AND the results.
64
+ forced_relative_path: Prefix a relative path to the path created from the root directory.
65
+
66
+ Examples:
67
+ For **relative_path**, given the following folder structure root/a/1,txt root/b.txt and relative_path="test".
68
+ Will return assets with relative path: test/a/1,txt and test/b.txt
69
+
70
+ Given the previous example, if flatten is also set to True, the following relative_path will be set:
71
+ /1.txt and /b.txt
72
+
73
+ Returns:
74
+ A list of assets.
75
+ """
76
+ found_assets = []
77
+ for entry in scan_directory(assets_directory, recursive):
78
+ relative_path = os.path.relpath(os.path.dirname(entry.path), assets_directory)
79
+ found_assets.append(Asset(absolute_path=os.path.abspath(entry.path),
80
+ relative_path=None if relative_path == "." else relative_path,
81
+ filename=entry.name))
82
+
83
+ # Apply the default filter
84
+ found_assets = list(filter(default_asset_file_filter, found_assets))
85
+
86
+ # Operations on assets (filter, flatten, force relative_path)
87
+ assets = []
88
+ for asset in found_assets:
89
+ if filters:
90
+ results = [f(asset) for f in filters]
91
+ if filters_mode == FilterMode.OR and not any(results):
92
+ continue
93
+ if filters_mode == FilterMode.AND and not all(results):
94
+ continue
95
+
96
+ if flatten:
97
+ asset.relative_path = None
98
+
99
+ if forced_relative_path:
100
+ asset.relative_path = os.path.join(forced_relative_path, asset.relative_path)
101
+
102
+ assets.append(asset)
103
+
104
+ return assets
105
+
106
+ def add_directory(self, assets_directory: 'str', recursive: 'bool' = True, flatten: 'bool' = False,
107
+ filters: 'TAssetFilterList' = None, filters_mode: 'FilterMode' = FilterMode.OR, # noqa: F821
108
+ relative_path: 'str' = None):
109
+ """
110
+ Retrieve assets from the specified directory and add them to the collection.
111
+ See :meth:`~AssetCollection.assets_from_directory` for arguments.
112
+ """
113
+ assets = AssetCollection.assets_from_directory(assets_directory, recursive, flatten, filters, filters_mode,
114
+ relative_path)
115
+ for asset in assets:
116
+ self.add_asset(asset)
117
+
118
+ def add_asset(self, asset: 'TAsset', fail_on_duplicate: 'bool' = True): # noqa: F821
119
+ """
120
+ Add an asset to the collection.
121
+
122
+ Args:
123
+ asset: An :class:`~idmtools.assets.asset.Asset` object to add.
124
+ fail_on_duplicate: Raise a **DuplicateAssetError** if an asset is duplicated.
125
+ If not, simply replace it.
126
+ """
127
+ if asset in self.assets:
128
+ if fail_on_duplicate:
129
+ raise DuplicatedAssetError(asset)
130
+ else:
131
+ # The equality not considering the content of the asset, even if it is already present
132
+ # nothing guarantees that the content is the same. So remove and add the fresh one.
133
+ self.assets.remove(asset)
134
+ self.assets.append(asset)
135
+
136
+ def get_one(self, **kwargs):
137
+ """
138
+ Get an asset out of the collection based on the filers passed.
139
+ Examples:
140
+ >>> a = AssetCollection()
141
+ >>> a.get_one(filename="filename.txt")
142
+ Args:
143
+ **kwargs: keyword argument representing the filters.
144
+
145
+ Returns: None or Asset if found
146
+
147
+ """
148
+ try:
149
+ return next(filter(lambda a: all(getattr(a, k) == kwargs.get(k) for k in kwargs), self.assets))
150
+ except StopIteration:
151
+ return None
152
+
153
+ def delete(self, **kwargs) -> 'NoReturn':
154
+ """
155
+ Delete an asset based on keywords attributes
156
+
157
+ Args:
158
+ **kwargs: Filter for the asset to delete.
159
+ """
160
+ if 'index' in kwargs:
161
+ return self.assets.remove(self.assets[kwargs.get('index')])
162
+
163
+ if 'asset' in kwargs:
164
+ return self.assets.remove(kwargs.get('asset'))
165
+
166
+ asset = self.get_one(**kwargs)
167
+ if asset:
168
+ self.assets.remove(asset)
169
+
170
+ def pop(self, **kwargs) -> 'TAsset':
171
+ """
172
+ Get and delete an asset based on keywords.
173
+ Args:
174
+ **kwargs: Filter for the asset to pop.
175
+
176
+ """
177
+ if not kwargs:
178
+ return self.assets.pop()
179
+
180
+ asset = self.get_one(**kwargs)
181
+ if asset:
182
+ self.assets.remove(asset)
183
+ return asset
184
+
185
+ def extend(self, assets: 'TAssetList', fail_on_duplicate: 'bool' = True) -> 'NoReturn':
186
+ """
187
+ Extend the collection with new assets
188
+ Args:
189
+ assets: Which assets to add
190
+ fail_on_duplicate: Fail if duplicated asset is included.
191
+
192
+ """
193
+ for asset in assets:
194
+ self.add_asset(asset, fail_on_duplicate)
195
+
196
+ def clear(self):
197
+ self.assets.clear()
198
+
199
+ def set_all_persisted(self):
200
+ for a in self:
201
+ a.persisted = True
202
+
203
+ @property
204
+ def count(self):
205
+ return len(self.assets)
206
+
207
+ @IEntity.uid.getter
208
+ def uid(self):
209
+ if self.count == 0:
210
+ return None
211
+ return super().uid
212
+
213
+ def __len__(self):
214
+ return len(self.assets)
215
+
216
+ def __getitem__(self, index):
217
+ return self.assets[index]
218
+
219
+ def __iter__(self):
220
+ yield from self.assets
221
+
222
+
223
+ TAssetCollection = typing.TypeVar("TAssetCollection", bound=AssetCollection)
@@ -0,0 +1,137 @@
1
+ import copy
2
+ import os
3
+ import shutil
4
+ from concurrent.futures._base import as_completed, Executor
5
+ from concurrent.futures.process import ProcessPoolExecutor
6
+ from concurrent.futures.thread import ThreadPoolExecutor
7
+ from dataclasses import dataclass, field
8
+ from enum import Enum
9
+ from pathlib import Path
10
+ from typing import List, Union, Type
11
+ from tqdm import tqdm
12
+ from idmtools.core import ItemType
13
+ from idmtools.entities import Suite
14
+ from idmtools.entities.experiment import Experiment
15
+ from idmtools.entities.iplatform import IPlatform
16
+ from idmtools.entities.iworkflow_item import IWorkflowItem
17
+ from idmtools.entities.platform_requirements import PlatformRequirements
18
+ from idmtools.registry.platform_specification import PlatformSpecification, get_platform_impl, \
19
+ example_configuration_impl, get_platform_type_impl
20
+ from idmtools.registry.plugin_specification import get_description_impl
21
+ from idmtools_test.utils.execute_operations.experiment_operations import TestExecutePlatformExperimentOperation
22
+ from idmtools_test.utils.execute_operations.simulate_operations import TestExecutePlatformSimulationOperation
23
+
24
+ supported_types = [PlatformRequirements.SHELL, PlatformRequirements.NativeBinary, PlatformRequirements.PYTHON,
25
+ PlatformRequirements.WINDOWS if os.name == "nt" else PlatformRequirements.LINUX]
26
+
27
+
28
+ class PoolType(Enum):
29
+ thread = ThreadPoolExecutor
30
+ process = ProcessPoolExecutor
31
+
32
+
33
+ DEFAULT_OUTPUT_PATH = Path(os.getenv("IDMTOOLS_TEST_EXECUTE_PATH", Path().cwd().joinpath(".test_platform")))
34
+
35
+
36
+ def clear_execute_platform():
37
+ if Path.exists(DEFAULT_OUTPUT_PATH):
38
+ for file in os.listdir(DEFAULT_OUTPUT_PATH):
39
+ path = Path(DEFAULT_OUTPUT_PATH).joinpath(file)
40
+ try:
41
+ shutil.rmtree(path)
42
+ except OSError:
43
+ os.remove(path)
44
+
45
+
46
+ @dataclass(repr=False)
47
+ class TestExecutePlatform(IPlatform):
48
+ _experiments: TestExecutePlatformExperimentOperation = field(
49
+ default=None, compare=False, metadata={"pickle_ignore": True}, repr=False, init=False
50
+ )
51
+ _simulations: TestExecutePlatformSimulationOperation = field(default=None, compare=False, metadata={"pickle_ignore": True},
52
+ repr=False, init=False)
53
+
54
+ _platform_supports: List[PlatformRequirements] = field(default_factory=lambda: copy.deepcopy(supported_types),
55
+ repr=False, init=False)
56
+
57
+ __test__ = False # Hide from test discovery
58
+ execute_directory: str = field(default=DEFAULT_OUTPUT_PATH)
59
+ pool: Executor = field(default=None, compare=False, metadata={"pickle_ignore": True}, repr=False, init=False)
60
+ pool_type: PoolType = field(default=PoolType.thread)
61
+ queue: List = field(default_factory=list, compare=False, metadata={"pickle_ignore": True}, repr=False, init=False)
62
+ workers: int = field(default=os.cpu_count()-1 if os.cpu_count() > 1 else 1)
63
+
64
+ def __post_init__(self):
65
+ self.init_interfaces()
66
+ self.supported_types = {ItemType.EXPERIMENT, ItemType.SIMULATION}
67
+ self.pool = self.pool_type.value(max_workers=self.workers)
68
+ super().__post_init__()
69
+
70
+ def init_interfaces(self):
71
+ self._experiments = TestExecutePlatformExperimentOperation(self)
72
+ self._simulations = TestExecutePlatformSimulationOperation(self)
73
+
74
+ def post_setstate(self):
75
+ self.init_interfaces()
76
+
77
+ def run_simulations(self, experiment: Experiment) -> None:
78
+ from idmtools.core import EntityStatus
79
+ self._simulations.set_simulation_status(experiment.uid, EntityStatus.RUNNING)
80
+
81
+ def cleanup(self):
82
+ self._experiments.experiments = dict()
83
+ self._simulations.simulations = dict()
84
+
85
+ def wait_till_done(self, item: Union[Experiment, IWorkflowItem, Suite], timeout: int = 60 * 60 * 24,
86
+ refresh_interval: int = 5, progress=True):
87
+ for future in as_completed(self.queue):
88
+ result = future.result()
89
+ for sim in self._simulations.simulations[result[0]]:
90
+ if sim.id == result[1]:
91
+ sim.status = result[2]
92
+ break
93
+
94
+ def wait_till_done_progress(self, item: Union[Experiment, IWorkflowItem, Suite], timeout: int = 60 * 60 * 24,
95
+ refresh_interval: int = 5):
96
+ for future in tqdm(as_completed(self.queue), total=len(self.queue)):
97
+ result = future.result()
98
+ if isinstance(item, Experiment):
99
+ for sim in item.simulations:
100
+ if sim.id == result[1]:
101
+ sim.status = result[2]
102
+ self._simulations.save_metadata(sim, update_data=dict(status=result[2]))
103
+ break
104
+ del self.queue
105
+ self.queue = []
106
+
107
+ def __del__(self):
108
+ self.pool.shutdown(False)
109
+
110
+
111
+ class TestExecutePlatformSpecification(PlatformSpecification):
112
+
113
+ @get_description_impl
114
+ def get_description(self) -> str:
115
+ return "Provides access to the Test Platform to IDM Tools"
116
+
117
+ @get_platform_impl
118
+ def get(self, **configuration) -> IPlatform:
119
+ """
120
+ Build our test platform from the passed in configuration object
121
+
122
+ We do our import of platform here to avoid any weir
123
+ Args:
124
+ configuration:
125
+
126
+ Returns:
127
+
128
+ """
129
+ return TestExecutePlatform(**configuration)
130
+
131
+ @example_configuration_impl
132
+ def example_configuration(self):
133
+ return ""
134
+
135
+ @get_platform_type_impl
136
+ def get_type(self) -> Type[TestExecutePlatform]:
137
+ return TestExecutePlatform
@@ -0,0 +1,94 @@
1
+ import copy
2
+ import os
3
+ from dataclasses import dataclass, field
4
+ from logging import getLogger
5
+ from typing import List, Type
6
+
7
+ from idmtools.core import ItemType
8
+ from idmtools.entities.experiment import Experiment
9
+ from idmtools.entities.iplatform import IPlatform
10
+ from idmtools.entities.platform_requirements import PlatformRequirements
11
+ from idmtools.registry.platform_specification import example_configuration_impl, get_platform_impl, \
12
+ get_platform_type_impl, PlatformSpecification
13
+ from idmtools.registry.plugin_specification import get_description_impl
14
+ from idmtools_test.utils.operations.experiment_operations import TestPlatformExperimentOperation
15
+ from idmtools_test.utils.operations.simulation_operations import TestPlatformSimulationOperation
16
+
17
+ logger = getLogger(__name__)
18
+ current_directory = os.path.dirname(os.path.realpath(__file__))
19
+ data_path = os.path.abspath(os.path.join(current_directory, "..", "data"))
20
+
21
+ supported_types = [PlatformRequirements.SHELL, PlatformRequirements.NativeBinary, PlatformRequirements.PYTHON,
22
+ PlatformRequirements.WINDOWS if os.name == "nt" else PlatformRequirements.LINUX]
23
+
24
+
25
+ @dataclass(repr=False)
26
+ class TestPlatform(IPlatform):
27
+ """
28
+ Test platform simulating a working platform to use in the test suites.
29
+ """
30
+
31
+ _experiments: TestPlatformExperimentOperation = field(default=None, compare=False, metadata={"pickle_ignore": True},
32
+ repr=False, init=False)
33
+ _simulations: TestPlatformSimulationOperation = field(default=None, compare=False, metadata={"pickle_ignore": True},
34
+ repr=False, init=False)
35
+
36
+ _platform_supports: List[PlatformRequirements] = field(default_factory=lambda: copy.deepcopy(supported_types),
37
+ repr=False, init=False)
38
+
39
+ __test__ = False # Hide from test discovery
40
+
41
+ def __post_init__(self):
42
+ self.init_interfaces()
43
+ self.supported_types = {ItemType.EXPERIMENT, ItemType.SIMULATION}
44
+ super().__post_init__()
45
+
46
+ def init_interfaces(self):
47
+ self._experiments = TestPlatformExperimentOperation(self)
48
+ self._simulations = TestPlatformSimulationOperation(self)
49
+
50
+ def post_setstate(self):
51
+ self.init_interfaces()
52
+
53
+ def run_simulations(self, experiment: Experiment) -> None:
54
+ from idmtools.core import EntityStatus
55
+ self._simulations.set_simulation_status(experiment.uid, EntityStatus.RUNNING)
56
+
57
+ def cleanup(self):
58
+ self._experiments.experiments = dict()
59
+ self._simulations.simulations = dict()
60
+
61
+
62
+ TEST_PLATFORM_EXAMPLE_CONFIG = """
63
+ [Test]
64
+
65
+ """
66
+
67
+
68
+ class TestPlatformSpecification(PlatformSpecification):
69
+
70
+ @get_description_impl
71
+ def get_description(self) -> str:
72
+ return "Provides access to the Test Platform to IDM Tools"
73
+
74
+ @get_platform_impl
75
+ def get(self, **configuration) -> IPlatform:
76
+ """
77
+ Build our test platform from the passed in configuration object
78
+
79
+ We do our import of platform here to avoid any weir
80
+ Args:
81
+ configuration:
82
+
83
+ Returns:
84
+
85
+ """
86
+ return TestPlatform(**configuration)
87
+
88
+ @example_configuration_impl
89
+ def example_configuration(self):
90
+ return TEST_PLATFORM_EXAMPLE_CONFIG
91
+
92
+ @get_platform_type_impl
93
+ def get_type(self) -> Type[TestPlatform]:
94
+ return TestPlatform
@@ -0,0 +1,69 @@
1
+ import json
2
+ from dataclasses import dataclass, field
3
+ from typing import Type
4
+
5
+ from idmtools.assets import Asset, AssetCollection
6
+ from idmtools.entities import CommandLine
7
+ from idmtools.entities.itask import ITask
8
+ from idmtools.entities.simulation import Simulation
9
+ from idmtools.registry.task_specification import TaskSpecification
10
+
11
+
12
+ @dataclass(repr=False)
13
+ class TestTask(ITask):
14
+ command: CommandLine = field(default=None, metadata={"md": True})
15
+ parameters: dict = field(default_factory=lambda: {}, metadata={"md": True})
16
+ common_asset_paths: list = field(default_factory=lambda: [])
17
+
18
+ __test__ = False # Hide from test discovery
19
+
20
+ def __post_init__(self):
21
+ if self.command is None:
22
+ self.command = CommandLine.from_string('echo this is a test')
23
+
24
+ def set_parameter(self, name: str, value: any) -> dict:
25
+ self.parameters[name] = value
26
+ return {"name": value}
27
+
28
+ def get_parameter(self, name, default=None):
29
+ """
30
+ Get a parameter in the simulation
31
+ Args:
32
+ name: Name of the parameter
33
+ Returns:the Value of the parameter
34
+ """
35
+ return self.parameters.get(name, default)
36
+
37
+ def update_parameters(self, params):
38
+ """
39
+ Bulk update parameters
40
+ Args:
41
+ params: dict with new values
42
+ Returns:None
43
+ """
44
+ self.parameters.update(params)
45
+
46
+ def gather_common_assets(self) -> AssetCollection:
47
+ # modified for test (uid hashing means changing uids) copied version from python_task.py
48
+ assets = [Asset(absolute_path=path) for path in self.common_asset_paths]
49
+ return AssetCollection(assets=assets)
50
+
51
+ def gather_transient_assets(self) -> AssetCollection:
52
+ if not self.transient_assets.has_asset(filename="config.json"):
53
+ self.transient_assets.add_asset(Asset(filename="config.json", content=json.dumps(self.parameters)))
54
+ return self.transient_assets
55
+
56
+ def reload_from_simulation(self, simulation: 'Simulation'):
57
+ pass
58
+
59
+
60
+ class TestTaskSpecification(TaskSpecification):
61
+
62
+ def get(self, configuration: dict) -> TestTask:
63
+ return TestTask(**configuration)
64
+
65
+ def get_description(self) -> str:
66
+ return "Defines a task that is just used for testing purposes"
67
+
68
+ def get_type(self) -> Type[TestTask]:
69
+ return TestTask
@@ -0,0 +1,146 @@
1
+ import sys
2
+ from io import StringIO
3
+ from contextlib import contextmanager
4
+ import os
5
+ import shutil
6
+ import subprocess
7
+ import pandas as pd
8
+ from idmtools.entities.simulation import Simulation
9
+
10
+
11
+ def get_case_name(name: str):
12
+ """
13
+ Add prefix from environment var to names of experiments
14
+ Args:
15
+ name:
16
+
17
+ Returns:
18
+
19
+ """
20
+ if os.environ.get("IDMTOOLS_TEST_PREFIX", None):
21
+ return f'{os.environ["IDMTOOLS_TEST_PREFIX"]}.{name}'
22
+ return name
23
+
24
+
25
+ def del_folder(path: str):
26
+ """
27
+ Delete Folder
28
+
29
+ Args:
30
+ path: Path to delete
31
+
32
+ Returns:
33
+
34
+ """
35
+ if os.path.exists(path):
36
+ shutil.rmtree(path)
37
+
38
+
39
+ def del_file(filename: str, dir: str = None):
40
+ """
41
+ Delete a file
42
+
43
+ Args:
44
+ filename: Filename
45
+ dir: Optional Directory
46
+
47
+ Returns:
48
+
49
+ """
50
+ if dir:
51
+ filepath = os.path.join(dir, filename)
52
+ else:
53
+ filepath = os.path.join(os.path.curdir, filename)
54
+
55
+ if os.path.exists(filepath):
56
+ print(filepath)
57
+ os.remove(filepath)
58
+
59
+
60
+ def load_csv_file(filename: str, dir: str = None) -> pd.DataFrame():
61
+ """
62
+ Load CSV File
63
+
64
+ Args:
65
+ filename: Filename
66
+ dir: Optional Directory
67
+
68
+ Returns:
69
+
70
+ """
71
+ df = None
72
+ if dir:
73
+ filepath = os.path.join(dir, filename)
74
+ else:
75
+ filepath = os.path.join(os.path.curdir, filename)
76
+
77
+ if os.path.exists(filepath):
78
+ df = pd.read_csv(filepath)
79
+ return df
80
+
81
+
82
+ def verify_simulation(simulation: Simulation, expected_parameters, expected_values):
83
+ for value_set in expected_values:
84
+ for i, value in enumerate(list(value_set)):
85
+ if not simulation.task.parameters[expected_parameters[i]] == expected_values:
86
+ break
87
+ return True
88
+ return False
89
+
90
+
91
+ def load_python_files_from_folder(analyzers_folder):
92
+ for file in os.listdir(analyzers_folder):
93
+ if '.py' in file:
94
+ yield file
95
+
96
+
97
+ def execute_example(cmd, cwd=None, shell=True):
98
+ popen_opts = dict(shell=shell)
99
+ if cwd:
100
+ popen_opts['cwd'] = cwd
101
+ popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True,
102
+ **popen_opts)
103
+ for stdout_line in iter(popen.stdout.readline, ""):
104
+ print(stdout_line.strip())
105
+ popen.stdout.close()
106
+ return_code = popen.wait()
107
+ if return_code:
108
+ raise subprocess.CalledProcessError(return_code, cmd)
109
+ return return_code
110
+
111
+
112
+ def test_example_folder(tc, analyzers_folder):
113
+ for file in load_python_files_from_folder(analyzers_folder):
114
+ with tc.subTest(file):
115
+ working_directory = analyzers_folder
116
+ try:
117
+ print(f'Running example: python {file}')
118
+ result = execute_example(f'python {file}', cwd=working_directory, shell=True)
119
+ tc.assertEqual(result, 0)
120
+ except subprocess.CalledProcessError as e:
121
+ tc.assertEqual(result, e.returncode, f'Result for example {file} failed. See {e.output}')
122
+
123
+
124
+ @contextmanager
125
+ def captured_output():
126
+ new_out, new_err = StringIO(), StringIO()
127
+ old_out, old_err = sys.stdout, sys.stderr
128
+ try:
129
+ sys.stdout, sys.stderr = new_out, new_err
130
+ yield sys.stdout, sys.stderr
131
+ finally:
132
+ sys.stdout, sys.stderr = old_out, old_err
133
+
134
+
135
+ def is_global_configuration_enabled() -> bool:
136
+ from idmtools import IdmConfigParser
137
+ return os.path.exists(IdmConfigParser.get_global_configuration_name()) or os.environ.get("IDMTOOLS_CONFIG_FILE", None) is not None
138
+
139
+
140
+ def get_performance_scale() -> int:
141
+ try:
142
+ scale = int(os.getenv("IDMTOOLS_TEST_SCALE", "1"))
143
+ except:
144
+ scale = 1
145
+ return scale
146
+