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.
- idmtools_platform_comps/__init__.py +25 -8
- idmtools_platform_comps/cli/__init__.py +4 -0
- idmtools_platform_comps/cli/cli_functions.py +50 -0
- idmtools_platform_comps/cli/comps.py +492 -0
- idmtools_platform_comps/comps_cli.py +48 -0
- idmtools_platform_comps/comps_operations/__init__.py +6 -0
- idmtools_platform_comps/comps_operations/asset_collection_operations.py +263 -0
- idmtools_platform_comps/comps_operations/experiment_operations.py +569 -0
- idmtools_platform_comps/comps_operations/simulation_operations.py +678 -0
- idmtools_platform_comps/comps_operations/suite_operations.py +228 -0
- idmtools_platform_comps/comps_operations/workflow_item_operations.py +269 -0
- idmtools_platform_comps/comps_platform.py +309 -0
- idmtools_platform_comps/plugin_info.py +168 -0
- idmtools_platform_comps/ssmt_operations/__init__.py +6 -0
- idmtools_platform_comps/ssmt_operations/simulation_operations.py +77 -0
- idmtools_platform_comps/ssmt_operations/workflow_item_operations.py +73 -0
- idmtools_platform_comps/ssmt_platform.py +44 -0
- idmtools_platform_comps/ssmt_work_items/__init__.py +4 -0
- idmtools_platform_comps/ssmt_work_items/comps_work_order_task.py +29 -0
- idmtools_platform_comps/ssmt_work_items/comps_workitems.py +113 -0
- idmtools_platform_comps/ssmt_work_items/icomps_workflowitem.py +71 -0
- idmtools_platform_comps/ssmt_work_items/work_order.py +54 -0
- idmtools_platform_comps/utils/__init__.py +4 -0
- idmtools_platform_comps/utils/assetize_output/__init__.py +4 -0
- idmtools_platform_comps/utils/assetize_output/assetize_output.py +125 -0
- idmtools_platform_comps/utils/assetize_output/assetize_ssmt_script.py +144 -0
- idmtools_platform_comps/utils/base_singularity_work_order.json +6 -0
- idmtools_platform_comps/utils/download/__init__.py +4 -0
- idmtools_platform_comps/utils/download/download.py +178 -0
- idmtools_platform_comps/utils/download/download_ssmt.py +81 -0
- idmtools_platform_comps/utils/download_experiment.py +116 -0
- idmtools_platform_comps/utils/file_filter_workitem.py +519 -0
- idmtools_platform_comps/utils/general.py +358 -0
- idmtools_platform_comps/utils/linux_mounts.py +73 -0
- idmtools_platform_comps/utils/lookups.py +123 -0
- idmtools_platform_comps/utils/package_version.py +489 -0
- idmtools_platform_comps/utils/python_requirements_ac/__init__.py +4 -0
- idmtools_platform_comps/utils/python_requirements_ac/create_asset_collection.py +155 -0
- idmtools_platform_comps/utils/python_requirements_ac/install_requirements.py +109 -0
- idmtools_platform_comps/utils/python_requirements_ac/requirements_to_asset_collection.py +374 -0
- idmtools_platform_comps/utils/python_version.py +40 -0
- idmtools_platform_comps/utils/scheduling.py +154 -0
- idmtools_platform_comps/utils/singularity_build.py +491 -0
- idmtools_platform_comps/utils/spatial_output.py +76 -0
- idmtools_platform_comps/utils/ssmt_utils/__init__.py +6 -0
- idmtools_platform_comps/utils/ssmt_utils/common.py +70 -0
- idmtools_platform_comps/utils/ssmt_utils/file_filter.py +568 -0
- idmtools_platform_comps/utils/sweeping.py +162 -0
- idmtools_platform_comps-0.0.2.dist-info/METADATA +100 -0
- idmtools_platform_comps-0.0.2.dist-info/RECORD +62 -0
- idmtools_platform_comps-0.0.2.dist-info/entry_points.txt +9 -0
- idmtools_platform_comps-0.0.2.dist-info/licenses/LICENSE.TXT +3 -0
- {idmtools_platform_comps-0.0.0.dev0.dist-info → idmtools_platform_comps-0.0.2.dist-info}/top_level.txt +1 -0
- ssmt_image/Dockerfile +52 -0
- ssmt_image/Makefile +21 -0
- ssmt_image/__init__.py +6 -0
- ssmt_image/bootstrap.sh +30 -0
- ssmt_image/build_docker_image.py +161 -0
- ssmt_image/pip.conf +3 -0
- ssmt_image/push_docker_image.py +49 -0
- ssmt_image/requirements.txt +9 -0
- idmtools_platform_comps-0.0.0.dev0.dist-info/METADATA +0 -41
- idmtools_platform_comps-0.0.0.dev0.dist-info/RECORD +0 -5
- {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
|