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
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from typing import Any, cast, TYPE_CHECKING
|
|
6
|
+
import numpy as np
|
|
7
|
+
import zarr # type: ignore
|
|
8
|
+
import pytest
|
|
9
|
+
from hpcflow.sdk.core.test_utils import (
|
|
10
|
+
make_schemas,
|
|
11
|
+
make_test_data_YAML_workflow,
|
|
12
|
+
make_workflow,
|
|
13
|
+
)
|
|
14
|
+
from hpcflow.sdk.persistence.json import (
|
|
15
|
+
JSONPersistentStore,
|
|
16
|
+
JsonStoreElement,
|
|
17
|
+
JsonStoreElementIter,
|
|
18
|
+
JsonStoreEAR,
|
|
19
|
+
)
|
|
20
|
+
from hpcflow.sdk.persistence.zarr import ZarrPersistentStore
|
|
21
|
+
from hpcflow.sdk.core.parameters import NullDefault
|
|
22
|
+
|
|
23
|
+
from hpcflow.app import app as hf
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from hpcflow.sdk.persistence.zarr import ZarrPersistentStore
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.mark.skip("need to refactor `make_test_store_from_spec`")
|
|
30
|
+
def test_store_pending_add_task(tmp_path: Path):
|
|
31
|
+
"""Check expected pending state after adding a task."""
|
|
32
|
+
|
|
33
|
+
# make store: 0 tasks:
|
|
34
|
+
store = JSONPersistentStore.make_test_store_from_spec(hf, [], dir=tmp_path)
|
|
35
|
+
task_ID = store.add_task()
|
|
36
|
+
assert store._pending.add_tasks == {task_ID: []}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@pytest.mark.skip("need to refactor `make_test_store_from_spec`")
|
|
40
|
+
def test_store_pending_add_element(tmp_path: Path):
|
|
41
|
+
"""Check expected pending state after adding an element."""
|
|
42
|
+
|
|
43
|
+
# make store: 1 task with 0 elements:
|
|
44
|
+
store = JSONPersistentStore.make_test_store_from_spec(app=hf, spec=[{}], dir=tmp_path)
|
|
45
|
+
elem_ID = store.add_element(task_ID=0)
|
|
46
|
+
assert store._pending.add_elements == {
|
|
47
|
+
elem_ID: JsonStoreElement(
|
|
48
|
+
id_=elem_ID,
|
|
49
|
+
is_pending=True,
|
|
50
|
+
es_idx=0,
|
|
51
|
+
task_ID=0,
|
|
52
|
+
iteration_IDs=[],
|
|
53
|
+
index=0,
|
|
54
|
+
seq_idx={},
|
|
55
|
+
src_idx={},
|
|
56
|
+
)
|
|
57
|
+
} and store._pending.add_task_element_IDs == {0: [0]}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.mark.skip("need to refactor `make_test_store_from_spec`")
|
|
61
|
+
@pytest.mark.parametrize("elem_ID", [0, 1])
|
|
62
|
+
def test_store_pending_add_element_iter(tmp_path: Path, elem_ID: int):
|
|
63
|
+
"""Check expected pending state after adding an element iteration."""
|
|
64
|
+
|
|
65
|
+
# make store: 1 task with 2 elements and 0 iterations:
|
|
66
|
+
store = JSONPersistentStore.make_test_store_from_spec(
|
|
67
|
+
hf,
|
|
68
|
+
[{"elements": [{}, {}]}],
|
|
69
|
+
dir=tmp_path,
|
|
70
|
+
)
|
|
71
|
+
iter_ID = store.add_element_iteration(
|
|
72
|
+
element_ID=elem_ID,
|
|
73
|
+
data_idx={},
|
|
74
|
+
schema_parameters=[],
|
|
75
|
+
)
|
|
76
|
+
assert store._pending.add_elem_iters == {
|
|
77
|
+
iter_ID: JsonStoreElementIter(
|
|
78
|
+
id_=iter_ID,
|
|
79
|
+
is_pending=True,
|
|
80
|
+
element_ID=elem_ID,
|
|
81
|
+
EAR_IDs={},
|
|
82
|
+
data_idx={},
|
|
83
|
+
schema_parameters=[],
|
|
84
|
+
EARs_initialised=False,
|
|
85
|
+
)
|
|
86
|
+
} and store._pending.add_elem_iter_IDs == {elem_ID: [iter_ID]}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@pytest.mark.skip("need to refactor `make_test_store_from_spec`")
|
|
90
|
+
def test_store_pending_add_EAR(tmp_path: Path):
|
|
91
|
+
"""Check expected pending state after adding an EAR."""
|
|
92
|
+
|
|
93
|
+
# make store: 1 task with 1 element and 1 iteration:
|
|
94
|
+
store = JSONPersistentStore.make_test_store_from_spec(
|
|
95
|
+
hf,
|
|
96
|
+
[{"elements": [{"iterations": [{}]}]}],
|
|
97
|
+
dir=tmp_path,
|
|
98
|
+
)
|
|
99
|
+
EAR_ID = store.add_EAR(
|
|
100
|
+
elem_iter_ID=0,
|
|
101
|
+
action_idx=0,
|
|
102
|
+
commands_idx=[],
|
|
103
|
+
data_idx={},
|
|
104
|
+
metadata={},
|
|
105
|
+
)
|
|
106
|
+
assert store._pending.add_EARs == {
|
|
107
|
+
EAR_ID: JsonStoreEAR(
|
|
108
|
+
id_=EAR_ID,
|
|
109
|
+
is_pending=True,
|
|
110
|
+
elem_iter_ID=0,
|
|
111
|
+
action_idx=0,
|
|
112
|
+
commands_idx=[],
|
|
113
|
+
data_idx={},
|
|
114
|
+
metadata={},
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@pytest.mark.skip("need to refactor `make_test_store_from_spec`")
|
|
120
|
+
def test_get_task_elements_task_is_pending(tmp_path: Path):
|
|
121
|
+
"""Check we get an empty list when getting all task elements of a pending task to
|
|
122
|
+
which no elements have been added."""
|
|
123
|
+
# make store: 0 tasks:
|
|
124
|
+
store = JSONPersistentStore.make_test_store_from_spec(hf, [], dir=tmp_path)
|
|
125
|
+
task_ID = store.add_task()
|
|
126
|
+
assert store.get_task_elements(task_ID, slice(0, None)) == []
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@pytest.mark.skip("need to refactor `make_test_store_from_spec`")
|
|
130
|
+
def test_get_task_elements_single_element_is_pending(tmp_path: Path):
|
|
131
|
+
"""Check expected return when getting all task elements of a persistent task that has
|
|
132
|
+
a single pending element."""
|
|
133
|
+
# make store: 1 task
|
|
134
|
+
store = JSONPersistentStore.make_test_store_from_spec(hf, [{}], dir=tmp_path)
|
|
135
|
+
store.add_element(task_ID=0)
|
|
136
|
+
assert store.get_task_elements(0, slice(0, None)) == [
|
|
137
|
+
{
|
|
138
|
+
"id": 0,
|
|
139
|
+
"is_pending": True,
|
|
140
|
+
"element_idx": 0,
|
|
141
|
+
"iteration_IDs": [],
|
|
142
|
+
"task_ID": 0,
|
|
143
|
+
"iterations": [],
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@pytest.mark.skip("need to refactor `make_test_store_from_spec`")
|
|
149
|
+
def test_get_task_elements_multi_element_one_pending(tmp_path: Path):
|
|
150
|
+
"""Check expected return when getting all task elements of a persistent task that has
|
|
151
|
+
a persistent element and a pending element."""
|
|
152
|
+
# make store: 1 task with 1 element:
|
|
153
|
+
store = JSONPersistentStore.make_test_store_from_spec(
|
|
154
|
+
hf, [{"elements": [{}]}], dir=tmp_path
|
|
155
|
+
)
|
|
156
|
+
store.add_element(task_ID=0)
|
|
157
|
+
assert store.get_task_elements(0, slice(0, None)) == [
|
|
158
|
+
{
|
|
159
|
+
"id": 0,
|
|
160
|
+
"is_pending": False,
|
|
161
|
+
"element_idx": 0,
|
|
162
|
+
"iteration_IDs": [],
|
|
163
|
+
"task_ID": 0,
|
|
164
|
+
"iterations": [],
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"id": 1,
|
|
168
|
+
"is_pending": True,
|
|
169
|
+
"element_idx": 1,
|
|
170
|
+
"iteration_IDs": [],
|
|
171
|
+
"task_ID": 0,
|
|
172
|
+
"iterations": [],
|
|
173
|
+
},
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@pytest.mark.skip("need to refactor `make_test_store_from_spec`")
|
|
178
|
+
def test_get_task_elements_single_element_iter_pending(tmp_path: Path):
|
|
179
|
+
"""Check expected return when getting all task elements of a persistent task that has
|
|
180
|
+
a persistent element with a pending iteration."""
|
|
181
|
+
# make store: 1 task with 1 element:
|
|
182
|
+
store = JSONPersistentStore.make_test_store_from_spec(
|
|
183
|
+
hf, [{"elements": [{}]}], dir=tmp_path
|
|
184
|
+
)
|
|
185
|
+
store.add_element_iteration(element_ID=0, data_idx={}, schema_parameters=[])
|
|
186
|
+
assert store.get_task_elements(0, slice(0, None)) == [
|
|
187
|
+
{
|
|
188
|
+
"id": 0,
|
|
189
|
+
"is_pending": False,
|
|
190
|
+
"element_idx": 0,
|
|
191
|
+
"iteration_IDs": [0],
|
|
192
|
+
"task_ID": 0,
|
|
193
|
+
"iterations": [
|
|
194
|
+
{
|
|
195
|
+
"id": 0,
|
|
196
|
+
"is_pending": True,
|
|
197
|
+
"element_ID": 0,
|
|
198
|
+
"EAR_IDs": {},
|
|
199
|
+
"data_idx": {},
|
|
200
|
+
"schema_parameters": [],
|
|
201
|
+
"EARs": {},
|
|
202
|
+
}
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@pytest.mark.skip("need to refactor `make_test_store_from_spec`")
|
|
209
|
+
def test_get_task_elements_single_element_iter_EAR_pending(tmp_path: Path):
|
|
210
|
+
"""Check expected return when getting all task elements of a persistent task that has
|
|
211
|
+
a persistent element with a persistent iteration and a pending EAR"""
|
|
212
|
+
# make store: 1 task with 1 element with 1 iteration:
|
|
213
|
+
store = JSONPersistentStore.make_test_store_from_spec(
|
|
214
|
+
hf, [{"elements": [{"iterations": [{}]}]}], dir=tmp_path
|
|
215
|
+
)
|
|
216
|
+
store.add_EAR(elem_iter_ID=0, action_idx=0, commands_idx=[], data_idx={}, metadata={})
|
|
217
|
+
assert store.get_task_elements(0, slice(0, None)) == [
|
|
218
|
+
{
|
|
219
|
+
"id": 0,
|
|
220
|
+
"is_pending": False,
|
|
221
|
+
"element_idx": 0,
|
|
222
|
+
"iteration_IDs": [0],
|
|
223
|
+
"task_ID": 0,
|
|
224
|
+
"iterations": [
|
|
225
|
+
{
|
|
226
|
+
"id": 0,
|
|
227
|
+
"is_pending": False,
|
|
228
|
+
"element_ID": 0,
|
|
229
|
+
"EAR_IDs": {0: [0]},
|
|
230
|
+
"data_idx": {},
|
|
231
|
+
"schema_parameters": [],
|
|
232
|
+
"EARs": {
|
|
233
|
+
0: [
|
|
234
|
+
{
|
|
235
|
+
"id_": 0,
|
|
236
|
+
"is_pending": True,
|
|
237
|
+
"elem_iter_ID": 0,
|
|
238
|
+
"action_idx": 0,
|
|
239
|
+
"commands_idx": [],
|
|
240
|
+
"data_idx": {},
|
|
241
|
+
"metadata": {},
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
]
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def test_make_zarr_store_zstd_compressor(null_config, tmp_path: Path):
|
|
252
|
+
wk = make_test_data_YAML_workflow(
|
|
253
|
+
workflow_name="workflow_1.yaml",
|
|
254
|
+
path=tmp_path,
|
|
255
|
+
store="zarr",
|
|
256
|
+
store_kwargs={"compressor": "zstd"},
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def test_make_zarr_store_no_compressor(null_config, tmp_path: Path):
|
|
261
|
+
wk = make_test_data_YAML_workflow(
|
|
262
|
+
workflow_name="workflow_1.yaml",
|
|
263
|
+
path=tmp_path,
|
|
264
|
+
store="zarr",
|
|
265
|
+
store_kwargs={"compressor": None},
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@pytest.mark.integration
|
|
270
|
+
@pytest.mark.skipif(
|
|
271
|
+
sys.version_info < (3, 9), reason="Python 3.8 support is being removed anyway."
|
|
272
|
+
)
|
|
273
|
+
def test_zarr_rechunk_data_equivalent(null_config, tmp_path: Path):
|
|
274
|
+
t1 = hf.Task(
|
|
275
|
+
schema=hf.task_schemas.test_t1_conditional_OS,
|
|
276
|
+
inputs={"p1": 101},
|
|
277
|
+
repeats=3,
|
|
278
|
+
)
|
|
279
|
+
wk = hf.Workflow.from_template_data(
|
|
280
|
+
tasks=[t1],
|
|
281
|
+
template_name="test_run_rechunk",
|
|
282
|
+
workflow_name="test_run_rechunk",
|
|
283
|
+
path=tmp_path,
|
|
284
|
+
)
|
|
285
|
+
wk.submit(wait=True, status=False, add_to_known=False)
|
|
286
|
+
wk.rechunk_runs(backup=True, status=False, chunk_size=None) # None -> one chunk
|
|
287
|
+
|
|
288
|
+
arr = cast("ZarrPersistentStore", wk._store)._get_EARs_arr()
|
|
289
|
+
assert arr.chunks == arr.shape
|
|
290
|
+
|
|
291
|
+
bak_path = (Path(arr.store.path) / arr.path).with_suffix(".bak")
|
|
292
|
+
arr_bak = zarr.open(bak_path)
|
|
293
|
+
|
|
294
|
+
assert arr_bak.chunks == (1, 1) # runs array is 2D
|
|
295
|
+
|
|
296
|
+
# check backup and new runs data are equal:
|
|
297
|
+
assert np.all(arr[:] == arr_bak[:])
|
|
298
|
+
|
|
299
|
+
# check attributes are equal:
|
|
300
|
+
assert arr.attrs.asdict() == arr_bak.attrs.asdict()
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
@pytest.mark.integration
|
|
304
|
+
@pytest.mark.skipif(
|
|
305
|
+
sys.version_info < (3, 9), reason="Python 3.8 support is being removed anyway."
|
|
306
|
+
)
|
|
307
|
+
def test_zarr_rechunk_data_equivalent_custom_chunk_size(null_config, tmp_path: Path):
|
|
308
|
+
t1 = hf.Task(
|
|
309
|
+
schema=hf.task_schemas.test_t1_conditional_OS,
|
|
310
|
+
inputs={"p1": 101},
|
|
311
|
+
repeats=3,
|
|
312
|
+
)
|
|
313
|
+
wk = hf.Workflow.from_template_data(
|
|
314
|
+
tasks=[t1],
|
|
315
|
+
template_name="test_run_rechunk",
|
|
316
|
+
workflow_name="test_run_rechunk",
|
|
317
|
+
path=tmp_path,
|
|
318
|
+
)
|
|
319
|
+
wk.submit(wait=True, status=False, add_to_known=False)
|
|
320
|
+
wk.rechunk_runs(backup=True, status=False, chunk_size=2)
|
|
321
|
+
|
|
322
|
+
arr = cast("ZarrPersistentStore", wk._store)._get_EARs_arr()
|
|
323
|
+
assert arr.chunks == (2, 2) # runs array is 2D
|
|
324
|
+
|
|
325
|
+
bak_path = (Path(arr.store.path) / arr.path).with_suffix(".bak")
|
|
326
|
+
arr_bak = zarr.open(bak_path)
|
|
327
|
+
|
|
328
|
+
assert arr_bak.chunks == (1, 1) # runs array is 2D
|
|
329
|
+
|
|
330
|
+
# check backup and new runs data are equal:
|
|
331
|
+
assert np.all(arr[:] == arr_bak[:])
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@pytest.mark.integration
|
|
335
|
+
def test_zarr_rechunk_data_no_backup_load_runs(null_config, tmp_path: Path):
|
|
336
|
+
t1 = hf.Task(
|
|
337
|
+
schema=hf.task_schemas.test_t1_conditional_OS,
|
|
338
|
+
inputs={"p1": 101},
|
|
339
|
+
repeats=3,
|
|
340
|
+
)
|
|
341
|
+
wk = hf.Workflow.from_template_data(
|
|
342
|
+
tasks=[t1],
|
|
343
|
+
template_name="test_run_rechunk",
|
|
344
|
+
workflow_name="test_run_rechunk",
|
|
345
|
+
path=tmp_path,
|
|
346
|
+
)
|
|
347
|
+
wk.submit(wait=True, status=False, add_to_known=False)
|
|
348
|
+
wk.rechunk_runs(backup=False, status=False)
|
|
349
|
+
|
|
350
|
+
arr = cast("ZarrPersistentStore", wk._store)._get_EARs_arr()
|
|
351
|
+
|
|
352
|
+
bak_path = (Path(arr.store.path) / arr.path).with_suffix(".bak")
|
|
353
|
+
assert not bak_path.is_file()
|
|
354
|
+
|
|
355
|
+
# check we can load runs:
|
|
356
|
+
runs = wk._store._get_persistent_EARs(id_lst=list(range(wk.num_EARs)))
|
|
357
|
+
run_ID = []
|
|
358
|
+
for i in runs.values():
|
|
359
|
+
run_ID.append(i.id_)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
@pytest.mark.integration
|
|
363
|
+
def test_zarr_rechunk_data_no_backup_load_parameter_base(null_config, tmp_path: Path):
|
|
364
|
+
t1 = hf.Task(
|
|
365
|
+
schema=hf.task_schemas.test_t1_conditional_OS,
|
|
366
|
+
inputs={"p1": 101},
|
|
367
|
+
repeats=3,
|
|
368
|
+
)
|
|
369
|
+
wk = hf.Workflow.from_template_data(
|
|
370
|
+
tasks=[t1],
|
|
371
|
+
template_name="test_run_rechunk",
|
|
372
|
+
workflow_name="test_run_rechunk",
|
|
373
|
+
path=tmp_path,
|
|
374
|
+
)
|
|
375
|
+
wk.submit(wait=True, status=False, add_to_known=False)
|
|
376
|
+
|
|
377
|
+
params_old = wk.get_all_parameter_data()
|
|
378
|
+
wk.rechunk_parameter_base(backup=False, status=False)
|
|
379
|
+
|
|
380
|
+
wk = wk.reload()
|
|
381
|
+
params_new = wk.get_all_parameter_data()
|
|
382
|
+
assert params_new == params_old
|
|
383
|
+
|
|
384
|
+
arr = cast("ZarrPersistentStore", wk._store)._get_parameter_base_array()
|
|
385
|
+
|
|
386
|
+
bak_path = (Path(arr.store.path) / arr.path).with_suffix(".bak")
|
|
387
|
+
assert not bak_path.is_file()
|
|
388
|
+
|
|
389
|
+
# check we can load parameters:
|
|
390
|
+
param_IDs = []
|
|
391
|
+
for i in wk.get_all_parameters():
|
|
392
|
+
param_IDs.append(i.id_)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def test_get_parameter_sources_duplicate_ids(null_config, tmp_path):
|
|
396
|
+
wk = make_workflow(
|
|
397
|
+
schemas_spec=[[{"p1": None}, ("p1",), "t1"]],
|
|
398
|
+
local_inputs={0: ("p1",)},
|
|
399
|
+
path=tmp_path,
|
|
400
|
+
)
|
|
401
|
+
id_lst = [0, 1, 1, 2, 0]
|
|
402
|
+
src = wk._store.get_parameter_sources(id_lst)
|
|
403
|
+
assert len(src) == len(id_lst)
|
|
404
|
+
assert src[0] == src[4]
|
|
405
|
+
assert src[1] == src[2]
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _transform_jobscript_dependencies_to_encodable(
|
|
409
|
+
deps: dict[tuple[int, int], dict[tuple[int, int], dict[str, Any]]],
|
|
410
|
+
) -> dict[str, list[dict[str, Any]]]:
|
|
411
|
+
"""Transform a dict of jobscript dependencies written in a more testing-friendly/
|
|
412
|
+
convenient format into the format expected by the method
|
|
413
|
+
`ZarrPersistentStore._encode_jobscript_block_dependencies`.
|
|
414
|
+
|
|
415
|
+
"""
|
|
416
|
+
max_js_idx = max(i[0] for i in deps)
|
|
417
|
+
sub_js: dict[str, list[dict[str, Any]]] = {
|
|
418
|
+
"jobscripts": [
|
|
419
|
+
{"blocks": [], "index": js_idx} for js_idx in range(max_js_idx + 1)
|
|
420
|
+
]
|
|
421
|
+
}
|
|
422
|
+
for (js_idx, blk_idx), deps_i in deps.items():
|
|
423
|
+
sub_js["jobscripts"][js_idx]["blocks"].append(
|
|
424
|
+
{
|
|
425
|
+
"dependencies": [[[k[0], k[1]], v] for k, v in deps_i.items()],
|
|
426
|
+
"index": blk_idx,
|
|
427
|
+
}
|
|
428
|
+
)
|
|
429
|
+
return sub_js
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def test_zarr_encode_jobscript_block_dependencies_element_mapping_array_non_array_equivalence():
|
|
433
|
+
deps_1 = {
|
|
434
|
+
(0, 0): {},
|
|
435
|
+
(1, 0): {(0, 0): {"js_element_mapping": {0: [0]}, "is_array": True}},
|
|
436
|
+
}
|
|
437
|
+
deps_2 = {
|
|
438
|
+
(0, 0): {},
|
|
439
|
+
(1, 0): {(0, 0): {"js_element_mapping": {0: np.array([0])}, "is_array": True}},
|
|
440
|
+
}
|
|
441
|
+
deps_1 = _transform_jobscript_dependencies_to_encodable(deps_1)
|
|
442
|
+
deps_2 = _transform_jobscript_dependencies_to_encodable(deps_2)
|
|
443
|
+
arr_1 = ZarrPersistentStore._encode_jobscript_block_dependencies(deps_1)
|
|
444
|
+
arr_2 = ZarrPersistentStore._encode_jobscript_block_dependencies(deps_2)
|
|
445
|
+
assert np.array_equal(arr_1, arr_2)
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def test_zarr_encode_decode_jobscript_block_dependencies():
|
|
449
|
+
|
|
450
|
+
deps = {
|
|
451
|
+
(0, 0): {},
|
|
452
|
+
(1, 0): {
|
|
453
|
+
(0, 0): {
|
|
454
|
+
"js_element_mapping": {0: [0], 1: [1]},
|
|
455
|
+
"is_array": True,
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
(2, 0): {
|
|
459
|
+
(1, 0): {
|
|
460
|
+
"js_element_mapping": {0: [0, 1], 1: [0, 1]},
|
|
461
|
+
"is_array": False,
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
(2, 1): {
|
|
465
|
+
(0, 0): {"js_element_mapping": {0: [0, 1]}, "is_array": False},
|
|
466
|
+
(2, 0): {"js_element_mapping": {0: [0, 1]}, "is_array": False},
|
|
467
|
+
},
|
|
468
|
+
}
|
|
469
|
+
deps_t = _transform_jobscript_dependencies_to_encodable(deps)
|
|
470
|
+
arr = ZarrPersistentStore._encode_jobscript_block_dependencies(deps_t)
|
|
471
|
+
assert np.array_equal(
|
|
472
|
+
arr,
|
|
473
|
+
np.array(
|
|
474
|
+
[
|
|
475
|
+
2,
|
|
476
|
+
0,
|
|
477
|
+
0,
|
|
478
|
+
12,
|
|
479
|
+
1,
|
|
480
|
+
0,
|
|
481
|
+
9,
|
|
482
|
+
0,
|
|
483
|
+
0,
|
|
484
|
+
1,
|
|
485
|
+
2,
|
|
486
|
+
0,
|
|
487
|
+
0,
|
|
488
|
+
2,
|
|
489
|
+
1,
|
|
490
|
+
1,
|
|
491
|
+
14,
|
|
492
|
+
2,
|
|
493
|
+
0,
|
|
494
|
+
11,
|
|
495
|
+
1,
|
|
496
|
+
0,
|
|
497
|
+
0,
|
|
498
|
+
3,
|
|
499
|
+
0,
|
|
500
|
+
0,
|
|
501
|
+
1,
|
|
502
|
+
3,
|
|
503
|
+
1,
|
|
504
|
+
0,
|
|
505
|
+
1,
|
|
506
|
+
18,
|
|
507
|
+
2,
|
|
508
|
+
1,
|
|
509
|
+
7,
|
|
510
|
+
0,
|
|
511
|
+
0,
|
|
512
|
+
0,
|
|
513
|
+
3,
|
|
514
|
+
0,
|
|
515
|
+
0,
|
|
516
|
+
1,
|
|
517
|
+
7,
|
|
518
|
+
2,
|
|
519
|
+
0,
|
|
520
|
+
0,
|
|
521
|
+
3,
|
|
522
|
+
0,
|
|
523
|
+
0,
|
|
524
|
+
1,
|
|
525
|
+
]
|
|
526
|
+
),
|
|
527
|
+
)
|
|
528
|
+
deps_rt = ZarrPersistentStore._decode_jobscript_block_dependencies(arr)
|
|
529
|
+
assert deps_rt == deps
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def test_zarr_encode_decode_jobscript_block_dependencies_large_many_to_one():
|
|
533
|
+
deps = {
|
|
534
|
+
(0, 0): {},
|
|
535
|
+
(1, 0): {
|
|
536
|
+
(0, 0): {"js_element_mapping": {0: list(range(1_000_000))}, "is_array": False}
|
|
537
|
+
},
|
|
538
|
+
}
|
|
539
|
+
deps_t = _transform_jobscript_dependencies_to_encodable(deps)
|
|
540
|
+
arr = ZarrPersistentStore._encode_jobscript_block_dependencies(deps_t)
|
|
541
|
+
deps_rt = ZarrPersistentStore._decode_jobscript_block_dependencies(arr)
|
|
542
|
+
assert deps_rt == deps
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
def test_zarr_encode_decode_jobscript_block_dependencies_large_one_to_one():
|
|
546
|
+
deps = {
|
|
547
|
+
(0, 0): {},
|
|
548
|
+
(1, 0): {
|
|
549
|
+
(0, 0): {
|
|
550
|
+
"js_element_mapping": {i: [i] for i in range(1_000_000)},
|
|
551
|
+
"is_array": False,
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
}
|
|
555
|
+
deps_t = _transform_jobscript_dependencies_to_encodable(deps)
|
|
556
|
+
arr = ZarrPersistentStore._encode_jobscript_block_dependencies(deps_t)
|
|
557
|
+
deps_rt = ZarrPersistentStore._decode_jobscript_block_dependencies(arr)
|
|
558
|
+
assert deps_rt == deps
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
@pytest.mark.parametrize(
|
|
562
|
+
"array",
|
|
563
|
+
(
|
|
564
|
+
np.array([]),
|
|
565
|
+
np.empty(0),
|
|
566
|
+
np.empty((0, 1, 2)),
|
|
567
|
+
np.array([1, 2, 3]),
|
|
568
|
+
np.array([[1, 2, 3], [4, 5, 6]]),
|
|
569
|
+
),
|
|
570
|
+
)
|
|
571
|
+
def test_zarr_save_persistent_array_shape(null_config, tmp_path, array):
|
|
572
|
+
s1 = make_schemas(({"p1": None}, ()))
|
|
573
|
+
t1 = hf.Task(schema=s1, inputs={"p1": array})
|
|
574
|
+
wk = hf.Workflow.from_template_data(
|
|
575
|
+
template_name="test_save_empty_array",
|
|
576
|
+
tasks=[t1],
|
|
577
|
+
path=tmp_path,
|
|
578
|
+
)
|
|
579
|
+
assert array.shape == wk.tasks[0].elements[0].get("inputs.p1")[:].shape
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
def test_zarr_single_chunk_threshold(null_config, tmp_path):
|
|
583
|
+
# test very large arrays (> ~1 GB) are saved using multiple chunks
|
|
584
|
+
array = np.zeros(
|
|
585
|
+
268_435_456
|
|
586
|
+
) # ~ 2.147483647 GB; greater than blosc's max buffer size
|
|
587
|
+
s1 = make_schemas(({"p1": None}, ()))
|
|
588
|
+
t1 = hf.Task(schema=s1, inputs={"p1": array})
|
|
589
|
+
wk = hf.Workflow.from_template_data(
|
|
590
|
+
template_name="test_large_array",
|
|
591
|
+
tasks=[t1],
|
|
592
|
+
path=tmp_path,
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
@pytest.mark.parametrize("store", ["json", "zarr"])
|
|
597
|
+
def test_store_parameter_encode_decode_types(null_config, tmp_path, store):
|
|
598
|
+
|
|
599
|
+
(s1,) = make_schemas(
|
|
600
|
+
(
|
|
601
|
+
{
|
|
602
|
+
"p1": NullDefault.NULL,
|
|
603
|
+
"p2": NullDefault.NULL,
|
|
604
|
+
"p3": NullDefault.NULL,
|
|
605
|
+
"p4": NullDefault.NULL,
|
|
606
|
+
"p5": NullDefault.NULL,
|
|
607
|
+
"p6": NullDefault.NULL,
|
|
608
|
+
"p7": NullDefault.NULL,
|
|
609
|
+
"p8": NullDefault.NULL,
|
|
610
|
+
"p9": NullDefault.NULL,
|
|
611
|
+
},
|
|
612
|
+
tuple(),
|
|
613
|
+
),
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
p1 = [1, 2, 3]
|
|
617
|
+
p2 = (1, 2, 3)
|
|
618
|
+
p3 = {1, 2, 3}
|
|
619
|
+
p4 = None
|
|
620
|
+
p5 = np.arange(10)
|
|
621
|
+
p6 = np.ma.array(np.arange(10), mask=np.random.randint(0, 2, 10))
|
|
622
|
+
p7 = [[1, 2], (3, 4), {5, 6}]
|
|
623
|
+
p8 = np.ma.array(np.arange(10), mask=np.ones(10)) # fully masked
|
|
624
|
+
p9 = {
|
|
625
|
+
"a2": np.ma.array(np.arange(10), mask=np.ones(10), fill_value=999)
|
|
626
|
+
} # custom fill value
|
|
627
|
+
|
|
628
|
+
t1 = hf.Task(
|
|
629
|
+
schema=s1,
|
|
630
|
+
inputs={
|
|
631
|
+
"p1": p1,
|
|
632
|
+
"p2": p2,
|
|
633
|
+
"p3": p3,
|
|
634
|
+
"p4": p4,
|
|
635
|
+
"p5": p5 if store == "zarr" else None,
|
|
636
|
+
"p6": p6 if store == "zarr" else None,
|
|
637
|
+
"p7": p7,
|
|
638
|
+
"p8": p8 if store == "zarr" else None,
|
|
639
|
+
"p9": p9 if store == "zarr" else None,
|
|
640
|
+
},
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
wk = hf.Workflow.from_template_data(
|
|
644
|
+
template_name="test_store_encoders",
|
|
645
|
+
tasks=[t1],
|
|
646
|
+
store=store,
|
|
647
|
+
path=tmp_path,
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
assert wk.tasks[0].elements[0].get("inputs.p1") == p1
|
|
651
|
+
assert wk.tasks[0].elements[0].get("inputs.p2") == p2
|
|
652
|
+
assert wk.tasks[0].elements[0].get("inputs.p3") == p3
|
|
653
|
+
assert wk.tasks[0].elements[0].get("inputs.p4") == p4
|
|
654
|
+
assert wk.tasks[0].elements[0].get("inputs.p7") == p7
|
|
655
|
+
|
|
656
|
+
if store == "zarr":
|
|
657
|
+
assert np.allclose(wk.tasks[0].elements[0].get("inputs.p5"), p5)
|
|
658
|
+
assert np.ma.allclose(wk.tasks[0].elements[0].get("inputs.p6"), p6)
|
|
659
|
+
assert np.ma.allclose(wk.tasks[0].elements[0].get("inputs.p8"), p8)
|
|
660
|
+
assert np.ma.allclose(wk.tasks[0].elements[0].get("inputs.p9.a2"), p9["a2"])
|
|
661
|
+
assert (
|
|
662
|
+
wk.tasks[0].elements[0].get("inputs.p9")["a2"].fill_value
|
|
663
|
+
== p9["a2"].fill_value
|
|
664
|
+
)
|