hpcflow 0.1.15__py3-none-any.whl → 0.2.0a271__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/__init__.py +2 -11
- hpcflow/__pyinstaller/__init__.py +5 -0
- hpcflow/__pyinstaller/hook-hpcflow.py +40 -0
- hpcflow/_version.py +1 -1
- hpcflow/app.py +43 -0
- hpcflow/cli.py +2 -461
- hpcflow/data/demo_data_manifest/__init__.py +3 -0
- hpcflow/data/demo_data_manifest/demo_data_manifest.json +6 -0
- hpcflow/data/jinja_templates/test/test_template.txt +8 -0
- hpcflow/data/programs/hello_world/README.md +1 -0
- hpcflow/data/programs/hello_world/hello_world.c +87 -0
- hpcflow/data/programs/hello_world/linux/hello_world +0 -0
- hpcflow/data/programs/hello_world/macos/hello_world +0 -0
- hpcflow/data/programs/hello_world/win/hello_world.exe +0 -0
- hpcflow/data/scripts/__init__.py +1 -0
- hpcflow/data/scripts/bad_script.py +2 -0
- hpcflow/data/scripts/demo_task_1_generate_t1_infile_1.py +8 -0
- hpcflow/data/scripts/demo_task_1_generate_t1_infile_2.py +8 -0
- hpcflow/data/scripts/demo_task_1_parse_p3.py +7 -0
- hpcflow/data/scripts/do_nothing.py +2 -0
- hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
- hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/generate_t1_file_01.py +7 -0
- hpcflow/data/scripts/import_future_script.py +7 -0
- hpcflow/data/scripts/input_file_generator_basic.py +3 -0
- hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
- hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_all_iters_test.py +15 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_env_spec.py +7 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_labels.py +8 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_sub_param_in_direct_out.py +6 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_group.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +11 -0
- hpcflow/data/scripts/main_script_test_json_and_direct_in_json_out.py +14 -0
- hpcflow/data/scripts/main_script_test_json_in_json_and_direct_out.py +17 -0
- hpcflow/data/scripts/main_script_test_json_in_json_out.py +14 -0
- hpcflow/data/scripts/main_script_test_json_in_json_out_labels.py +16 -0
- hpcflow/data/scripts/main_script_test_json_in_obj.py +12 -0
- hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
- hpcflow/data/scripts/main_script_test_json_out_obj.py +10 -0
- hpcflow/data/scripts/main_script_test_json_sub_param_in_json_out_labels.py +16 -0
- hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
- hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
- hpcflow/data/scripts/output_file_parser_basic.py +3 -0
- hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
- hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/parse_t1_file_01.py +4 -0
- hpcflow/data/scripts/script_exit_test.py +5 -0
- hpcflow/data/template_components/__init__.py +1 -0
- hpcflow/data/template_components/command_files.yaml +26 -0
- hpcflow/data/template_components/environments.yaml +13 -0
- hpcflow/data/template_components/parameters.yaml +14 -0
- hpcflow/data/template_components/task_schemas.yaml +139 -0
- hpcflow/data/workflows/workflow_1.yaml +5 -0
- hpcflow/examples.ipynb +1037 -0
- hpcflow/sdk/__init__.py +149 -0
- hpcflow/sdk/app.py +4266 -0
- hpcflow/sdk/cli.py +1479 -0
- hpcflow/sdk/cli_common.py +385 -0
- hpcflow/sdk/config/__init__.py +5 -0
- hpcflow/sdk/config/callbacks.py +246 -0
- hpcflow/sdk/config/cli.py +388 -0
- hpcflow/sdk/config/config.py +1410 -0
- hpcflow/sdk/config/config_file.py +501 -0
- hpcflow/sdk/config/errors.py +272 -0
- hpcflow/sdk/config/types.py +150 -0
- hpcflow/sdk/core/__init__.py +38 -0
- hpcflow/sdk/core/actions.py +3857 -0
- hpcflow/sdk/core/app_aware.py +25 -0
- hpcflow/sdk/core/cache.py +224 -0
- hpcflow/sdk/core/command_files.py +814 -0
- hpcflow/sdk/core/commands.py +424 -0
- hpcflow/sdk/core/element.py +2071 -0
- hpcflow/sdk/core/enums.py +221 -0
- hpcflow/sdk/core/environment.py +256 -0
- hpcflow/sdk/core/errors.py +1043 -0
- hpcflow/sdk/core/execute.py +207 -0
- hpcflow/sdk/core/json_like.py +809 -0
- hpcflow/sdk/core/loop.py +1320 -0
- hpcflow/sdk/core/loop_cache.py +282 -0
- hpcflow/sdk/core/object_list.py +933 -0
- hpcflow/sdk/core/parameters.py +3371 -0
- hpcflow/sdk/core/rule.py +196 -0
- hpcflow/sdk/core/run_dir_files.py +57 -0
- hpcflow/sdk/core/skip_reason.py +7 -0
- hpcflow/sdk/core/task.py +3792 -0
- hpcflow/sdk/core/task_schema.py +993 -0
- hpcflow/sdk/core/test_utils.py +538 -0
- hpcflow/sdk/core/types.py +447 -0
- hpcflow/sdk/core/utils.py +1207 -0
- hpcflow/sdk/core/validation.py +87 -0
- hpcflow/sdk/core/values.py +477 -0
- hpcflow/sdk/core/workflow.py +4820 -0
- hpcflow/sdk/core/zarr_io.py +206 -0
- hpcflow/sdk/data/__init__.py +13 -0
- hpcflow/sdk/data/config_file_schema.yaml +34 -0
- hpcflow/sdk/data/config_schema.yaml +260 -0
- hpcflow/sdk/data/environments_spec_schema.yaml +21 -0
- hpcflow/sdk/data/files_spec_schema.yaml +5 -0
- hpcflow/sdk/data/parameters_spec_schema.yaml +7 -0
- hpcflow/sdk/data/task_schema_spec_schema.yaml +3 -0
- hpcflow/sdk/data/workflow_spec_schema.yaml +22 -0
- hpcflow/sdk/demo/__init__.py +3 -0
- hpcflow/sdk/demo/cli.py +242 -0
- hpcflow/sdk/helper/__init__.py +3 -0
- hpcflow/sdk/helper/cli.py +137 -0
- hpcflow/sdk/helper/helper.py +300 -0
- hpcflow/sdk/helper/watcher.py +192 -0
- hpcflow/sdk/log.py +288 -0
- hpcflow/sdk/persistence/__init__.py +18 -0
- hpcflow/sdk/persistence/base.py +2817 -0
- hpcflow/sdk/persistence/defaults.py +6 -0
- hpcflow/sdk/persistence/discovery.py +39 -0
- hpcflow/sdk/persistence/json.py +954 -0
- hpcflow/sdk/persistence/pending.py +948 -0
- hpcflow/sdk/persistence/store_resource.py +203 -0
- hpcflow/sdk/persistence/types.py +309 -0
- hpcflow/sdk/persistence/utils.py +73 -0
- hpcflow/sdk/persistence/zarr.py +2388 -0
- hpcflow/sdk/runtime.py +320 -0
- hpcflow/sdk/submission/__init__.py +3 -0
- hpcflow/sdk/submission/enums.py +70 -0
- hpcflow/sdk/submission/jobscript.py +2379 -0
- hpcflow/sdk/submission/schedulers/__init__.py +281 -0
- hpcflow/sdk/submission/schedulers/direct.py +233 -0
- hpcflow/sdk/submission/schedulers/sge.py +376 -0
- hpcflow/sdk/submission/schedulers/slurm.py +598 -0
- hpcflow/sdk/submission/schedulers/utils.py +25 -0
- hpcflow/sdk/submission/shells/__init__.py +52 -0
- hpcflow/sdk/submission/shells/base.py +229 -0
- hpcflow/sdk/submission/shells/bash.py +504 -0
- hpcflow/sdk/submission/shells/os_version.py +115 -0
- hpcflow/sdk/submission/shells/powershell.py +352 -0
- hpcflow/sdk/submission/submission.py +1402 -0
- hpcflow/sdk/submission/types.py +140 -0
- hpcflow/sdk/typing.py +194 -0
- hpcflow/sdk/utils/arrays.py +69 -0
- hpcflow/sdk/utils/deferred_file.py +55 -0
- hpcflow/sdk/utils/hashing.py +16 -0
- hpcflow/sdk/utils/patches.py +31 -0
- hpcflow/sdk/utils/strings.py +69 -0
- hpcflow/tests/api/test_api.py +32 -0
- hpcflow/tests/conftest.py +123 -0
- hpcflow/tests/data/__init__.py +0 -0
- hpcflow/tests/data/benchmark_N_elements.yaml +6 -0
- hpcflow/tests/data/benchmark_script_runner.yaml +26 -0
- hpcflow/tests/data/multi_path_sequences.yaml +29 -0
- hpcflow/tests/data/workflow_1.json +10 -0
- hpcflow/tests/data/workflow_1.yaml +5 -0
- hpcflow/tests/data/workflow_1_slurm.yaml +8 -0
- hpcflow/tests/data/workflow_1_wsl.yaml +8 -0
- hpcflow/tests/data/workflow_test_run_abort.yaml +42 -0
- hpcflow/tests/jinja_templates/test_jinja_templates.py +161 -0
- hpcflow/tests/programs/test_programs.py +180 -0
- hpcflow/tests/schedulers/direct_linux/test_direct_linux_submission.py +12 -0
- hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
- hpcflow/tests/schedulers/slurm/test_slurm_submission.py +14 -0
- hpcflow/tests/scripts/test_input_file_generators.py +282 -0
- hpcflow/tests/scripts/test_main_scripts.py +1361 -0
- hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
- hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
- hpcflow/tests/shells/wsl/test_wsl_submission.py +14 -0
- hpcflow/tests/unit/test_action.py +1066 -0
- hpcflow/tests/unit/test_action_rule.py +24 -0
- hpcflow/tests/unit/test_app.py +132 -0
- hpcflow/tests/unit/test_cache.py +46 -0
- hpcflow/tests/unit/test_cli.py +172 -0
- hpcflow/tests/unit/test_command.py +377 -0
- hpcflow/tests/unit/test_config.py +195 -0
- hpcflow/tests/unit/test_config_file.py +162 -0
- hpcflow/tests/unit/test_element.py +666 -0
- hpcflow/tests/unit/test_element_iteration.py +88 -0
- hpcflow/tests/unit/test_element_set.py +158 -0
- hpcflow/tests/unit/test_group.py +115 -0
- hpcflow/tests/unit/test_input_source.py +1479 -0
- hpcflow/tests/unit/test_input_value.py +398 -0
- hpcflow/tests/unit/test_jobscript_unit.py +757 -0
- hpcflow/tests/unit/test_json_like.py +1247 -0
- hpcflow/tests/unit/test_loop.py +2674 -0
- hpcflow/tests/unit/test_meta_task.py +325 -0
- hpcflow/tests/unit/test_multi_path_sequences.py +259 -0
- hpcflow/tests/unit/test_object_list.py +116 -0
- hpcflow/tests/unit/test_parameter.py +243 -0
- hpcflow/tests/unit/test_persistence.py +664 -0
- hpcflow/tests/unit/test_resources.py +243 -0
- hpcflow/tests/unit/test_run.py +286 -0
- hpcflow/tests/unit/test_run_directories.py +29 -0
- hpcflow/tests/unit/test_runtime.py +9 -0
- hpcflow/tests/unit/test_schema_input.py +372 -0
- hpcflow/tests/unit/test_shell.py +129 -0
- hpcflow/tests/unit/test_slurm.py +39 -0
- hpcflow/tests/unit/test_submission.py +502 -0
- hpcflow/tests/unit/test_task.py +2560 -0
- hpcflow/tests/unit/test_task_schema.py +182 -0
- hpcflow/tests/unit/test_utils.py +616 -0
- hpcflow/tests/unit/test_value_sequence.py +549 -0
- hpcflow/tests/unit/test_values.py +91 -0
- hpcflow/tests/unit/test_workflow.py +827 -0
- hpcflow/tests/unit/test_workflow_template.py +186 -0
- hpcflow/tests/unit/utils/test_arrays.py +40 -0
- hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
- hpcflow/tests/unit/utils/test_hashing.py +65 -0
- hpcflow/tests/unit/utils/test_patches.py +5 -0
- hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
- hpcflow/tests/unit/utils/test_strings.py +97 -0
- hpcflow/tests/workflows/__init__.py +0 -0
- hpcflow/tests/workflows/test_directory_structure.py +31 -0
- hpcflow/tests/workflows/test_jobscript.py +355 -0
- hpcflow/tests/workflows/test_run_status.py +198 -0
- hpcflow/tests/workflows/test_skip_downstream.py +696 -0
- hpcflow/tests/workflows/test_submission.py +140 -0
- hpcflow/tests/workflows/test_workflows.py +564 -0
- hpcflow/tests/workflows/test_zip.py +18 -0
- hpcflow/viz_demo.ipynb +6794 -0
- hpcflow-0.2.0a271.dist-info/LICENSE +375 -0
- hpcflow-0.2.0a271.dist-info/METADATA +65 -0
- hpcflow-0.2.0a271.dist-info/RECORD +237 -0
- {hpcflow-0.1.15.dist-info → hpcflow-0.2.0a271.dist-info}/WHEEL +4 -5
- hpcflow-0.2.0a271.dist-info/entry_points.txt +6 -0
- hpcflow/api.py +0 -490
- hpcflow/archive/archive.py +0 -307
- hpcflow/archive/cloud/cloud.py +0 -45
- hpcflow/archive/cloud/errors.py +0 -9
- hpcflow/archive/cloud/providers/dropbox.py +0 -427
- hpcflow/archive/errors.py +0 -5
- hpcflow/base_db.py +0 -4
- hpcflow/config.py +0 -233
- hpcflow/copytree.py +0 -66
- hpcflow/data/examples/_config.yml +0 -14
- hpcflow/data/examples/damask/demo/1.run.yml +0 -4
- hpcflow/data/examples/damask/demo/2.process.yml +0 -29
- hpcflow/data/examples/damask/demo/geom.geom +0 -2052
- hpcflow/data/examples/damask/demo/load.load +0 -1
- hpcflow/data/examples/damask/demo/material.config +0 -185
- hpcflow/data/examples/damask/inputs/geom.geom +0 -2052
- hpcflow/data/examples/damask/inputs/load.load +0 -1
- hpcflow/data/examples/damask/inputs/material.config +0 -185
- hpcflow/data/examples/damask/profiles/_variable_lookup.yml +0 -21
- hpcflow/data/examples/damask/profiles/damask.yml +0 -4
- hpcflow/data/examples/damask/profiles/damask_process.yml +0 -8
- hpcflow/data/examples/damask/profiles/damask_run.yml +0 -5
- hpcflow/data/examples/damask/profiles/default.yml +0 -6
- hpcflow/data/examples/thinking.yml +0 -177
- hpcflow/errors.py +0 -2
- hpcflow/init_db.py +0 -37
- hpcflow/models.py +0 -2595
- hpcflow/nesting.py +0 -9
- hpcflow/profiles.py +0 -455
- hpcflow/project.py +0 -81
- hpcflow/scheduler.py +0 -322
- hpcflow/utils.py +0 -103
- hpcflow/validation.py +0 -166
- hpcflow/variables.py +0 -543
- hpcflow-0.1.15.dist-info/METADATA +0 -168
- hpcflow-0.1.15.dist-info/RECORD +0 -45
- hpcflow-0.1.15.dist-info/entry_points.txt +0 -8
- hpcflow-0.1.15.dist-info/top_level.txt +0 -1
- /hpcflow/{archive → data/jinja_templates}/__init__.py +0 -0
- /hpcflow/{archive/cloud → data/programs}/__init__.py +0 -0
- /hpcflow/{archive/cloud/providers → data/workflows}/__init__.py +0 -0
hpcflow/api.py
DELETED
|
@@ -1,490 +0,0 @@
|
|
|
1
|
-
"""`hpcflow.api.py`
|
|
2
|
-
|
|
3
|
-
This module contains the application programming interface (API) to `hpcflow`,
|
|
4
|
-
and includes functions that are called by the command line interface (CLI; in
|
|
5
|
-
`hpcflow.cli.py`).
|
|
6
|
-
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
from time import sleep
|
|
11
|
-
from datetime import datetime
|
|
12
|
-
import json
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
from beautifultable import BeautifulTable
|
|
16
|
-
from sqlalchemy.exc import OperationalError
|
|
17
|
-
|
|
18
|
-
from hpcflow.config import Config
|
|
19
|
-
from hpcflow.init_db import init_db
|
|
20
|
-
from hpcflow.models import Workflow, CommandGroupSubmission
|
|
21
|
-
from hpcflow.profiles import parse_job_profiles, prepare_workflow_dict
|
|
22
|
-
from hpcflow.project import Project
|
|
23
|
-
from hpcflow.archive.cloud.cloud import CloudProvider
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def make_workflow(dir_path=None, profile_list=None, json_file=None, json_str=None,
|
|
27
|
-
workflow_dict=None, clean=False, config_dir=None):
|
|
28
|
-
"""Generate a new Workflow and add it to the local database.
|
|
29
|
-
|
|
30
|
-
Parameters
|
|
31
|
-
----------
|
|
32
|
-
dir_path : str or Path, optional
|
|
33
|
-
The directory in which the Workflow will be generated. By default, this
|
|
34
|
-
is the working (i.e. invoking) directory.
|
|
35
|
-
profile_list : list of (str or Path), optional
|
|
36
|
-
List of YAML profile file paths to use to construct the Workflow. By
|
|
37
|
-
default, and if `json_file` and `json_str` and not specified, all
|
|
38
|
-
YAML files in the `dir_path` directory that match the profile
|
|
39
|
-
specification format in the global configuration will be parsed as
|
|
40
|
-
Workflow profiles. If not None, only those profiles listed will be
|
|
41
|
-
parsed as Workflow profiles.
|
|
42
|
-
json_file : str or Path, optional
|
|
43
|
-
Path to a JSON file that represents a Workflow. By default, set to
|
|
44
|
-
`None`.
|
|
45
|
-
json_str : str, optional
|
|
46
|
-
JSON string that represents a Workflow. By default, set to `None`.
|
|
47
|
-
workflow_dict : dict, optional
|
|
48
|
-
Dict representing the workflow to generate.
|
|
49
|
-
clean : bool, optional
|
|
50
|
-
If True, all existing hpcflow data will be removed from `dir_path`.
|
|
51
|
-
Useful for debugging.
|
|
52
|
-
|
|
53
|
-
Returns
|
|
54
|
-
-------
|
|
55
|
-
workflow_id : int
|
|
56
|
-
The insert ID of the Workflow object in the local database.
|
|
57
|
-
|
|
58
|
-
Notes
|
|
59
|
-
-----
|
|
60
|
-
Specify only one of `profile_list`, `json_file` or `json_str`.
|
|
61
|
-
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
opts = [profile_list, json_file, json_str, workflow_dict]
|
|
65
|
-
not_nones = sum([i is not None for i in opts])
|
|
66
|
-
if not_nones > 1:
|
|
67
|
-
msg = ('Specify only one of `profile_list`, `json_file`, `json_str` or '
|
|
68
|
-
'`workflow_dict`.')
|
|
69
|
-
raise ValueError(msg)
|
|
70
|
-
|
|
71
|
-
project = Project(dir_path, config_dir, clean=clean)
|
|
72
|
-
|
|
73
|
-
if json_str:
|
|
74
|
-
workflow_dict = json.loads(json_str)
|
|
75
|
-
|
|
76
|
-
elif json_file:
|
|
77
|
-
json_file = Path(json_file).resolve()
|
|
78
|
-
with Path(json_file).open() as handle:
|
|
79
|
-
workflow_dict = json.load(handle)
|
|
80
|
-
|
|
81
|
-
elif profile_list:
|
|
82
|
-
profile_list = [Path(i).resolve() for i in profile_list]
|
|
83
|
-
# Get workflow from YAML profiles:
|
|
84
|
-
workflow_dict = parse_job_profiles(project.dir_path, profile_list)
|
|
85
|
-
|
|
86
|
-
else:
|
|
87
|
-
workflow_dict = prepare_workflow_dict(workflow_dict)
|
|
88
|
-
|
|
89
|
-
Session = init_db(project, check_exists=False)
|
|
90
|
-
session = Session()
|
|
91
|
-
|
|
92
|
-
workflow = Workflow(directory=project.dir_path, **workflow_dict)
|
|
93
|
-
|
|
94
|
-
session.add(workflow)
|
|
95
|
-
session.commit()
|
|
96
|
-
|
|
97
|
-
workflow_id = workflow.id_
|
|
98
|
-
session.close()
|
|
99
|
-
|
|
100
|
-
return workflow_id
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def submit_workflow(workflow_id, dir_path=None, task_range='all', config_dir=None):
|
|
104
|
-
"""Submit (part of) a previously generated Workflow.
|
|
105
|
-
|
|
106
|
-
Parameters
|
|
107
|
-
----------
|
|
108
|
-
workflow_id : int
|
|
109
|
-
The ID of the Workflow to submit, as in the local database.
|
|
110
|
-
dir_path : str or Path, optional
|
|
111
|
-
The directory in which the Workflow exists. By default, this is the working (i.e.
|
|
112
|
-
invoking) directory.
|
|
113
|
-
task_range : (list of int) or str, optional
|
|
114
|
-
Specify which tasks from the initial command group to submit. If a list, it must
|
|
115
|
-
have either two or three elements; if it has two elements, these signify the first
|
|
116
|
-
and last tasks, inclusively, to submit. By default, the task step size is one, but
|
|
117
|
-
this can be chosen as a third list entry. If a string "all", all tasks are
|
|
118
|
-
submitted.
|
|
119
|
-
"""
|
|
120
|
-
|
|
121
|
-
# TODO: do validation of task_ranges here? so models.workflow.add_submission
|
|
122
|
-
# always receives a definite `task_ranges`? What about if the number is
|
|
123
|
-
# indeterminate at submission time?
|
|
124
|
-
|
|
125
|
-
if task_range == 'all' or task_range is None:
|
|
126
|
-
task_range = [1, -1, 1]
|
|
127
|
-
if len(task_range) == 2:
|
|
128
|
-
task_range.append(1)
|
|
129
|
-
|
|
130
|
-
# print('api.submit_workflow: task_range: {}'.format(task_range), flush=True)
|
|
131
|
-
|
|
132
|
-
project = Project(dir_path, config_dir)
|
|
133
|
-
Session = init_db(project, check_exists=True)
|
|
134
|
-
session = Session()
|
|
135
|
-
|
|
136
|
-
workflow = session.query(Workflow).get(workflow_id)
|
|
137
|
-
submission = workflow.add_submission(project, task_range)
|
|
138
|
-
|
|
139
|
-
session.commit()
|
|
140
|
-
|
|
141
|
-
submission_id = submission.id_
|
|
142
|
-
session.close()
|
|
143
|
-
|
|
144
|
-
return submission_id
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def get_workflow_ids(dir_path=None, config_dir=None):
|
|
148
|
-
"""Get the IDs of existing Workflows.
|
|
149
|
-
|
|
150
|
-
Parameters
|
|
151
|
-
----------
|
|
152
|
-
dir_path : str or Path, optional
|
|
153
|
-
The directory in which the Workflows exist. By default, this is the
|
|
154
|
-
working (i.e. invoking) directory.
|
|
155
|
-
|
|
156
|
-
Returns
|
|
157
|
-
-------
|
|
158
|
-
workflow_ids : list of int
|
|
159
|
-
List of IDs of Workflows.
|
|
160
|
-
|
|
161
|
-
"""
|
|
162
|
-
|
|
163
|
-
project = Project(dir_path, config_dir)
|
|
164
|
-
Session = init_db(project, check_exists=True)
|
|
165
|
-
session = Session()
|
|
166
|
-
|
|
167
|
-
workflow_ids = [i.id_ for i in session.query(Workflow.id_)]
|
|
168
|
-
|
|
169
|
-
session.close()
|
|
170
|
-
|
|
171
|
-
return workflow_ids
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def clean(dir_path=None, config_dir=None):
|
|
175
|
-
"""Clean the directory of all content generated by `hpcflow`."""
|
|
176
|
-
|
|
177
|
-
project = Project(dir_path, config_dir)
|
|
178
|
-
project.clean()
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
def write_runtime_files(cmd_group_sub_id, task_idx, iter_idx, dir_path=None,
|
|
182
|
-
config_dir=None):
|
|
183
|
-
"""Write the commands files for a given command group submission.
|
|
184
|
-
|
|
185
|
-
Parameters
|
|
186
|
-
----------
|
|
187
|
-
cmd_group_sub_id : int
|
|
188
|
-
ID of the command group submission for which a command file is to be
|
|
189
|
-
generated.
|
|
190
|
-
task_idx : int, optional
|
|
191
|
-
Task ID. What is this for???
|
|
192
|
-
dir_path : str or Path, optional
|
|
193
|
-
The directory in which the Workflow will be generated. By default, this
|
|
194
|
-
is the working (i.e. invoking) directory.
|
|
195
|
-
|
|
196
|
-
"""
|
|
197
|
-
|
|
198
|
-
project = Project(dir_path, config_dir)
|
|
199
|
-
Session = init_db(project, check_exists=True)
|
|
200
|
-
session = Session()
|
|
201
|
-
|
|
202
|
-
cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
|
|
203
|
-
cg_sub.write_runtime_files(project, task_idx, iter_idx)
|
|
204
|
-
|
|
205
|
-
session.commit()
|
|
206
|
-
session.close()
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
def set_task_start(cmd_group_sub_id, task_idx, iter_idx, dir_path=None, config_dir=None):
|
|
210
|
-
|
|
211
|
-
project = Project(dir_path, config_dir)
|
|
212
|
-
Session = init_db(project, check_exists=True)
|
|
213
|
-
session = Session()
|
|
214
|
-
|
|
215
|
-
cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
|
|
216
|
-
|
|
217
|
-
sleep_time = 5
|
|
218
|
-
block_msg = (f'{{}} api.set_task_start: Database locked. Sleeping for {sleep_time} '
|
|
219
|
-
f'seconds')
|
|
220
|
-
|
|
221
|
-
blocked = True
|
|
222
|
-
while blocked:
|
|
223
|
-
try:
|
|
224
|
-
session.refresh(cg_sub)
|
|
225
|
-
cg_sub.set_task_start(task_idx, iter_idx)
|
|
226
|
-
session.commit()
|
|
227
|
-
blocked = False
|
|
228
|
-
except OperationalError:
|
|
229
|
-
# Database is likely locked.
|
|
230
|
-
session.rollback()
|
|
231
|
-
print(block_msg.format(datetime.now()), flush=True)
|
|
232
|
-
sleep(sleep_time)
|
|
233
|
-
|
|
234
|
-
session.close()
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
def set_task_end(cmd_group_sub_id, task_idx, iter_idx, dir_path=None, config_dir=None):
|
|
238
|
-
|
|
239
|
-
project = Project(dir_path, config_dir)
|
|
240
|
-
Session = init_db(project, check_exists=True)
|
|
241
|
-
session = Session()
|
|
242
|
-
|
|
243
|
-
cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
|
|
244
|
-
|
|
245
|
-
sleep_time = 5
|
|
246
|
-
block_msg = (f'{{}} api.set_task_end: Database locked. Sleeping for {sleep_time} '
|
|
247
|
-
f'seconds')
|
|
248
|
-
|
|
249
|
-
blocked = True
|
|
250
|
-
while blocked:
|
|
251
|
-
try:
|
|
252
|
-
session.refresh(cg_sub)
|
|
253
|
-
cg_sub.set_task_end(task_idx, iter_idx)
|
|
254
|
-
session.commit()
|
|
255
|
-
blocked = False
|
|
256
|
-
except OperationalError:
|
|
257
|
-
# Database is likely locked.
|
|
258
|
-
session.rollback()
|
|
259
|
-
print(block_msg.format(datetime.now()), flush=True)
|
|
260
|
-
sleep(sleep_time)
|
|
261
|
-
|
|
262
|
-
session.close()
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
def archive(cmd_group_sub_id, task_idx, iter_idx, dir_path=None, config_dir=None):
|
|
266
|
-
"""Initiate an archive of a given task.
|
|
267
|
-
|
|
268
|
-
Parameters
|
|
269
|
-
----------
|
|
270
|
-
cmd_group_sub_id : int
|
|
271
|
-
ID of the command group submission for which an archive is to be
|
|
272
|
-
started.
|
|
273
|
-
task_idx : int
|
|
274
|
-
The task index to be archived (or rather, the task whose working directory
|
|
275
|
-
will be archived).
|
|
276
|
-
dir_path : str or Path, optional
|
|
277
|
-
The directory in which the Workflow will be generated. By default, this
|
|
278
|
-
is the working (i.e. invoking) directory.
|
|
279
|
-
|
|
280
|
-
"""
|
|
281
|
-
|
|
282
|
-
project = Project(dir_path, config_dir)
|
|
283
|
-
Session = init_db(project, check_exists=True)
|
|
284
|
-
session = Session()
|
|
285
|
-
|
|
286
|
-
cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
|
|
287
|
-
cg_sub.do_archive(task_idx, iter_idx)
|
|
288
|
-
|
|
289
|
-
session.commit()
|
|
290
|
-
session.close()
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
def root_archive(workflow_id, dir_path=None, config_dir=None):
|
|
294
|
-
"""Archive the root directory of the Workflow."""
|
|
295
|
-
|
|
296
|
-
project = Project(dir_path, config_dir)
|
|
297
|
-
Session = init_db(project, check_exists=True)
|
|
298
|
-
session = Session()
|
|
299
|
-
|
|
300
|
-
workflow = session.query(Workflow).get(workflow_id)
|
|
301
|
-
workflow.do_root_archive()
|
|
302
|
-
|
|
303
|
-
session.commit()
|
|
304
|
-
session.close()
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def get_scheduler_stats(cmd_group_sub_id, task_idx, iter_idx, dir_path=None,
|
|
308
|
-
config_dir=None):
|
|
309
|
-
"""Scrape completed task information from the scheduler.
|
|
310
|
-
|
|
311
|
-
Parameters
|
|
312
|
-
----------
|
|
313
|
-
cmd_group_sub_id : int
|
|
314
|
-
ID of the command group submission for which an archive is to be
|
|
315
|
-
started.
|
|
316
|
-
task_idx : int
|
|
317
|
-
The task index to be archived (or rather, the task whose working directory
|
|
318
|
-
will be archived).
|
|
319
|
-
dir_path : str or Path, optional
|
|
320
|
-
The directory in which the Workflow will be generated. By default, this
|
|
321
|
-
is the working (i.e. invoking) directory.
|
|
322
|
-
|
|
323
|
-
"""
|
|
324
|
-
|
|
325
|
-
project = Project(dir_path, config_dir)
|
|
326
|
-
Session = init_db(project, check_exists=True)
|
|
327
|
-
session = Session()
|
|
328
|
-
|
|
329
|
-
cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
|
|
330
|
-
cg_sub.get_scheduler_stats(task_idx, iter_idx)
|
|
331
|
-
|
|
332
|
-
session.commit()
|
|
333
|
-
session.close()
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
def get_stats(dir_path=None, workflow_id=None, jsonable=True, datetime_dicts=False,
|
|
337
|
-
config_dir=None):
|
|
338
|
-
"""Get task statistics (as a JSON-like dict) for a project."""
|
|
339
|
-
|
|
340
|
-
project = Project(dir_path, config_dir)
|
|
341
|
-
Session = init_db(project, check_exists=True)
|
|
342
|
-
session = Session()
|
|
343
|
-
|
|
344
|
-
all_workflow_ids = [i.id_ for i in session.query(Workflow.id_)]
|
|
345
|
-
|
|
346
|
-
if not all_workflow_ids:
|
|
347
|
-
msg = 'No workflows exist in directory: "{}"'
|
|
348
|
-
raise ValueError(msg.format(project.dir_path))
|
|
349
|
-
|
|
350
|
-
elif workflow_id:
|
|
351
|
-
|
|
352
|
-
if workflow_id not in all_workflow_ids:
|
|
353
|
-
msg = 'No workflow with ID "{}" was found in directory: "{}"'
|
|
354
|
-
raise ValueError(msg.format(workflow_id, project.dir_path))
|
|
355
|
-
|
|
356
|
-
workflow_ids = [workflow_id]
|
|
357
|
-
|
|
358
|
-
else:
|
|
359
|
-
workflow_ids = all_workflow_ids
|
|
360
|
-
|
|
361
|
-
workflows = [session.query(Workflow).get(i) for i in workflow_ids]
|
|
362
|
-
stats = [i.get_stats(jsonable=jsonable, datetime_dicts=datetime_dicts)
|
|
363
|
-
for i in workflows]
|
|
364
|
-
|
|
365
|
-
session.close()
|
|
366
|
-
|
|
367
|
-
return stats
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
def get_formatted_stats(dir_path=None, workflow_id=None, max_width=100,
|
|
371
|
-
show_task_end=False, config_dir=None):
|
|
372
|
-
"""Get task statistics formatted like a table."""
|
|
373
|
-
|
|
374
|
-
stats = get_stats(dir_path, workflow_id, jsonable=True, config_dir=config_dir)
|
|
375
|
-
|
|
376
|
-
out = ''
|
|
377
|
-
for workflow in stats:
|
|
378
|
-
out += 'Workflow ID: {}\n'.format(workflow['workflow_id'])
|
|
379
|
-
for submission in workflow['submissions']:
|
|
380
|
-
out += 'Submission ID: {}\n'.format(submission['submission_id'])
|
|
381
|
-
for cmd_group_sub in submission['command_group_submissions']:
|
|
382
|
-
out += 'Command group submission ID: {}\n'.format(
|
|
383
|
-
cmd_group_sub['command_group_submission_id'])
|
|
384
|
-
out += 'Commands:\n'
|
|
385
|
-
for cmd in cmd_group_sub['commands']:
|
|
386
|
-
out += '\t{}\n'.format(cmd)
|
|
387
|
-
task_table = BeautifulTable(max_width=max_width)
|
|
388
|
-
task_table.set_style(BeautifulTable.STYLE_BOX)
|
|
389
|
-
task_table.row_separator_char = ''
|
|
390
|
-
headers = [
|
|
391
|
-
'It.',
|
|
392
|
-
'#',
|
|
393
|
-
'SID',
|
|
394
|
-
'Dir.',
|
|
395
|
-
'Start',
|
|
396
|
-
'Duration',
|
|
397
|
-
'Archive',
|
|
398
|
-
'memory',
|
|
399
|
-
'hostname',
|
|
400
|
-
]
|
|
401
|
-
if show_task_end:
|
|
402
|
-
headers = headers[:5] + ['End'] + headers[5:]
|
|
403
|
-
task_table.column_headers = headers
|
|
404
|
-
task_table.column_alignments['Duration'] = BeautifulTable.ALIGN_RIGHT
|
|
405
|
-
|
|
406
|
-
for task in cmd_group_sub['tasks']:
|
|
407
|
-
row = [
|
|
408
|
-
task['iteration'],
|
|
409
|
-
task['order_id'],
|
|
410
|
-
task['scheduler_id'],
|
|
411
|
-
task['working_directory'],
|
|
412
|
-
task['start_time'] or 'pending',
|
|
413
|
-
task['duration'] or '-',
|
|
414
|
-
task['archive_status'] or '-',
|
|
415
|
-
task['memory'] or '-',
|
|
416
|
-
task['hostname'] or '-',
|
|
417
|
-
]
|
|
418
|
-
if show_task_end:
|
|
419
|
-
row = row[:5] + [task['end_time'] or '-'] + row[5:]
|
|
420
|
-
task_table.append_row(row)
|
|
421
|
-
|
|
422
|
-
out += str(task_table) + '\n\n'
|
|
423
|
-
|
|
424
|
-
return out
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
def save_stats(save_path, dir_path=None, workflow_id=None, config_dir=None):
|
|
428
|
-
"""Save task statistics as a JSON file."""
|
|
429
|
-
|
|
430
|
-
stats = get_stats(dir_path, workflow_id, jsonable=True, config_dir=config_dir)
|
|
431
|
-
|
|
432
|
-
save_path = Path(save_path)
|
|
433
|
-
with save_path.open('w') as handle:
|
|
434
|
-
json.dump(stats, handle, indent=4, sort_keys=True)
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
def kill(dir_path=None, workflow_id=None, config_dir=None):
|
|
438
|
-
"""Delete jobscripts associated with a given workflow."""
|
|
439
|
-
|
|
440
|
-
project = Project(dir_path, config_dir)
|
|
441
|
-
Session = init_db(project, check_exists=True)
|
|
442
|
-
session = Session()
|
|
443
|
-
|
|
444
|
-
all_workflow_ids = [i.id_ for i in session.query(Workflow.id_)]
|
|
445
|
-
|
|
446
|
-
if not all_workflow_ids:
|
|
447
|
-
msg = 'No workflows exist in directory: "{}"'
|
|
448
|
-
raise ValueError(msg.format(project.dir_path))
|
|
449
|
-
|
|
450
|
-
elif workflow_id:
|
|
451
|
-
|
|
452
|
-
if workflow_id not in all_workflow_ids:
|
|
453
|
-
msg = 'No workflow with ID "{}" was found in directory: "{}"'
|
|
454
|
-
raise ValueError(msg.format(workflow_id, project.dir_path))
|
|
455
|
-
|
|
456
|
-
workflow_ids = [workflow_id]
|
|
457
|
-
|
|
458
|
-
else:
|
|
459
|
-
workflow_ids = all_workflow_ids
|
|
460
|
-
|
|
461
|
-
for i in workflow_ids:
|
|
462
|
-
workflow = session.query(Workflow).get(i)
|
|
463
|
-
workflow.kill_active()
|
|
464
|
-
|
|
465
|
-
session.commit()
|
|
466
|
-
session.close()
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
def update_config(name, value, config_dir=None):
|
|
470
|
-
Config.update(name, value, config_dir=config_dir)
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
def cloud_connect(provider, config_dir=None):
|
|
474
|
-
Config.set_config(config_dir)
|
|
475
|
-
token_key = {'dropbox': 'dropbox_token'}[provider.lower()]
|
|
476
|
-
provider = {'dropbox': CloudProvider.dropbox}[provider.lower()]
|
|
477
|
-
token = Config.get(token_key)
|
|
478
|
-
good = False
|
|
479
|
-
if token:
|
|
480
|
-
try:
|
|
481
|
-
provider.check_access()
|
|
482
|
-
print('Connected to cloud provider.')
|
|
483
|
-
good = True
|
|
484
|
-
except:
|
|
485
|
-
print('Existing cloud provider key does not work.')
|
|
486
|
-
pass
|
|
487
|
-
if not good:
|
|
488
|
-
print('Getting new cloud token.')
|
|
489
|
-
token = provider.get_token()
|
|
490
|
-
update_config(token_key, token, config_dir=config_dir)
|