idmtools-platform-comps 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 (64) hide show
  1. idmtools_platform_comps/__init__.py +25 -8
  2. idmtools_platform_comps/cli/__init__.py +4 -0
  3. idmtools_platform_comps/cli/cli_functions.py +50 -0
  4. idmtools_platform_comps/cli/comps.py +492 -0
  5. idmtools_platform_comps/comps_cli.py +48 -0
  6. idmtools_platform_comps/comps_operations/__init__.py +6 -0
  7. idmtools_platform_comps/comps_operations/asset_collection_operations.py +263 -0
  8. idmtools_platform_comps/comps_operations/experiment_operations.py +569 -0
  9. idmtools_platform_comps/comps_operations/simulation_operations.py +678 -0
  10. idmtools_platform_comps/comps_operations/suite_operations.py +228 -0
  11. idmtools_platform_comps/comps_operations/workflow_item_operations.py +269 -0
  12. idmtools_platform_comps/comps_platform.py +309 -0
  13. idmtools_platform_comps/plugin_info.py +168 -0
  14. idmtools_platform_comps/ssmt_operations/__init__.py +6 -0
  15. idmtools_platform_comps/ssmt_operations/simulation_operations.py +77 -0
  16. idmtools_platform_comps/ssmt_operations/workflow_item_operations.py +73 -0
  17. idmtools_platform_comps/ssmt_platform.py +44 -0
  18. idmtools_platform_comps/ssmt_work_items/__init__.py +4 -0
  19. idmtools_platform_comps/ssmt_work_items/comps_work_order_task.py +29 -0
  20. idmtools_platform_comps/ssmt_work_items/comps_workitems.py +113 -0
  21. idmtools_platform_comps/ssmt_work_items/icomps_workflowitem.py +71 -0
  22. idmtools_platform_comps/ssmt_work_items/work_order.py +54 -0
  23. idmtools_platform_comps/utils/__init__.py +4 -0
  24. idmtools_platform_comps/utils/assetize_output/__init__.py +4 -0
  25. idmtools_platform_comps/utils/assetize_output/assetize_output.py +125 -0
  26. idmtools_platform_comps/utils/assetize_output/assetize_ssmt_script.py +144 -0
  27. idmtools_platform_comps/utils/base_singularity_work_order.json +6 -0
  28. idmtools_platform_comps/utils/download/__init__.py +4 -0
  29. idmtools_platform_comps/utils/download/download.py +178 -0
  30. idmtools_platform_comps/utils/download/download_ssmt.py +81 -0
  31. idmtools_platform_comps/utils/download_experiment.py +116 -0
  32. idmtools_platform_comps/utils/file_filter_workitem.py +519 -0
  33. idmtools_platform_comps/utils/general.py +358 -0
  34. idmtools_platform_comps/utils/linux_mounts.py +73 -0
  35. idmtools_platform_comps/utils/lookups.py +123 -0
  36. idmtools_platform_comps/utils/package_version.py +489 -0
  37. idmtools_platform_comps/utils/python_requirements_ac/__init__.py +4 -0
  38. idmtools_platform_comps/utils/python_requirements_ac/create_asset_collection.py +155 -0
  39. idmtools_platform_comps/utils/python_requirements_ac/install_requirements.py +109 -0
  40. idmtools_platform_comps/utils/python_requirements_ac/requirements_to_asset_collection.py +374 -0
  41. idmtools_platform_comps/utils/python_version.py +40 -0
  42. idmtools_platform_comps/utils/scheduling.py +154 -0
  43. idmtools_platform_comps/utils/singularity_build.py +491 -0
  44. idmtools_platform_comps/utils/spatial_output.py +76 -0
  45. idmtools_platform_comps/utils/ssmt_utils/__init__.py +6 -0
  46. idmtools_platform_comps/utils/ssmt_utils/common.py +70 -0
  47. idmtools_platform_comps/utils/ssmt_utils/file_filter.py +568 -0
  48. idmtools_platform_comps/utils/sweeping.py +162 -0
  49. idmtools_platform_comps-0.0.2.dist-info/METADATA +100 -0
  50. idmtools_platform_comps-0.0.2.dist-info/RECORD +62 -0
  51. idmtools_platform_comps-0.0.2.dist-info/entry_points.txt +9 -0
  52. idmtools_platform_comps-0.0.2.dist-info/licenses/LICENSE.TXT +3 -0
  53. {idmtools_platform_comps-0.0.0.dev0.dist-info → idmtools_platform_comps-0.0.2.dist-info}/top_level.txt +1 -0
  54. ssmt_image/Dockerfile +52 -0
  55. ssmt_image/Makefile +21 -0
  56. ssmt_image/__init__.py +6 -0
  57. ssmt_image/bootstrap.sh +30 -0
  58. ssmt_image/build_docker_image.py +161 -0
  59. ssmt_image/pip.conf +3 -0
  60. ssmt_image/push_docker_image.py +49 -0
  61. ssmt_image/requirements.txt +9 -0
  62. idmtools_platform_comps-0.0.0.dev0.dist-info/METADATA +0 -41
  63. idmtools_platform_comps-0.0.0.dev0.dist-info/RECORD +0 -5
  64. {idmtools_platform_comps-0.0.0.dev0.dist-info → idmtools_platform_comps-0.0.2.dist-info}/WHEEL +0 -0
