hpcflow 0.1.9__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 -462
- 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.9.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 -458
- hpcflow/archive/archive.py +0 -308
- hpcflow/archive/cloud/cloud.py +0 -47
- hpcflow/archive/cloud/errors.py +0 -9
- hpcflow/archive/cloud/providers/dropbox.py +0 -432
- hpcflow/archive/errors.py +0 -5
- hpcflow/base_db.py +0 -4
- hpcflow/config.py +0 -232
- 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 -2549
- hpcflow/nesting.py +0 -9
- hpcflow/profiles.py +0 -455
- hpcflow/project.py +0 -81
- hpcflow/scheduler.py +0 -323
- hpcflow/utils.py +0 -103
- hpcflow/validation.py +0 -167
- hpcflow/variables.py +0 -544
- hpcflow-0.1.9.dist-info/METADATA +0 -168
- hpcflow-0.1.9.dist-info/RECORD +0 -45
- hpcflow-0.1.9.dist-info/entry_points.txt +0 -8
- hpcflow-0.1.9.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/sdk/core/rule.py
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Rules apply conditions to workflow elements or loops.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from valida.conditions import ConditionLike # type: ignore
|
|
9
|
+
from valida import Rule as ValidaRule # type: ignore
|
|
10
|
+
|
|
11
|
+
from hpcflow.sdk.core.errors import ContainerKeyError, UnsetParameterDataError
|
|
12
|
+
from hpcflow.sdk.core.json_like import JSONLike
|
|
13
|
+
from hpcflow.sdk.core.utils import get_in_container
|
|
14
|
+
from hpcflow.sdk.log import TimeIt
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from typing import Any
|
|
18
|
+
from typing_extensions import TypeIs
|
|
19
|
+
from .actions import Action, ElementActionRun
|
|
20
|
+
from .element import ElementIteration
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Rule(JSONLike):
|
|
24
|
+
"""
|
|
25
|
+
Class to represent a testable condition on an element iteration or run.
|
|
26
|
+
|
|
27
|
+
Exactly one of ``check_exists``, ``check_missing`` and ``condition`` must be provided.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
check_exists: str
|
|
32
|
+
If set, check this attribute exists.
|
|
33
|
+
check_missing: str
|
|
34
|
+
If set, check this attribute does *not* exist.
|
|
35
|
+
path: str
|
|
36
|
+
Where to look up the attribute to check.
|
|
37
|
+
If not specified, determined by context.
|
|
38
|
+
condition: ConditionLike
|
|
39
|
+
A general condition to check (or kwargs used to generate one).
|
|
40
|
+
cast: str
|
|
41
|
+
If set, a cast to apply prior to running the general check.
|
|
42
|
+
doc: str
|
|
43
|
+
Optional descriptive text.
|
|
44
|
+
default: bool
|
|
45
|
+
Optional default value to return when testing the rule if the path is not valid.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
check_exists: str | None = None,
|
|
51
|
+
check_missing: str | None = None,
|
|
52
|
+
path: str | None = None,
|
|
53
|
+
condition: dict[str, Any] | ConditionLike | None = None,
|
|
54
|
+
cast: str | None = None,
|
|
55
|
+
doc: str | None = None,
|
|
56
|
+
default: bool | None = None,
|
|
57
|
+
):
|
|
58
|
+
if sum(arg is not None for arg in (check_exists, check_missing, condition)) != 1:
|
|
59
|
+
raise ValueError(
|
|
60
|
+
"Specify either one of `check_exists`, `check_missing` or a `condition` "
|
|
61
|
+
"(and optional `path`)"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if not isinstance(condition, dict):
|
|
65
|
+
#: A general condition for this rule to check.
|
|
66
|
+
self.condition = condition
|
|
67
|
+
else:
|
|
68
|
+
self.condition = ConditionLike.from_json_like(condition)
|
|
69
|
+
|
|
70
|
+
#: If set, this rule checks this attribute exists.
|
|
71
|
+
self.check_exists = check_exists
|
|
72
|
+
#: If set, this rule checks this attribute does *not* exist.
|
|
73
|
+
self.check_missing = check_missing
|
|
74
|
+
#: Where to look up the attribute to check (if not determined by context).
|
|
75
|
+
self.path = path
|
|
76
|
+
#: If set, a cast to apply prior to running the general check.
|
|
77
|
+
self.cast = cast
|
|
78
|
+
#: Optional descriptive text.
|
|
79
|
+
self.doc = doc
|
|
80
|
+
#: A default value to return from testing the rule if the path is not valid.
|
|
81
|
+
self.default = default
|
|
82
|
+
|
|
83
|
+
def __repr__(self) -> str:
|
|
84
|
+
out = f"{self.__class__.__name__}("
|
|
85
|
+
if self.check_exists:
|
|
86
|
+
out += f"check_exists={self.check_exists!r}"
|
|
87
|
+
elif self.check_missing:
|
|
88
|
+
out += f"check_missing={self.check_missing!r}"
|
|
89
|
+
else:
|
|
90
|
+
out += f"condition={self.condition!r}"
|
|
91
|
+
if self.path:
|
|
92
|
+
out += f", path={self.path!r}"
|
|
93
|
+
if self.cast:
|
|
94
|
+
out += f", cast={self.cast!r}"
|
|
95
|
+
if self.default is not None:
|
|
96
|
+
out += f", default={self.default!r}"
|
|
97
|
+
|
|
98
|
+
out += ")"
|
|
99
|
+
return out
|
|
100
|
+
|
|
101
|
+
def __eq__(self, other) -> bool:
|
|
102
|
+
if not isinstance(other, self.__class__):
|
|
103
|
+
return False
|
|
104
|
+
return (
|
|
105
|
+
self.check_exists == other.check_exists
|
|
106
|
+
and self.check_missing == other.check_missing
|
|
107
|
+
and self.path == other.path
|
|
108
|
+
and self.condition == other.condition
|
|
109
|
+
and self.cast == other.cast
|
|
110
|
+
and self.doc == other.doc
|
|
111
|
+
and self.default == other.default
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def __is_ElementIteration(cls, value) -> TypeIs[ElementIteration]:
|
|
116
|
+
return isinstance(value, cls._app.ElementIteration)
|
|
117
|
+
|
|
118
|
+
@TimeIt.decorator
|
|
119
|
+
def test(
|
|
120
|
+
self,
|
|
121
|
+
element_like: ElementIteration | ElementActionRun,
|
|
122
|
+
action: Action | None = None,
|
|
123
|
+
) -> bool:
|
|
124
|
+
"""Test if the rule evaluates to true or false for a given run, or element
|
|
125
|
+
iteration and action combination."""
|
|
126
|
+
|
|
127
|
+
task = element_like.task
|
|
128
|
+
schema_data_idx = element_like.data_idx
|
|
129
|
+
|
|
130
|
+
if check := self.check_exists or self.check_missing:
|
|
131
|
+
if len(check.split(".")) > 2:
|
|
132
|
+
# sub-parameter, so need to try to retrieve parameter data
|
|
133
|
+
try:
|
|
134
|
+
task._get_merged_parameter_data(
|
|
135
|
+
schema_data_idx, raise_on_missing=True
|
|
136
|
+
)
|
|
137
|
+
return bool(self.check_exists)
|
|
138
|
+
except ValueError:
|
|
139
|
+
return not self.check_exists
|
|
140
|
+
else:
|
|
141
|
+
if self.check_exists:
|
|
142
|
+
return self.check_exists in schema_data_idx
|
|
143
|
+
elif self.check_missing:
|
|
144
|
+
return self.check_missing not in schema_data_idx
|
|
145
|
+
else:
|
|
146
|
+
if self.path and self.path.startswith("resources."):
|
|
147
|
+
if self.__is_ElementIteration(element_like):
|
|
148
|
+
assert action is not None
|
|
149
|
+
elem_res = element_like.get_resources(
|
|
150
|
+
action=action, set_defaults=True
|
|
151
|
+
)
|
|
152
|
+
else:
|
|
153
|
+
elem_res = element_like.get_resources()
|
|
154
|
+
|
|
155
|
+
res_path = self.path.split(".")[1:]
|
|
156
|
+
try:
|
|
157
|
+
element_dat = get_in_container(
|
|
158
|
+
cont=elem_res, path=res_path, cast_indices=True
|
|
159
|
+
)
|
|
160
|
+
except ContainerKeyError:
|
|
161
|
+
if self.default is not None:
|
|
162
|
+
return bool(self.default)
|
|
163
|
+
else:
|
|
164
|
+
raise
|
|
165
|
+
else:
|
|
166
|
+
try:
|
|
167
|
+
element_dat = element_like.get(
|
|
168
|
+
self.path,
|
|
169
|
+
raise_on_missing=True,
|
|
170
|
+
raise_on_unset=True,
|
|
171
|
+
)
|
|
172
|
+
except (ValueError, IndexError, UnsetParameterDataError):
|
|
173
|
+
if self.default is not None:
|
|
174
|
+
return bool(self.default)
|
|
175
|
+
else:
|
|
176
|
+
raise
|
|
177
|
+
# test the rule:
|
|
178
|
+
return self._valida_check(element_dat)
|
|
179
|
+
|
|
180
|
+
# Something bizarre was specified. Don't match it!
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
def _valida_check(self, value: Any) -> bool:
|
|
184
|
+
"""
|
|
185
|
+
Check this rule against the specific object, under the assumption that we need
|
|
186
|
+
to use valida for the check. Does not do path tracing to select the object to
|
|
187
|
+
pass; that is the caller's responsibility.
|
|
188
|
+
"""
|
|
189
|
+
# note: Valida can't `rule.test` scalars yet, so wrap it in a list and set
|
|
190
|
+
# path to first element (see: https://github.com/hpcflow/valida/issues/9):
|
|
191
|
+
rule = ValidaRule(
|
|
192
|
+
path=[0],
|
|
193
|
+
condition=self.condition,
|
|
194
|
+
cast=self.cast,
|
|
195
|
+
)
|
|
196
|
+
return rule.test([value]).is_valid
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model of files in the run directory.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from typing import Any, TYPE_CHECKING
|
|
7
|
+
from hpcflow.sdk.core.app_aware import AppAware
|
|
8
|
+
from hpcflow.sdk.core.utils import JSONLikeDirSnapShot
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..submission.shells.base import Shell
|
|
12
|
+
from .types import BlockActionKey
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RunDirAppFiles(AppAware):
|
|
16
|
+
"""A class to encapsulate the naming/recognition of app-created files within run
|
|
17
|
+
directories."""
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def get_run_file_prefix(block_act_key: BlockActionKey) -> str:
|
|
21
|
+
"""
|
|
22
|
+
Get the common prefix for files associated with a run.
|
|
23
|
+
"""
|
|
24
|
+
return f"js_{block_act_key[0]}_block_{block_act_key[1]}_act_{block_act_key[2]}"
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def get_commands_file_name(cls, block_act_key: BlockActionKey, shell: Shell) -> str:
|
|
28
|
+
"""
|
|
29
|
+
Get the name of the file containing commands.
|
|
30
|
+
"""
|
|
31
|
+
return cls.get_run_file_prefix(block_act_key) + shell.JS_EXT
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def get_run_param_dump_file_prefix(cls, block_act_key: BlockActionKey) -> str:
|
|
35
|
+
"""Get the prefix to a file in the run directory that the app will dump parameter
|
|
36
|
+
data to."""
|
|
37
|
+
return cls.get_run_file_prefix(block_act_key) + "_inputs"
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def get_run_param_load_file_prefix(cls, block_act_key: BlockActionKey) -> str:
|
|
41
|
+
"""Get the prefix to a file in the run directory that the app will load parameter
|
|
42
|
+
data from."""
|
|
43
|
+
return cls.get_run_file_prefix(block_act_key) + "_outputs"
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def take_snapshot(cls, root_path=None) -> dict[str, Any]:
|
|
47
|
+
"""
|
|
48
|
+
Take a :py:class:`JSONLikeDirSnapShot`.
|
|
49
|
+
|
|
50
|
+
This includes command files that are invoked by jobscripts, the app log file, and
|
|
51
|
+
the app standard out/error file.
|
|
52
|
+
"""
|
|
53
|
+
snapshot = JSONLikeDirSnapShot()
|
|
54
|
+
snapshot.take(root_path or ".")
|
|
55
|
+
ss_js = snapshot.to_json_like(use_strings=True)
|
|
56
|
+
ss_js.pop("root_path") # always the current working directory of the run
|
|
57
|
+
return ss_js
|