hpcflow-new2 0.2.0a179__py3-none-any.whl → 0.2.0a181__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.
- hpcflow/_version.py +1 -1
- hpcflow/data/demo_data_manifest/__init__.py +3 -0
- hpcflow/sdk/__init__.py +4 -1
- hpcflow/sdk/app.py +160 -15
- hpcflow/sdk/cli.py +14 -0
- hpcflow/sdk/cli_common.py +83 -0
- hpcflow/sdk/config/__init__.py +4 -0
- hpcflow/sdk/config/callbacks.py +25 -2
- hpcflow/sdk/config/cli.py +4 -1
- hpcflow/sdk/config/config.py +188 -14
- hpcflow/sdk/config/config_file.py +91 -3
- hpcflow/sdk/config/errors.py +33 -0
- hpcflow/sdk/core/__init__.py +2 -0
- hpcflow/sdk/core/actions.py +492 -35
- hpcflow/sdk/core/cache.py +22 -0
- hpcflow/sdk/core/command_files.py +221 -5
- hpcflow/sdk/core/commands.py +57 -0
- hpcflow/sdk/core/element.py +407 -8
- hpcflow/sdk/core/environment.py +92 -0
- hpcflow/sdk/core/errors.py +245 -61
- hpcflow/sdk/core/json_like.py +72 -14
- hpcflow/sdk/core/loop.py +122 -21
- hpcflow/sdk/core/loop_cache.py +34 -9
- hpcflow/sdk/core/object_list.py +172 -26
- hpcflow/sdk/core/parallel.py +14 -0
- hpcflow/sdk/core/parameters.py +478 -25
- hpcflow/sdk/core/rule.py +31 -1
- hpcflow/sdk/core/run_dir_files.py +12 -2
- hpcflow/sdk/core/task.py +407 -80
- hpcflow/sdk/core/task_schema.py +70 -9
- hpcflow/sdk/core/test_utils.py +35 -0
- hpcflow/sdk/core/utils.py +101 -4
- hpcflow/sdk/core/validation.py +13 -1
- hpcflow/sdk/core/workflow.py +316 -96
- hpcflow/sdk/core/zarr_io.py +23 -0
- hpcflow/sdk/data/__init__.py +13 -0
- hpcflow/sdk/demo/__init__.py +3 -0
- hpcflow/sdk/helper/__init__.py +3 -0
- hpcflow/sdk/helper/cli.py +9 -0
- hpcflow/sdk/helper/helper.py +28 -0
- hpcflow/sdk/helper/watcher.py +33 -0
- hpcflow/sdk/log.py +40 -0
- hpcflow/sdk/persistence/__init__.py +14 -4
- hpcflow/sdk/persistence/base.py +289 -23
- hpcflow/sdk/persistence/json.py +29 -0
- hpcflow/sdk/persistence/pending.py +217 -107
- hpcflow/sdk/persistence/store_resource.py +58 -2
- hpcflow/sdk/persistence/utils.py +8 -0
- hpcflow/sdk/persistence/zarr.py +68 -1
- hpcflow/sdk/runtime.py +52 -10
- hpcflow/sdk/submission/__init__.py +3 -0
- hpcflow/sdk/submission/jobscript.py +198 -9
- hpcflow/sdk/submission/jobscript_info.py +13 -0
- hpcflow/sdk/submission/schedulers/__init__.py +60 -0
- hpcflow/sdk/submission/schedulers/direct.py +53 -0
- hpcflow/sdk/submission/schedulers/sge.py +45 -7
- hpcflow/sdk/submission/schedulers/slurm.py +45 -8
- hpcflow/sdk/submission/schedulers/utils.py +4 -0
- hpcflow/sdk/submission/shells/__init__.py +11 -1
- hpcflow/sdk/submission/shells/base.py +32 -1
- hpcflow/sdk/submission/shells/bash.py +36 -1
- hpcflow/sdk/submission/shells/os_version.py +18 -6
- hpcflow/sdk/submission/shells/powershell.py +22 -0
- hpcflow/sdk/submission/submission.py +88 -3
- hpcflow/sdk/typing.py +10 -1
- {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/METADATA +3 -3
- {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/RECORD +70 -70
- {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/LICENSE +0 -0
- {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/entry_points.txt +0 -0
hpcflow/_version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.2.
|
1
|
+
__version__ = "0.2.0a181"
|
hpcflow/sdk/__init__.py
CHANGED
@@ -4,7 +4,8 @@ import logging
|
|
4
4
|
import os
|
5
5
|
import sys
|
6
6
|
|
7
|
-
|
7
|
+
#: Classes used in the construction of a workflow.
|
8
|
+
#: :meta hide-value:
|
8
9
|
sdk_classes = {
|
9
10
|
"Workflow": "hpcflow.sdk.core.workflow",
|
10
11
|
"Task": "hpcflow.sdk.core.task",
|
@@ -95,6 +96,8 @@ sdk_classes = {
|
|
95
96
|
}
|
96
97
|
|
97
98
|
# these are defined as `BaseApp` methods with an underscore prefix:
|
99
|
+
#: Functions exported by the application.
|
100
|
+
#: :meta hide-value:
|
98
101
|
sdk_funcs = (
|
99
102
|
"make_workflow",
|
100
103
|
"make_demo_workflow",
|
hpcflow/sdk/app.py
CHANGED
@@ -65,7 +65,7 @@ DEMO_WK_FORMATS = {".yaml": "yaml", ".yml": "yaml", ".json": "json", ".jsonc": "
|
|
65
65
|
|
66
66
|
|
67
67
|
def rate_limit_safe_url_to_fs(app, *args, logger=None, **kwargs):
|
68
|
-
"""Call fsspec's
|
68
|
+
R"""Call fsspec's ``url_to_fs`` but retry on ``requests.exceptions.HTTPError``\ s.
|
69
69
|
|
70
70
|
References
|
71
71
|
----------
|
@@ -125,14 +125,24 @@ def get_app_attribute(name):
|
|
125
125
|
|
126
126
|
|
127
127
|
def get_app_module_all():
|
128
|
+
"""
|
129
|
+
The list of all symbols exported by this module.
|
130
|
+
"""
|
128
131
|
return ["app"] + list(sdk_classes.keys()) + list(sdk_funcs)
|
129
132
|
|
130
133
|
|
131
134
|
def get_app_module_dir():
|
135
|
+
"""
|
136
|
+
The sorted list of all symbols exported by this module.
|
137
|
+
"""
|
132
138
|
return lambda: sorted(get_app_module_all())
|
133
139
|
|
134
140
|
|
135
141
|
class Singleton(type):
|
142
|
+
"""
|
143
|
+
Metaclass that enforces that only one instance of a class can be made.
|
144
|
+
"""
|
145
|
+
|
136
146
|
_instances = {}
|
137
147
|
|
138
148
|
def __call__(cls, *args, **kwargs):
|
@@ -158,15 +168,42 @@ class BaseApp(metaclass=Singleton):
|
|
158
168
|
|
159
169
|
Parameters
|
160
170
|
----------
|
171
|
+
name:
|
172
|
+
The name of the application.
|
173
|
+
version:
|
174
|
+
The version of the application.
|
161
175
|
module:
|
162
176
|
The module name in which the app object is defined.
|
177
|
+
description:
|
178
|
+
Description of the application.
|
179
|
+
gh_org:
|
180
|
+
Name of Github organisation responsible for the application.
|
181
|
+
gh_repo:
|
182
|
+
Github repository containing the application source.
|
183
|
+
config_options:
|
184
|
+
Configuration options.
|
185
|
+
scripts_dir:
|
186
|
+
Directory for scripts.
|
187
|
+
workflows_dir:
|
188
|
+
Directory for workflows.
|
189
|
+
demo_data_dir:
|
190
|
+
Directory for demonstration data.
|
191
|
+
data_data_manifest_dir:
|
192
|
+
Directory for demonstration data manifests.
|
193
|
+
template_components:
|
194
|
+
Template components.
|
195
|
+
pytest_args:
|
196
|
+
Arguments for pytest.
|
197
|
+
package_name:
|
198
|
+
Name of package if not the application name.
|
163
199
|
docs_import_conv:
|
164
200
|
The convention for the app alias used in import statements in the documentation.
|
165
201
|
E.g. for the `hpcflow` base app, this is `hf`. This is combined with `module` to
|
166
202
|
form the complete import statement. E.g. for the `hpcflow` base app, the complete
|
167
203
|
import statement is: `import hpcflow.app as hf`, where `hpcflow.app` is the
|
168
204
|
`module` argument and `hf` is the `docs_import_conv` argument.
|
169
|
-
|
205
|
+
docs_url:
|
206
|
+
URL to documentation.
|
170
207
|
"""
|
171
208
|
|
172
209
|
_known_subs_file_name = "known_submissions.txt"
|
@@ -194,22 +231,38 @@ class BaseApp(metaclass=Singleton):
|
|
194
231
|
):
|
195
232
|
SDK_logger.info(f"Generating {self.__class__.__name__} {name!r}.")
|
196
233
|
|
234
|
+
#: The name of the application.
|
197
235
|
self.name = name
|
236
|
+
#: Name of package.
|
198
237
|
self.package_name = package_name or name.lower()
|
238
|
+
#: The version of the application.
|
199
239
|
self.version = version
|
240
|
+
#: The module name in which the app object is defined.
|
200
241
|
self.module = module
|
242
|
+
#: Description of the application.
|
201
243
|
self.description = description
|
244
|
+
#: Name of Github organisation responsible for the application.
|
202
245
|
self.gh_org = gh_org
|
246
|
+
#: Github repository containing the application source.
|
203
247
|
self.gh_repo = gh_repo
|
248
|
+
#: Configuration options.
|
204
249
|
self.config_options = config_options
|
250
|
+
#: Arguments for pytest.
|
205
251
|
self.pytest_args = pytest_args
|
252
|
+
#: Directory for scripts.
|
206
253
|
self.scripts_dir = scripts_dir
|
254
|
+
#: Directory for workflows.
|
207
255
|
self.workflows_dir = workflows_dir
|
256
|
+
#: Directory for demonstration data.
|
208
257
|
self.demo_data_dir = demo_data_dir
|
258
|
+
#: Directory for demonstration data manifests.
|
209
259
|
self.demo_data_manifest_dir = demo_data_manifest_dir
|
260
|
+
#: The convention for the app alias used in import statements in the documentation.
|
210
261
|
self.docs_import_conv = docs_import_conv
|
262
|
+
#: URL to documentation.
|
211
263
|
self.docs_url = docs_url
|
212
264
|
|
265
|
+
#: Command line interface subsystem.
|
213
266
|
self.cli = make_cli(self)
|
214
267
|
|
215
268
|
self._log = AppLog(self)
|
@@ -293,14 +346,23 @@ class BaseApp(metaclass=Singleton):
|
|
293
346
|
|
294
347
|
@property
|
295
348
|
def run_time_info(self) -> RunTimeInfo:
|
349
|
+
"""
|
350
|
+
Information about the runtime.
|
351
|
+
"""
|
296
352
|
return self._run_time_info
|
297
353
|
|
298
354
|
@property
|
299
355
|
def log(self) -> AppLog:
|
356
|
+
"""
|
357
|
+
The application log.
|
358
|
+
"""
|
300
359
|
return self._log
|
301
360
|
|
302
361
|
@property
|
303
362
|
def timeit(self) -> bool:
|
363
|
+
"""
|
364
|
+
Whether the timing analysis system is active.
|
365
|
+
"""
|
304
366
|
return TimeIt.active
|
305
367
|
|
306
368
|
@timeit.setter
|
@@ -309,6 +371,9 @@ class BaseApp(metaclass=Singleton):
|
|
309
371
|
|
310
372
|
@property
|
311
373
|
def template_components(self) -> Dict[str, ObjectList]:
|
374
|
+
"""
|
375
|
+
The template component data.
|
376
|
+
"""
|
312
377
|
if not self.is_template_components_loaded:
|
313
378
|
self._load_template_components()
|
314
379
|
return self._template_components
|
@@ -406,6 +471,10 @@ class BaseApp(metaclass=Singleton):
|
|
406
471
|
def load_builtin_template_component_data(
|
407
472
|
cls, package
|
408
473
|
) -> Dict[str, Union[List, Dict]]:
|
474
|
+
"""
|
475
|
+
Load the template component data built into the package.
|
476
|
+
This is as opposed to the template components defined by users.
|
477
|
+
"""
|
409
478
|
SDK_logger.info(
|
410
479
|
f"Loading built-in template component data for package: {package!r}."
|
411
480
|
)
|
@@ -426,74 +495,119 @@ class BaseApp(metaclass=Singleton):
|
|
426
495
|
|
427
496
|
@property
|
428
497
|
def parameters(self) -> get_app_attribute("ParametersList"):
|
498
|
+
"""
|
499
|
+
The known template parameters.
|
500
|
+
"""
|
429
501
|
self._ensure_template_component("parameters")
|
430
502
|
return self._parameters
|
431
503
|
|
432
504
|
@property
|
433
505
|
def command_files(self) -> get_app_attribute("CommandFilesList"):
|
506
|
+
"""
|
507
|
+
The known template command files.
|
508
|
+
"""
|
434
509
|
self._ensure_template_component("command_files")
|
435
510
|
return self._command_files
|
436
511
|
|
437
512
|
@property
|
438
513
|
def envs(self) -> get_app_attribute("EnvironmentsList"):
|
514
|
+
"""
|
515
|
+
The known template execution environments.
|
516
|
+
"""
|
439
517
|
self._ensure_template_component("environments")
|
440
518
|
return self._environments
|
441
519
|
|
442
520
|
@property
|
443
521
|
def scripts(self):
|
522
|
+
"""
|
523
|
+
The known template scripts.
|
524
|
+
"""
|
444
525
|
self._ensure_template_component("scripts")
|
445
526
|
return self._scripts
|
446
527
|
|
447
528
|
@property
|
448
529
|
def task_schemas(self) -> get_app_attribute("TaskSchemasList"):
|
530
|
+
"""
|
531
|
+
The known template task schemas.
|
532
|
+
"""
|
449
533
|
self._ensure_template_component("task_schemas")
|
450
534
|
return self._task_schemas
|
451
535
|
|
452
536
|
@property
|
453
537
|
def logger(self) -> Logger:
|
538
|
+
"""
|
539
|
+
The main underlying logger.
|
540
|
+
"""
|
454
541
|
return self.log.logger
|
455
542
|
|
456
543
|
@property
|
457
544
|
def API_logger(self) -> Logger:
|
545
|
+
"""
|
546
|
+
The logger for API messages.
|
547
|
+
"""
|
458
548
|
return self.logger.getChild("api")
|
459
549
|
|
460
550
|
@property
|
461
551
|
def CLI_logger(self) -> Logger:
|
552
|
+
"""
|
553
|
+
The logger for CLI messages.
|
554
|
+
"""
|
462
555
|
return self.logger.getChild("cli")
|
463
556
|
|
464
557
|
@property
|
465
558
|
def config_logger(self) -> Logger:
|
559
|
+
"""
|
560
|
+
The logger for configuration messages.
|
561
|
+
"""
|
466
562
|
return self.logger.getChild("config")
|
467
563
|
|
468
564
|
@property
|
469
565
|
def persistence_logger(self) -> Logger:
|
566
|
+
"""
|
567
|
+
The logger for persistence engine messages.
|
568
|
+
"""
|
470
569
|
return self.logger.getChild("persistence")
|
471
570
|
|
472
571
|
@property
|
473
572
|
def submission_logger(self) -> Logger:
|
573
|
+
"""
|
574
|
+
The logger for job submission messages.
|
575
|
+
"""
|
474
576
|
return self.logger.getChild("submission")
|
475
577
|
|
476
578
|
@property
|
477
579
|
def runtime_info_logger(self) -> Logger:
|
580
|
+
"""
|
581
|
+
The logger for runtime messages.
|
582
|
+
"""
|
478
583
|
return self.logger.getChild("runtime")
|
479
584
|
|
480
585
|
@property
|
481
586
|
def is_config_loaded(self) -> bool:
|
587
|
+
"""
|
588
|
+
Whether the configuration is loaded.
|
589
|
+
"""
|
482
590
|
return bool(self._config)
|
483
591
|
|
484
592
|
@property
|
485
593
|
def is_template_components_loaded(self) -> bool:
|
486
|
-
"""
|
594
|
+
"""Whether any template component (e.g. parameters) has been loaded."""
|
487
595
|
return bool(self._template_components)
|
488
596
|
|
489
597
|
@property
|
490
598
|
def config(self) -> Config:
|
599
|
+
"""
|
600
|
+
The configuration.
|
601
|
+
"""
|
491
602
|
if not self.is_config_loaded:
|
492
603
|
self.load_config()
|
493
604
|
return self._config
|
494
605
|
|
495
606
|
@property
|
496
607
|
def scheduler_lookup(self):
|
608
|
+
"""
|
609
|
+
The scheduler mapping.
|
610
|
+
"""
|
497
611
|
return {
|
498
612
|
("direct", "posix"): self.DirectPosix,
|
499
613
|
("direct", "nt"): self.DirectWindows,
|
@@ -550,35 +664,42 @@ class BaseApp(metaclass=Singleton):
|
|
550
664
|
|
551
665
|
@property
|
552
666
|
def user_data_dir(self) -> Path:
|
667
|
+
"""
|
668
|
+
The user's data directory.
|
669
|
+
"""
|
553
670
|
if self._user_data_dir is None:
|
554
671
|
self._user_data_dir = Path(user_data_dir(appname=self.package_name))
|
555
672
|
return self._user_data_dir
|
556
673
|
|
557
674
|
@property
|
558
675
|
def user_cache_dir(self) -> Path:
|
559
|
-
"""
|
676
|
+
"""The user's cache directory."""
|
560
677
|
if self._user_cache_dir is None:
|
561
678
|
self._user_cache_dir = Path(user_cache_path(appname=self.package_name))
|
562
679
|
return self._user_cache_dir
|
563
680
|
|
564
681
|
@property
|
565
682
|
def user_runtime_dir(self) -> Path:
|
566
|
-
"""
|
683
|
+
"""The user's temporary runtime directory."""
|
567
684
|
if self._user_runtime_dir is None:
|
568
685
|
self._user_runtime_dir = self.user_data_dir.joinpath("temp")
|
569
686
|
return self._user_runtime_dir
|
570
687
|
|
571
688
|
@property
|
572
689
|
def demo_data_cache_dir(self) -> Path:
|
573
|
-
"""
|
690
|
+
"""A directory for example data caching."""
|
574
691
|
if self._demo_data_cache_dir is None:
|
575
692
|
self._demo_data_cache_dir = self.user_cache_dir.joinpath("demo_data")
|
576
693
|
return self._demo_data_cache_dir
|
577
694
|
|
578
695
|
@property
|
579
696
|
def user_data_hostname_dir(self) -> Path:
|
580
|
-
"""
|
581
|
-
|
697
|
+
"""
|
698
|
+
The directory for holding user data.
|
699
|
+
|
700
|
+
We segregate by hostname to account for the case where multiple machines might
|
701
|
+
use the same shared file system.
|
702
|
+
"""
|
582
703
|
|
583
704
|
# This might need to cover e.g. multiple login nodes, as described in the
|
584
705
|
# config file:
|
@@ -589,7 +710,7 @@ class BaseApp(metaclass=Singleton):
|
|
589
710
|
|
590
711
|
@property
|
591
712
|
def user_cache_hostname_dir(self) -> Path:
|
592
|
-
"""
|
713
|
+
"""The hostname-scoped app cache directory."""
|
593
714
|
if self._user_cache_hostname_dir is None:
|
594
715
|
machine_name = self.config.get("machine")
|
595
716
|
self._user_cache_hostname_dir = self.user_cache_dir.joinpath(machine_name)
|
@@ -718,11 +839,17 @@ class BaseApp(metaclass=Singleton):
|
|
718
839
|
warn=True,
|
719
840
|
**overrides,
|
720
841
|
) -> None:
|
842
|
+
"""
|
843
|
+
Load the user's configuration.
|
844
|
+
"""
|
721
845
|
if warn and self.is_config_loaded:
|
722
846
|
warnings.warn("Configuration is already loaded; reloading.")
|
723
847
|
self._load_config(config_dir, config_key, **overrides)
|
724
848
|
|
725
849
|
def unload_config(self):
|
850
|
+
"""
|
851
|
+
Discard any loaded configuration.
|
852
|
+
"""
|
726
853
|
self._config_files = {}
|
727
854
|
self._config = None
|
728
855
|
|
@@ -762,6 +889,10 @@ class BaseApp(metaclass=Singleton):
|
|
762
889
|
warn=True,
|
763
890
|
**overrides,
|
764
891
|
) -> None:
|
892
|
+
"""
|
893
|
+
Reload the configuration. Use if a user has updated the configuration file
|
894
|
+
outside the scope of this application.
|
895
|
+
"""
|
765
896
|
if warn and not self.is_config_loaded:
|
766
897
|
warnings.warn("Configuration is not loaded; loading.")
|
767
898
|
self.log.remove_file_handlers()
|
@@ -909,7 +1040,10 @@ class BaseApp(metaclass=Singleton):
|
|
909
1040
|
with self.get_demo_workflow_template_file(name) as path:
|
910
1041
|
return self.WorkflowTemplate.from_file(path)
|
911
1042
|
|
912
|
-
def template_components_from_json_like(self, json_like)
|
1043
|
+
def template_components_from_json_like(self, json_like):
|
1044
|
+
"""
|
1045
|
+
Get template components from a (simply parsed) JSOM document.
|
1046
|
+
"""
|
913
1047
|
cls_lookup = {
|
914
1048
|
"parameters": self.ParametersList,
|
915
1049
|
"command_files": self.CommandFilesList,
|
@@ -944,6 +1078,9 @@ class BaseApp(metaclass=Singleton):
|
|
944
1078
|
return param_map
|
945
1079
|
|
946
1080
|
def get_info(self) -> Dict[str, Any]:
|
1081
|
+
"""
|
1082
|
+
Get miscellaneous runtime system information.
|
1083
|
+
"""
|
947
1084
|
return {
|
948
1085
|
"name": self.name,
|
949
1086
|
"version": self.version,
|
@@ -951,13 +1088,12 @@ class BaseApp(metaclass=Singleton):
|
|
951
1088
|
"is_frozen": self.run_time_info.is_frozen,
|
952
1089
|
}
|
953
1090
|
|
954
|
-
@property
|
955
|
-
def known_subs_file_name(self):
|
956
|
-
return self._known_subs_file_name
|
957
|
-
|
958
1091
|
@property
|
959
1092
|
def known_subs_file_path(self):
|
960
|
-
|
1093
|
+
"""
|
1094
|
+
The path to the file describing known submissions.
|
1095
|
+
"""
|
1096
|
+
return self.user_data_hostname_dir / self._known_subs_file_name
|
961
1097
|
|
962
1098
|
def _format_known_submissions_line(
|
963
1099
|
self,
|
@@ -2242,6 +2378,9 @@ class BaseApp(metaclass=Singleton):
|
|
2242
2378
|
use_current_env=False,
|
2243
2379
|
env_source_file=None,
|
2244
2380
|
):
|
2381
|
+
"""
|
2382
|
+
Configure an execution environment.
|
2383
|
+
"""
|
2245
2384
|
if not setup:
|
2246
2385
|
setup = []
|
2247
2386
|
if not executables:
|
@@ -2505,9 +2644,15 @@ class BaseApp(metaclass=Singleton):
|
|
2505
2644
|
return cache_file_path
|
2506
2645
|
|
2507
2646
|
def cache_demo_data_file(self, file_name) -> Path:
|
2647
|
+
"""
|
2648
|
+
Get the name of a cached demo data file.
|
2649
|
+
"""
|
2508
2650
|
return self.get_demo_data_file_path(file_name)
|
2509
2651
|
|
2510
2652
|
def cache_all_demo_data_files(self) -> List[Path]:
|
2653
|
+
"""
|
2654
|
+
Get the name of all cached demo data file.
|
2655
|
+
"""
|
2511
2656
|
return [self.get_demo_data_file_path(i) for i in self.list_demo_data_files()]
|
2512
2657
|
|
2513
2658
|
def copy_demo_data(
|
hpcflow/sdk/cli.py
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
"""
|
2
|
+
Command line interface implementation.
|
3
|
+
"""
|
4
|
+
|
1
5
|
import json
|
2
6
|
import os
|
3
7
|
from typing import Dict, List
|
@@ -38,26 +42,36 @@ from hpcflow.sdk.cli_common import (
|
|
38
42
|
rechunk_backup_opt,
|
39
43
|
rechunk_chunk_size_opt,
|
40
44
|
rechunk_status_opt,
|
45
|
+
_add_doc_from_help,
|
41
46
|
)
|
42
47
|
from hpcflow.sdk.helper.cli import get_helper_CLI
|
43
48
|
from hpcflow.sdk.log import TimeIt
|
44
49
|
from hpcflow.sdk.submission.shells import ALL_SHELLS
|
45
50
|
|
51
|
+
#: Standard option
|
46
52
|
string_option = click.option(
|
47
53
|
"--string",
|
48
54
|
is_flag=True,
|
49
55
|
default=False,
|
50
56
|
help="Determines if passing a file path or a string.",
|
51
57
|
)
|
58
|
+
#: Standard option
|
52
59
|
workflow_ref_type_opt = click.option(
|
53
60
|
"--ref-type",
|
54
61
|
"-r",
|
55
62
|
type=click.Choice(["assume-id", "id", "path"]),
|
56
63
|
default="assume-id",
|
64
|
+
help="How to interpret a reference, as an ID, a path, or to guess.",
|
57
65
|
)
|
58
66
|
|
59
67
|
|
68
|
+
_add_doc_from_help(string_option, workflow_ref_type_opt)
|
69
|
+
|
70
|
+
|
60
71
|
def parse_jobscript_wait_spec(jobscripts: str) -> Dict[int, List[int]]:
|
72
|
+
"""
|
73
|
+
Parse a jobscript wait specification.
|
74
|
+
"""
|
61
75
|
sub_js_idx_dct = {}
|
62
76
|
for sub_i in jobscripts.split(";"):
|
63
77
|
sub_idx_str, js_idx_lst_str = sub_i.split(":")
|