@@ -0,0 +1,263 @@
1
+ """idmtools comps asset collections operations.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """
5
+ import ntpath
6
+ import os
7
+ import uuid
8
+ from dataclasses import field, dataclass
9
+ from functools import partial
10
+ from logging import getLogger, DEBUG
11
+ from typing import Type, Union, List, TYPE_CHECKING, Optional, Dict
12
+ from uuid import UUID
13
+ import humanfriendly
14
+ from COMPS.Data import AssetCollection as COMPSAssetCollection, QueryCriteria, AssetCollectionFile, SimulationFile, OutputFileMetadata, WorkItemFile
15
+ from tqdm import tqdm
16
+ from idmtools import IdmConfigParser
17
+ from idmtools.assets import AssetCollection, Asset
18
+ from idmtools.core import ItemType
19
+ from idmtools.entities.iplatform_ops.iplatform_asset_collection_operations import IPlatformAssetCollectionOperations
20
+ from idmtools_platform_comps.utils.general import get_file_as_generator
21
+
22
+ if TYPE_CHECKING: # pragma: no cover
23
+ from idmtools_platform_comps.comps_platform import COMPSPlatform
24
+
25
+ logger = getLogger(__name__)
26
+ user_logger = getLogger("user")
27
+
28
+
29
+ @dataclass
30
+ class CompsPlatformAssetCollectionOperations(IPlatformAssetCollectionOperations):
31
+ """
32
+ Provides AssetCollection Operations to COMPSPlatform.
33
+ """
34
+ platform: 'COMPSPlatform' # noqa F821
35
+ platform_type: Type = field(default=COMPSAssetCollection)
36
+
37
+ def get(self, asset_collection_id: Optional[UUID], load_children: Optional[List[str]] = None, query_criteria: Optional[QueryCriteria] = None, **kwargs) -> COMPSAssetCollection:
38
+ """
39
+ Get an asset collection by id.
40
+
41
+ Args:
42
+ asset_collection_id: Id of asset collection
43
+ load_children: Optional list of children to load. Defaults to assets and tags
44
+ query_criteria: Optional query_criteria. Ignores children default
45
+ **kwargs:
46
+
47
+ Returns:
48
+ COMPSAssetCollection
49
+ """
50
+ children = load_children if load_children is not None else ["assets", "tags"]
51
+ if asset_collection_id is None and query_criteria is None:
52
+ raise ValueError("You cannot query for all asset collections. Please specify a query criteria or an id")
53
+ query_criteria = query_criteria or QueryCriteria().select_children(children)
54
+ return COMPSAssetCollection.get(id=asset_collection_id, query_criteria=query_criteria)
55
+
56
+ def platform_create(self, asset_collection: AssetCollection, **kwargs) -> COMPSAssetCollection:
57
+ """
58
+ Create AssetCollection.
59
+
60
+ Args:
61
+ asset_collection: AssetCollection to create
62
+ **kwargs:
63
+
64
+ Returns:
65
+ COMPSAssetCollection
66
+ """
67
+ ac = COMPSAssetCollection()
68
+ ac_files = set()
69
+ ac_map = dict()
70
+ for asset in asset_collection:
71
+ # using checksum is not accurate and not all systems will support de-duplication
72
+ if asset.checksum is None:
73
+ md5_checksum_str = asset.calculate_checksum()
74
+ ac_files.add(
75
+ (
76
+ asset.filename,
77
+ asset.relative_path,
78
+ uuid.UUID(md5_checksum_str)
79
+ )
80
+ )
81
+ ac_map[asset] = uuid.UUID(md5_checksum_str)
82
+ else: # We should already have this asset so we should have a md5sum
83
+ ac_files.add(
84
+ (
85
+ asset.filename,
86
+ asset.relative_path,
87
+ asset.checksum if isinstance(asset.checksum, uuid.UUID) else uuid.UUID(asset.checksum)
88
+ )
89
+ )
90
+ ac_map[asset] = asset.checksum if isinstance(asset.checksum, uuid.UUID) else uuid.UUID(asset.checksum)
91
+
92
+ # remove any duplicates
93
+ if logger.isEnabledFor(DEBUG):
94
+ logger.debug(f"Building ac. Filtered out {len(asset_collection) - len(ac_files)} assets that exist on COMPS already")
95
+
96
+ for file in ac_files:
97
+ ac.add_asset(AssetCollectionFile(file_name=file[0], relative_path=file[1], md5_checksum=file[2]))
98
+ del ac_files
99
+ # Add tags
100
+ if asset_collection.tags:
101
+ ac.set_tags(asset_collection.tags)
102
+
103
+ # check for missing files first
104
+ missing_files = ac.save(return_missing_files=True)
105
+ if missing_files:
106
+ if logger.isEnabledFor(DEBUG):
107
+ logger.debug(f"{len(missing_files)} missing files detected")
108
+ ac2 = COMPSAssetCollection()
109
+ if asset_collection.tags:
110
+ ac2.set_tags(ac.tags)
111
+ total_size = 0
112
+ for asset, cksum in ac_map.items():
113
+ if cksum in missing_files:
114
+ if asset.absolute_path:
115
+ total_size += os.path.getsize(asset.absolute_path)
116
+ ac2.add_asset(
117
+ AssetCollectionFile(
118
+ file_name=asset.filename,
119
+ relative_path=asset.relative_path
120
+ ),
121
+ file_path=asset.absolute_path
122
+ )
123
+ else:
124
+ total_size += len(asset.bytes)
125
+ ac2.add_asset(
126
+ AssetCollectionFile(
127
+ file_name=asset.filename,
128
+ relative_path=asset.relative_path
129
+ ),
130
+ data=asset.bytes
131
+ )
132
+ else:
133
+ ac2.add_asset(AssetCollectionFile(
134
+ file_name=asset.filename,
135
+ relative_path=asset.relative_path,
136
+ md5_checksum=cksum
137
+ ))
138
+ if IdmConfigParser.is_output_enabled():
139
+ user_logger.info(f"Uploading {len(missing_files)} files/{humanfriendly.format_size(total_size)}")
140
+ callback = None
141
+ prog = None
142
+ if not IdmConfigParser.is_progress_bar_disabled():
143
+ prog = tqdm(desc="Uploading files", unit='file', total=len(missing_files))
144
+
145
+ def update_progress(total_files_uploaded):
146
+ prog.n = total_files_uploaded
147
+ prog.display()
148
+
149
+ callback = update_progress
150
+ ac2.save(upload_files_callback=callback)
151
+ if callback:
152
+ callback(len(missing_files))
153
+ prog.close()
154
+ ac = ac2
155
+ asset_collection.uid = ac.id
156
+ asset_collection._platform_object = ac
157
+ asset_collection.platform = self.platform
158
+ asset_collection.platform_id = self.platform.uid
159
+ return ac
160
+
161
+ def to_entity(self, asset_collection: Union[COMPSAssetCollection, SimulationFile, List[SimulationFile], OutputFileMetadata, List[WorkItemFile]], **kwargs) \
162
+ -> AssetCollection:
163
+ """
164
+ Convert COMPS Asset Collection or Simulation File to IDM Asset Collection.
165
+
166
+ Args:
167
+ asset_collection: Comps asset/asset collection to convert to idm asset collection
168
+ **kwargs:
169
+
170
+ Returns:
171
+ AssetCollection
172
+
173
+ Raises:
174
+ ValueError - If the file is not a SimulationFile or WorkItemFile
175
+ """
176
+ ac = AssetCollection()
177
+ # set the platform/original object
178
+ ac.platform = self.platform
179
+ # we support comps simulations files and experiments as asset collections
180
+ # only true asset collections have ids
181
+ if isinstance(asset_collection, COMPSAssetCollection):
182
+ ac.uid = asset_collection.id
183
+ ac.tags = asset_collection.tags
184
+ elif isinstance(asset_collection, list) and len(asset_collection):
185
+ if not isinstance(asset_collection[0], (SimulationFile, WorkItemFile)):
186
+ raise ValueError("Unknown asset list")
187
+ else:
188
+ for file in asset_collection:
189
+ ac.add_asset(self.__simulation_file_to_asset(file))
190
+ assets = asset_collection.assets if isinstance(asset_collection, COMPSAssetCollection) else asset_collection
191
+ # if we have just one, make it a list
192
+ if isinstance(asset_collection, SimulationFile):
193
+ ac.add_asset(self.__simulation_file_to_asset(asset_collection))
194
+ if assets:
195
+ # add items to asset collection
196
+ for asset in assets:
197
+ if isinstance(asset, OutputFileMetadata):
198
+ a = Asset(filename=asset.friendly_name, relative_path=asset.path_from_root, persisted=True)
199
+ else:
200
+ a = Asset(filename=asset.file_name, checksum=asset.md5_checksum)
201
+ a._platform_object = asset
202
+ if isinstance(asset_collection, COMPSAssetCollection):
203
+ a.relative_path = asset.relative_path
204
+ a.persisted = True
205
+ a.length = asset.length
206
+ if isinstance(asset, OutputFileMetadata) or asset.uri:
207
+ a.download_generator_hook = partial(get_file_as_generator, asset)
208
+ ac.assets.append(a)
209
+
210
+ return ac
211
+
212
+ def __simulation_file_to_asset(self, asset_collection: Union[SimulationFile, WorkItemFile]):
213
+ """
214
+ Converts a Simulation File to an Asset.
215
+
216
+ Args:
217
+ asset_collection:
218
+
219
+ Returns:
220
+ Asset created from sim file.
221
+ """
222
+ asset = Asset(filename=asset_collection.file_name, checksum=asset_collection.md5_checksum)
223
+ # set original object for quick access again later
224
+ asset._platform_object = asset_collection
225
+ asset.is_simulation_file = True
226
+ asset.persisted = True
227
+ asset.length = asset_collection.length
228
+ if asset.uri:
229
+ asset.download_generator_hook = partial(get_file_as_generator, asset_collection)
230
+ return asset
231
+
232
+ def get_assets(self, asset_collection: AssetCollection, files: List[str], **kwargs) -> Dict[str, bytearray]:
233
+ """
234
+ Fetch the files associated with an AssetCollection.
235
+
236
+ Args:
237
+ asset_collection: AssetCollection to fetch files from
238
+ files: List of files to download. For example ['config.json', 'stdout.txt', 'python/dtk_post_process.py']
239
+ **kwargs: Additional arguments
240
+
241
+ Returns:
242
+ Dictionary of filename -> ByteArray
243
+ """
244
+ # get the asset collection from COMPS
245
+ ac = self.platform.get_item(asset_collection.id, ItemType.ASSETCOLLECTION, raw=True)
246
+
247
+ normalized_files = [ntpath.normpath(file) for file in files]
248
+ ret = {}
249
+ if ac is not None:
250
+ for file in normalized_files:
251
+ match_found = False # Track if the file matches any asset in `ac.assets`
252
+ for asset_file in ac.assets:
253
+ # Get asset file path which combined the relative path and filename if relative path is set
254
+ asset_file_path = os.path.join(asset_file.relative_path,
255
+ asset_file.file_name) if asset_file.relative_path else asset_file.file_name
256
+ normalized_asset_file_path = ntpath.normpath(asset_file_path)
257
+ if normalized_asset_file_path == file:
258
+ ret[asset_file_path] = asset_file.retrieve()
259
+ match_found = True
260
+ break
261
+ if not match_found:
262
+ user_logger.warning(f"\nFile '{file}' not found in asset collection {ac.id}")
263
+ return ret