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,178 @@
1
+ """idmtools download work item output.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """
5
+ import os
6
+ import sys
7
+ import warnings
8
+ import zipfile
9
+ from dataclasses import dataclass, field
10
+ from enum import Enum
11
+ from logging import getLogger, DEBUG
12
+ from pathlib import PurePath
13
+ from uuid import UUID
14
+ from COMPS.Data import WorkItem
15
+ from tqdm import tqdm
16
+
17
+ from idmtools import IdmConfigParser
18
+ from idmtools.assets.file_list import FileList
19
+ from idmtools.core import EntityStatus
20
+ from idmtools.entities.iplatform import IPlatform
21
+ from idmtools_platform_comps.utils.file_filter_workitem import FileFilterWorkItem
22
+ from idmtools_platform_comps.utils.general import get_file_as_generator
23
+
24
+ logger = getLogger(__name__)
25
+ user_logger = getLogger('user')
26
+
27
+
28
+ class CompressType(Enum):
29
+ """Defines the compression types we support.
30
+
31
+ lzma is the best balance between speed and compression ratio typically
32
+ """
33
+ lzma = 'lzma'
34
+ deflate = 'deflate'
35
+ bz = "bz"
36
+
37
+
38
+ @dataclass(repr=False)
39
+ class DownloadWorkItem(FileFilterWorkItem):
40
+ """
41
+ DownloadWorkItem provides a utility to download items through a workitem with compression.
42
+
43
+ The main advantage of this over Analyzers is the compression. This is most effective when the targets to download have many
44
+ items that are similar to download. For example, an experiment with 1000 simulations with similar output can greatly benefit
45
+ from downloading through this method.
46
+
47
+ Notes:
48
+ - TODO Link examples here.
49
+ """
50
+ output_path: str = field(default_factory=os.getcwd)
51
+ extract_after_download: bool = field(default=True)
52
+ delete_after_download: bool = field(default=True)
53
+ zip_name: str = field(default='output.zip')
54
+ compress_type: CompressType = field(default=None)
55
+
56
+ def __post_init__(self, item_name: str, asset_collection_id: UUID, asset_files: FileList, user_files: FileList,
57
+ command: str):
58
+ """
59
+ Constructor for DownloadWorkItem.
60
+
61
+ Args:
62
+ item_name: item name
63
+ asset_collection_id: AssetCollection id
64
+ asset_files: Asset files
65
+ user_files: user asset files
66
+ command: command
67
+
68
+ Returns:
69
+ None
70
+ """
71
+ self._ssmt_script = str(PurePath(__file__).parent.joinpath("download_ssmt.py"))
72
+ if self.compress_type is None:
73
+ if (self.extract_after_download and self.delete_after_download) or sys.platform != 'win32':
74
+ self.compress_type = CompressType.lzma
75
+ elif sys.platform == 'win32':
76
+ self.compress_type = CompressType.deflate
77
+ else:
78
+ self.compress_type = CompressType.lzma
79
+ super().__post_init__(item_name, asset_collection_id, asset_files, user_files, command)
80
+ warnings.warn(
81
+ message="DownloadWorkItem is deprecated. Until a replacement is added, please use native COMPS scripts. See "
82
+ "'https://github.com/InstituteforDiseaseModeling/pyCOMPS/blob/master/examples/retrieve_simulation_outputs_for_experiment.py'",
83
+ category=FutureWarning)
84
+
85
+ def _extra_command_args(self, command: str) -> str:
86
+ """
87
+ Add specific additional arguments for the download command. In this case, only the zip name and compression type can be changed.
88
+
89
+ Args:
90
+ command: Command to append additional items to
91
+
92
+ Returns:
93
+ Updated command
94
+ """
95
+ if self.zip_name != "output.zip":
96
+ command += f" --zip-name {self.zip_name}"
97
+ if self.compress_type != "lzma":
98
+ command += f" --compress-type {self.compress_type.value}"
99
+ return command
100
+
101
+ def wait(self, wait_on_done_progress: bool = True, timeout: int = None, refresh_interval=None,
102
+ platform: 'IPlatform' = None) -> None:
103
+ """
104
+ Waits on Download WorkItem to finish. This first waits on any dependent items to finish(Experiment/Simulation/WorkItems).
105
+
106
+ Args:
107
+ wait_on_done_progress: When set to true, a progress bar will be shown from the item
108
+ timeout: Timeout for waiting on item. If none, wait will be forever
109
+ refresh_interval: How often to refresh progress
110
+ platform: Platform
111
+
112
+ Returns:
113
+ AssetCollection created if item succeeds
114
+ """
115
+ # wait on related items before we wait on our item
116
+ p = super()._check_for_platform_from_context(platform)
117
+ opts = dict(wait_on_done_progress=wait_on_done_progress, timeout=timeout, refresh_interval=refresh_interval,
118
+ platform=p)
119
+ self._wait_on_children(**opts)
120
+
121
+ super().wait(**opts)
122
+ if self.status == EntityStatus.SUCCEEDED and not self.dry_run:
123
+ # Download our zip
124
+ po: WorkItem = self.get_platform_object(platform=self.platform)
125
+ if self._uid:
126
+ oi = po.retrieve_output_file_info([self.zip_name])
127
+ zip_name = PurePath(self.output_path).joinpath(self.zip_name)
128
+ with tqdm(total=oi[0].length, unit='B', unit_scale=True, unit_divisor=1024,
129
+ desc="Downloading Files") as pbar:
130
+ self.__download_file(oi, pbar, zip_name)
131
+ if self.extract_after_download:
132
+ self.__extract_output(zip_name)
133
+
134
+ if self.delete_after_download:
135
+ if self.extract_after_download:
136
+ if IdmConfigParser.is_output_enabled():
137
+ user_logger.debug(f"Removing {zip_name}")
138
+ os.remove(zip_name)
139
+ if IdmConfigParser.is_output_enabled():
140
+ user_logger.debug(f'Deleting workitem {self.uid}')
141
+ po.delete()
142
+ self.uid = None
143
+
144
+ def __extract_output(self, zip_name):
145
+ """
146
+ Extra output from our zip file.
147
+
148
+ Args:
149
+ zip_name: Zip file to extract
150
+
151
+ Returns:
152
+ None
153
+ """
154
+ if logger.isEnabledFor(DEBUG):
155
+ logger.debug(f"Extracting {zip_name}")
156
+ with zipfile.ZipFile(zip_name, 'r') as zin:
157
+ zin.extractall(self.output_path)
158
+
159
+ def __download_file(self, oi, pbar, zip_name):
160
+ """
161
+ Download our file tracking progress as we go.
162
+
163
+ Args:
164
+ oi: Stream to download
165
+ pbar: Prograss Bar
166
+ zip_name: Zip file to save to
167
+
168
+ Returns:
169
+ None
170
+ """
171
+ if logger.isEnabledFor(DEBUG):
172
+ logger.debug(f"Downloading file to {zip_name}")
173
+ parent_dir = PurePath(zip_name).parent
174
+ os.makedirs(parent_dir, exist_ok=True)
175
+ with open(zip_name, 'wb') as zo:
176
+ for chunk in get_file_as_generator(oi[0]):
177
+ pbar.update(len(chunk))
178
+ zo.write(chunk)
@@ -0,0 +1,81 @@
1
+ """idmtools download workitem ssmt script.
2
+
3
+ This script is meant to be ran remotely on SSMT, not locally.
4
+
5
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
6
+ """
7
+ # flake8: noqa F405 F403
8
+ import sys
9
+ import zipfile
10
+ from logging import getLogger
11
+ import os
12
+ from COMPS.Data import WorkItem
13
+
14
+ # we have to support two ways to load the utils. The first is load from Assets
15
+ # the fallback is the installed package
16
+ # this allows us to move forward with changes to utils without need for new images
17
+ from idmtools_platform_comps.utils.ssmt_utils.file_filter import parse_filter_args_common, filter_files_and_assets
18
+
19
+ try:
20
+ from file_filter import *
21
+ from common import *
22
+ except (FileNotFoundError, ImportError):
23
+ from idmtools_platform_comps.utils.ssmt_utils.file_filter import *
24
+ from idmtools_platform_comps.utils.ssmt_utils.common import *
25
+
26
+ logger = getLogger(__name__)
27
+ user_logger = getLogger('user')
28
+
29
+
30
+ def get_argument_parser():
31
+ p = get_common_parser("Download")
32
+ p.add_argument("--zip-name", default="output.zip")
33
+ return p
34
+
35
+
36
+ def create_archive_from_files(args: Namespace, files, files_from_ac, compress_type: str = "lzma"):
37
+ if compress_type == "lzma":
38
+ compress_type = zipfile.ZIP_LZMA
39
+ elif compress_type == "deflate":
40
+ compress_type = zipfile.ZIP_DEFLATED
41
+ elif compress_type == "bz":
42
+ compress_type = zipfile.ZIP_BZIP2
43
+ with zipfile.ZipFile(args.zip_name, mode="w", compression=compress_type) as zo:
44
+ for f in tqdm(sorted(files, key=lambda x: x[1]), total=len(files), mininterval=5, maxinterval=15):
45
+ logger.info(f"Adding {f[0].encode('ascii', 'ignore').decode('utf-8')} to {f[1].encode('ascii', 'ignore').decode('utf-8')}")
46
+ zo.write(f[0], f[1].encode('ascii', 'ignore').decode('utf-8'))
47
+ for f in tqdm(files_from_ac, total=len(files_from_ac), mininterval=5, maxinterval=15):
48
+ fn = PurePath(f.relative_path).joinpath(f.file_name) if f.relative_path else f.file_name
49
+ if logger.isEnabledFor(DEBUG):
50
+ logger.debug(f"Adding {f[0]} to {fn}")
51
+ zo.write(f.uri, fn)
52
+
53
+
54
+ if __name__ == "__main__": # pragma: no cover
55
+ # build our argument parser and then parse the command line
56
+ parser = get_argument_parser()
57
+ parser.add_argument("--compress-type", choices=["lzma", "deflate", "bz2"], default="lzma")
58
+ args = parser.parse_args()
59
+
60
+ # Set our JOB config global with config provided
61
+ JOB_CONFIG = vars(args)
62
+ # register our error handler
63
+ sys.excepthook = get_error_handler_dump_config_and_error(JOB_CONFIG)
64
+
65
+ # Parse the common arguments common to filter scripts
66
+ entity_filter_func, fn_format_func = parse_filter_args_common(args)
67
+
68
+ # login
69
+ client = login_to_env()
70
+
71
+ # Load our work-item
72
+ wi = WorkItem.get(os.environ['COMPS_WORKITEM_GUID'])
73
+
74
+ # Gather all our files in Experiments, Simulations, and Asset Collections
75
+ files, files_from_ac = filter_files_and_assets(args, entity_filter_func, wi, fn_format_func)
76
+ ensure_no_duplicates(files_from_ac, files)
77
+
78
+ if args.dry_run:
79
+ print_results(files_from_ac, files)
80
+ else:
81
+ create_archive_from_files(args, files, files_from_ac)
@@ -0,0 +1,116 @@
1
+ """idmtools download experiment tools.
2
+
3
+ This allow downloading experiments for local testing.
4
+
5
+ Notes:
6
+ - We need some details around this somewhere. Maybe some documentation?
7
+
8
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
9
+ """
10
+ import os
11
+ import stat
12
+ import sys
13
+ from concurrent.futures._base import as_completed
14
+ from concurrent.futures.thread import ThreadPoolExecutor
15
+ from contextlib import suppress
16
+ from idmtools import IdmConfigParser
17
+ from idmtools.core.context import get_current_platform
18
+ from idmtools.entities.experiment import Experiment
19
+ from idmtools.entities.simulation import Simulation
20
+
21
+
22
+ def get_script_extension():
23
+ """Determine extension to write out file as."""
24
+ if sys.platform in ["linux", "darwin"]:
25
+ return "sh"
26
+ else:
27
+ return "bat"
28
+
29
+
30
+ def download_asset(asset, path):
31
+ """Download a single asset."""
32
+ os.makedirs(path, exist_ok=True)
33
+ asset.download_to_path(path)
34
+
35
+
36
+ def write_script(simulation: Simulation, path):
37
+ """
38
+ Writes a shell script to execute simulation.
39
+
40
+ Args:
41
+ simulation:
42
+ path:
43
+
44
+ Returns:
45
+ None
46
+ """
47
+ command = str(simulation.task.command)
48
+ sp = os.path.join(path, f"idmtools_run.{get_script_extension()}")
49
+ with open(sp, "w") as sfile:
50
+ sfile.write(command)
51
+ if sys.platform in ["linux", "darwin"]:
52
+ st = os.stat(sp)
53
+ os.chmod(sp, st.st_mode | stat.S_IEXEC)
54
+
55
+
56
+ def write_experiment_script(experiment: Experiment, path: str):
57
+ """
58
+ Write an experiment script.
59
+
60
+ Args:
61
+ experiment:
62
+ path:
63
+
64
+ Returns:
65
+ None
66
+ """
67
+ sp = os.path.join(path, f"idmtools_run.{get_script_extension()}")
68
+
69
+ with open(sp, 'w') as sout:
70
+ for sim in experiment.simulations:
71
+ sout.write(f".{os.path.sep}{sim.id}{os.path.sep}idmtools_run.{get_script_extension()}")
72
+ if sys.platform == "linux":
73
+ st = os.stat(sp)
74
+ os.chmod(sp, st.st_mode | stat.S_IEXEC)
75
+
76
+
77
+ def download_experiment(experiment: Experiment, destination: str):
78
+ """
79
+ Downloads experiment to local directory.
80
+
81
+ Useful for troubleshooting experiments
82
+
83
+ Args:
84
+ experiment: Experiment to download
85
+ destination: Destionation Directory
86
+
87
+ Returns:
88
+ None
89
+ """
90
+ asset_dir = os.path.join(destination, "Assets")
91
+ os.makedirs(asset_dir, exist_ok=True)
92
+ pool = ThreadPoolExecutor()
93
+ futures = []
94
+ for asset in experiment.assets:
95
+ futures.append(pool.submit(download_asset, asset, asset_dir))
96
+
97
+ for sim in experiment.simulations:
98
+ sim_path = os.path.join(destination, sim.id)
99
+ with suppress(FileExistsError):
100
+ os.makedirs(sim_path, exist_ok=True)
101
+
102
+ for output in get_current_platform()._simulations.all_files(sim):
103
+ futures.append(pool.submit(download_asset, output, sim_path))
104
+
105
+ write_script(sim, sim_path)
106
+ if sys.platform == "linux" and not os.path.exists(os.path.join(sim_path, "Assets")):
107
+ os.symlink("../Assets", os.path.join(sim_path, "Assets"))
108
+
109
+ write_experiment_script(experiment, destination)
110
+ if IdmConfigParser.is_progress_bar_disabled():
111
+ items = as_completed(futures)
112
+ else:
113
+ from tqdm import tqdm
114
+ items = tqdm(as_completed(futures), total=len(futures), unit="files")
115
+ for _future in items:
116
+ pass