hpcflow-new2 0.2.0a189__py3-none-any.whl → 0.2.0a199__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/__pyinstaller/hook-hpcflow.py +9 -6
- hpcflow/_version.py +1 -1
- hpcflow/app.py +1 -0
- hpcflow/data/scripts/bad_script.py +2 -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/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_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_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_hdf5_in_obj.py +1 -1
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +1 -1
- hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -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/script_exit_test.py +5 -0
- hpcflow/data/template_components/environments.yaml +1 -1
- hpcflow/sdk/__init__.py +26 -15
- hpcflow/sdk/app.py +2192 -768
- hpcflow/sdk/cli.py +506 -296
- hpcflow/sdk/cli_common.py +105 -7
- hpcflow/sdk/config/__init__.py +1 -1
- hpcflow/sdk/config/callbacks.py +115 -43
- hpcflow/sdk/config/cli.py +126 -103
- hpcflow/sdk/config/config.py +674 -318
- hpcflow/sdk/config/config_file.py +131 -95
- hpcflow/sdk/config/errors.py +125 -84
- hpcflow/sdk/config/types.py +148 -0
- hpcflow/sdk/core/__init__.py +25 -1
- hpcflow/sdk/core/actions.py +1771 -1059
- hpcflow/sdk/core/app_aware.py +24 -0
- hpcflow/sdk/core/cache.py +139 -79
- hpcflow/sdk/core/command_files.py +263 -287
- hpcflow/sdk/core/commands.py +145 -112
- hpcflow/sdk/core/element.py +828 -535
- hpcflow/sdk/core/enums.py +192 -0
- hpcflow/sdk/core/environment.py +74 -93
- hpcflow/sdk/core/errors.py +455 -52
- hpcflow/sdk/core/execute.py +207 -0
- hpcflow/sdk/core/json_like.py +540 -272
- hpcflow/sdk/core/loop.py +751 -347
- hpcflow/sdk/core/loop_cache.py +164 -47
- hpcflow/sdk/core/object_list.py +370 -207
- hpcflow/sdk/core/parameters.py +1100 -627
- hpcflow/sdk/core/rule.py +59 -41
- hpcflow/sdk/core/run_dir_files.py +21 -37
- hpcflow/sdk/core/skip_reason.py +7 -0
- hpcflow/sdk/core/task.py +1649 -1339
- hpcflow/sdk/core/task_schema.py +308 -196
- hpcflow/sdk/core/test_utils.py +191 -114
- hpcflow/sdk/core/types.py +440 -0
- hpcflow/sdk/core/utils.py +485 -309
- hpcflow/sdk/core/validation.py +82 -9
- hpcflow/sdk/core/workflow.py +2544 -1178
- hpcflow/sdk/core/zarr_io.py +98 -137
- hpcflow/sdk/data/workflow_spec_schema.yaml +2 -0
- hpcflow/sdk/demo/cli.py +53 -33
- hpcflow/sdk/helper/cli.py +18 -15
- hpcflow/sdk/helper/helper.py +75 -63
- hpcflow/sdk/helper/watcher.py +61 -28
- hpcflow/sdk/log.py +122 -71
- hpcflow/sdk/persistence/__init__.py +8 -31
- hpcflow/sdk/persistence/base.py +1360 -606
- hpcflow/sdk/persistence/defaults.py +6 -0
- hpcflow/sdk/persistence/discovery.py +38 -0
- hpcflow/sdk/persistence/json.py +568 -188
- hpcflow/sdk/persistence/pending.py +382 -179
- hpcflow/sdk/persistence/store_resource.py +39 -23
- hpcflow/sdk/persistence/types.py +318 -0
- hpcflow/sdk/persistence/utils.py +14 -11
- hpcflow/sdk/persistence/zarr.py +1337 -433
- hpcflow/sdk/runtime.py +44 -41
- hpcflow/sdk/submission/{jobscript_info.py → enums.py} +39 -12
- hpcflow/sdk/submission/jobscript.py +1651 -692
- hpcflow/sdk/submission/schedulers/__init__.py +167 -39
- hpcflow/sdk/submission/schedulers/direct.py +121 -81
- hpcflow/sdk/submission/schedulers/sge.py +170 -129
- hpcflow/sdk/submission/schedulers/slurm.py +291 -268
- hpcflow/sdk/submission/schedulers/utils.py +12 -2
- hpcflow/sdk/submission/shells/__init__.py +14 -15
- hpcflow/sdk/submission/shells/base.py +150 -29
- hpcflow/sdk/submission/shells/bash.py +283 -173
- hpcflow/sdk/submission/shells/os_version.py +31 -30
- hpcflow/sdk/submission/shells/powershell.py +228 -170
- hpcflow/sdk/submission/submission.py +1014 -335
- hpcflow/sdk/submission/types.py +140 -0
- hpcflow/sdk/typing.py +182 -12
- hpcflow/sdk/utils/arrays.py +71 -0
- hpcflow/sdk/utils/deferred_file.py +55 -0
- hpcflow/sdk/utils/hashing.py +16 -0
- hpcflow/sdk/utils/patches.py +12 -0
- hpcflow/sdk/utils/strings.py +33 -0
- hpcflow/tests/api/test_api.py +32 -0
- hpcflow/tests/conftest.py +27 -6
- hpcflow/tests/data/multi_path_sequences.yaml +29 -0
- hpcflow/tests/data/workflow_test_run_abort.yaml +34 -35
- hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
- hpcflow/tests/schedulers/slurm/test_slurm_submission.py +5 -2
- hpcflow/tests/scripts/test_input_file_generators.py +282 -0
- hpcflow/tests/scripts/test_main_scripts.py +866 -85
- 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 +12 -4
- hpcflow/tests/unit/test_action.py +262 -75
- hpcflow/tests/unit/test_action_rule.py +9 -4
- hpcflow/tests/unit/test_app.py +33 -6
- hpcflow/tests/unit/test_cache.py +46 -0
- hpcflow/tests/unit/test_cli.py +134 -1
- hpcflow/tests/unit/test_command.py +71 -54
- hpcflow/tests/unit/test_config.py +142 -16
- hpcflow/tests/unit/test_config_file.py +21 -18
- hpcflow/tests/unit/test_element.py +58 -62
- hpcflow/tests/unit/test_element_iteration.py +50 -1
- hpcflow/tests/unit/test_element_set.py +29 -19
- hpcflow/tests/unit/test_group.py +4 -2
- hpcflow/tests/unit/test_input_source.py +116 -93
- hpcflow/tests/unit/test_input_value.py +29 -24
- hpcflow/tests/unit/test_jobscript_unit.py +757 -0
- hpcflow/tests/unit/test_json_like.py +44 -35
- hpcflow/tests/unit/test_loop.py +1396 -84
- hpcflow/tests/unit/test_meta_task.py +325 -0
- hpcflow/tests/unit/test_multi_path_sequences.py +229 -0
- hpcflow/tests/unit/test_object_list.py +17 -12
- hpcflow/tests/unit/test_parameter.py +29 -7
- hpcflow/tests/unit/test_persistence.py +237 -42
- hpcflow/tests/unit/test_resources.py +20 -18
- hpcflow/tests/unit/test_run.py +117 -6
- hpcflow/tests/unit/test_run_directories.py +29 -0
- hpcflow/tests/unit/test_runtime.py +2 -1
- hpcflow/tests/unit/test_schema_input.py +23 -15
- hpcflow/tests/unit/test_shell.py +23 -2
- hpcflow/tests/unit/test_slurm.py +8 -7
- hpcflow/tests/unit/test_submission.py +38 -89
- hpcflow/tests/unit/test_task.py +352 -247
- hpcflow/tests/unit/test_task_schema.py +33 -20
- hpcflow/tests/unit/test_utils.py +9 -11
- hpcflow/tests/unit/test_value_sequence.py +15 -12
- hpcflow/tests/unit/test_workflow.py +114 -83
- hpcflow/tests/unit/test_workflow_template.py +0 -1
- 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/workflows/__init__.py +0 -0
- hpcflow/tests/workflows/test_directory_structure.py +31 -0
- hpcflow/tests/workflows/test_jobscript.py +334 -1
- 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 +160 -15
- hpcflow/tests/workflows/test_zip.py +18 -0
- hpcflow/viz_demo.ipynb +6587 -3
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/METADATA +8 -4
- hpcflow_new2-0.2.0a199.dist-info/RECORD +221 -0
- hpcflow/sdk/core/parallel.py +0 -21
- hpcflow_new2-0.2.0a189.dist-info/RECORD +0 -158
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/LICENSE +0 -0
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/entry_points.txt +0 -0
hpcflow/sdk/log.py
CHANGED
@@ -2,12 +2,40 @@
|
|
2
2
|
Interface to the standard logger, and performance logging utility.
|
3
3
|
"""
|
4
4
|
|
5
|
+
from __future__ import annotations
|
5
6
|
from functools import wraps
|
6
7
|
import logging
|
8
|
+
import logging.handlers
|
7
9
|
from pathlib import Path
|
8
10
|
import time
|
9
11
|
from collections import defaultdict
|
12
|
+
from collections.abc import Callable, Sequence
|
10
13
|
import statistics
|
14
|
+
from dataclasses import dataclass
|
15
|
+
from typing import ClassVar, TypeVar, TYPE_CHECKING
|
16
|
+
from typing_extensions import ParamSpec
|
17
|
+
|
18
|
+
if TYPE_CHECKING:
|
19
|
+
from .app import BaseApp
|
20
|
+
|
21
|
+
|
22
|
+
P = ParamSpec("P")
|
23
|
+
T = TypeVar("T")
|
24
|
+
|
25
|
+
|
26
|
+
@dataclass
|
27
|
+
class _Summary:
|
28
|
+
"""
|
29
|
+
Summary of a particular node's execution time.
|
30
|
+
"""
|
31
|
+
|
32
|
+
number: int
|
33
|
+
mean: float
|
34
|
+
stddev: float
|
35
|
+
min: float
|
36
|
+
max: float
|
37
|
+
sum: float
|
38
|
+
children: dict[tuple[str, ...], _Summary]
|
11
39
|
|
12
40
|
|
13
41
|
class TimeIt:
|
@@ -16,29 +44,39 @@ class TimeIt:
|
|
16
44
|
"""
|
17
45
|
|
18
46
|
#: Whether the instrumentation is active.
|
19
|
-
active = False
|
47
|
+
active: ClassVar = False
|
20
48
|
#: Where to log to.
|
21
|
-
file_path = None
|
49
|
+
file_path: ClassVar[str | None] = None
|
22
50
|
#: The details be tracked.
|
23
|
-
timers = defaultdict(list)
|
51
|
+
timers: ClassVar[dict[tuple[str, ...], list[float]]] = defaultdict(list)
|
24
52
|
#: Traces of the stack.
|
25
|
-
trace = []
|
53
|
+
trace: ClassVar[list[str]] = []
|
26
54
|
#: Trace indices.
|
27
|
-
trace_idx = []
|
55
|
+
trace_idx: ClassVar[list[int]] = []
|
28
56
|
#: Preceding traces.
|
29
|
-
trace_prev = []
|
57
|
+
trace_prev: ClassVar[list[str]] = []
|
30
58
|
#: Preceding trace indices.
|
31
|
-
trace_idx_prev = []
|
59
|
+
trace_idx_prev: ClassVar[list[int]] = []
|
60
|
+
|
61
|
+
def __enter__(self):
|
62
|
+
self.__class__.active = True
|
63
|
+
return self
|
64
|
+
|
65
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
66
|
+
try:
|
67
|
+
self.__class__.summarise_string()
|
68
|
+
finally:
|
69
|
+
self.__class__.reset()
|
70
|
+
self.__class__.active = False
|
32
71
|
|
33
72
|
@classmethod
|
34
|
-
def decorator(cls, func):
|
73
|
+
def decorator(cls, func: Callable[P, T]) -> Callable[P, T]:
|
35
74
|
"""
|
36
75
|
Decorator for a method that is to have its execution time monitored.
|
37
76
|
"""
|
38
77
|
|
39
78
|
@wraps(func)
|
40
|
-
def wrapper(*args, **kwargs):
|
41
|
-
|
79
|
+
def wrapper(*args, **kwargs) -> T:
|
42
80
|
if not cls.active:
|
43
81
|
return func(*args, **kwargs)
|
44
82
|
|
@@ -68,48 +106,45 @@ class TimeIt:
|
|
68
106
|
return wrapper
|
69
107
|
|
70
108
|
@classmethod
|
71
|
-
def
|
109
|
+
def _summarise(cls) -> dict[tuple[str, ...], _Summary]:
|
72
110
|
"""
|
73
111
|
Produce a machine-readable summary of method execution time statistics.
|
74
112
|
"""
|
75
113
|
stats = {
|
76
|
-
k:
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
114
|
+
k: _Summary(
|
115
|
+
len(v),
|
116
|
+
statistics.mean(v),
|
117
|
+
statistics.pstdev(v),
|
118
|
+
min(v),
|
119
|
+
max(v),
|
120
|
+
sum(v),
|
121
|
+
{},
|
122
|
+
)
|
84
123
|
for k, v in cls.timers.items()
|
85
124
|
}
|
86
125
|
|
87
126
|
# make a graph
|
88
|
-
for
|
89
|
-
stats[k]["children"] = {}
|
90
|
-
|
91
|
-
for key in sorted(stats.keys(), key=lambda x: len(x), reverse=True):
|
127
|
+
for key in sorted(stats, key=lambda x: len(x), reverse=True):
|
92
128
|
if len(key) == 1:
|
93
129
|
continue
|
94
130
|
value = stats.pop(key)
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
stats[other_key]["children"][key] = value
|
99
|
-
break
|
131
|
+
parent_key = key[:-1]
|
132
|
+
if parent_key in stats:
|
133
|
+
stats[parent_key].children[key] = value
|
100
134
|
|
101
135
|
return stats
|
102
136
|
|
103
137
|
@classmethod
|
104
|
-
def summarise_string(cls):
|
138
|
+
def summarise_string(cls) -> None:
|
105
139
|
"""
|
106
140
|
Produce a human-readable summary of method execution time statistics.
|
107
141
|
"""
|
108
142
|
|
109
|
-
def _format_nodes(
|
110
|
-
|
111
|
-
|
112
|
-
|
143
|
+
def _format_nodes(
|
144
|
+
node: dict[tuple[str, ...], _Summary],
|
145
|
+
depth: int = 0,
|
146
|
+
depth_final: Sequence[bool] = (),
|
147
|
+
):
|
113
148
|
for idx, (k, v) in enumerate(node.items()):
|
114
149
|
is_final_child = idx == len(node) - 1
|
115
150
|
angle = "└ " if is_final_child else "├ "
|
@@ -117,38 +152,40 @@ class TimeIt:
|
|
117
152
|
if depth > 0:
|
118
153
|
bars = "".join(f"{'│ ' if not i else ' '}" for i in depth_final)
|
119
154
|
k_str = bars + (angle if depth > 0 else "") + f"{k[depth]}"
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
stddev_str = f"({v['stddev']:8.6f})" if number > 1 else f"{f' ':^10s}"
|
155
|
+
min_str = f"{v.min:10.6f}" if v.number > 1 else f"{f'-':^12s}"
|
156
|
+
max_str = f"{v.max:10.6f}" if v.number > 1 else f"{f'-':^12s}"
|
157
|
+
stddev_str = f"({v.stddev:8.6f})" if v.number > 1 else f"{f' ':^10s}"
|
124
158
|
out.append(
|
125
|
-
f"{k_str:.<80s} {v
|
126
|
-
f"{v
|
159
|
+
f"{k_str:.<80s} {v.sum:12.6f} "
|
160
|
+
f"{v.mean:10.6f} {stddev_str} {v.number:8d} "
|
127
161
|
f"{min_str} {max_str} "
|
128
162
|
)
|
129
|
-
depth_final_next = list(depth_final)
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
_format_nodes(
|
134
|
-
v["children"], depth=depth + 1, depth_final=depth_final_next
|
135
|
-
)
|
136
|
-
)
|
137
|
-
return out
|
163
|
+
depth_final_next = list(depth_final)
|
164
|
+
if depth > 0:
|
165
|
+
depth_final_next.append(is_final_child)
|
166
|
+
_format_nodes(v.children, depth + 1, depth_final_next)
|
138
167
|
|
139
|
-
summary = cls.
|
168
|
+
summary = cls._summarise()
|
140
169
|
|
141
170
|
out = [
|
142
171
|
f"{'function':^80s} {'sum /s':^12s} {'mean (stddev) /s':^20s} {'N':^8s} "
|
143
172
|
f"{'min /s':^12s} {'max /s':^12s}"
|
144
173
|
]
|
145
|
-
|
174
|
+
_format_nodes(summary)
|
146
175
|
out_str = "\n".join(out)
|
147
176
|
if cls.file_path:
|
148
177
|
Path(cls.file_path).write_text(out_str, encoding="utf-8")
|
149
178
|
else:
|
150
179
|
print(out_str)
|
151
180
|
|
181
|
+
@classmethod
|
182
|
+
def reset(cls):
|
183
|
+
cls.timers = defaultdict(list)
|
184
|
+
cls.trace = []
|
185
|
+
cls.trace_idx = []
|
186
|
+
cls.trace_prev = []
|
187
|
+
cls.trace_idx_prev = []
|
188
|
+
|
152
189
|
|
153
190
|
class AppLog:
|
154
191
|
"""
|
@@ -156,22 +193,23 @@ class AppLog:
|
|
156
193
|
"""
|
157
194
|
|
158
195
|
#: Default logging level for the console.
|
159
|
-
DEFAULT_LOG_CONSOLE_LEVEL = "WARNING"
|
196
|
+
DEFAULT_LOG_CONSOLE_LEVEL: ClassVar = "WARNING"
|
160
197
|
#: Default logging level for log files.
|
161
|
-
DEFAULT_LOG_FILE_LEVEL = "
|
198
|
+
DEFAULT_LOG_FILE_LEVEL: ClassVar = "WARNING"
|
162
199
|
|
163
|
-
def __init__(self, app, log_console_level=None):
|
200
|
+
def __init__(self, app: BaseApp, log_console_level: str | None = None) -> None:
|
164
201
|
#: The application context.
|
165
|
-
self.
|
202
|
+
self._app = app
|
166
203
|
#: The base logger for the application.
|
167
204
|
self.logger = logging.getLogger(app.package_name)
|
168
205
|
self.logger.setLevel(logging.DEBUG)
|
169
206
|
#: The handler for directing logging messages to the console.
|
170
|
-
self.console_handler = self.
|
207
|
+
self.console_handler = self.__add_console_logger(
|
171
208
|
level=log_console_level or AppLog.DEFAULT_LOG_CONSOLE_LEVEL
|
172
209
|
)
|
210
|
+
self.file_handler: logging.FileHandler | None = None
|
173
211
|
|
174
|
-
def
|
212
|
+
def __add_console_logger(self, level: str, fmt: str | None = None) -> logging.Handler:
|
175
213
|
fmt = fmt or "%(levelname)s %(name)s: %(message)s"
|
176
214
|
handler = logging.StreamHandler()
|
177
215
|
handler.setFormatter(logging.Formatter(fmt))
|
@@ -179,18 +217,30 @@ class AppLog:
|
|
179
217
|
self.logger.addHandler(handler)
|
180
218
|
return handler
|
181
219
|
|
182
|
-
def update_console_level(self, new_level):
|
220
|
+
def update_console_level(self, new_level: str | None = None) -> None:
|
183
221
|
"""
|
184
222
|
Set the logging level for console messages.
|
185
223
|
"""
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
def
|
224
|
+
new_level = new_level or AppLog.DEFAULT_LOG_CONSOLE_LEVEL
|
225
|
+
self.console_handler.setLevel(new_level.upper())
|
226
|
+
|
227
|
+
def update_file_level(self, new_level: str | None = None) -> None:
|
228
|
+
if self.file_handler:
|
229
|
+
new_level = new_level or AppLog.DEFAULT_LOG_FILE_LEVEL
|
230
|
+
self.file_handler.setLevel(new_level.upper())
|
231
|
+
|
232
|
+
def add_file_logger(
|
233
|
+
self,
|
234
|
+
path: str | Path,
|
235
|
+
level: str | None = None,
|
236
|
+
fmt: str | None = None,
|
237
|
+
max_bytes: int | None = None,
|
238
|
+
) -> None:
|
190
239
|
"""
|
191
240
|
Add a log file.
|
192
241
|
"""
|
193
|
-
|
242
|
+
path = Path(path)
|
243
|
+
fmt = fmt or "%(asctime)s %(levelname)s %(name)s: %(message)s"
|
194
244
|
level = level or AppLog.DEFAULT_LOG_FILE_LEVEL
|
195
245
|
max_bytes = max_bytes or int(10e6)
|
196
246
|
|
@@ -202,12 +252,13 @@ class AppLog:
|
|
202
252
|
handler.setFormatter(logging.Formatter(fmt))
|
203
253
|
handler.setLevel(level.upper())
|
204
254
|
self.logger.addHandler(handler)
|
205
|
-
|
206
|
-
|
207
|
-
def
|
208
|
-
"""Remove
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
255
|
+
self.file_handler = handler
|
256
|
+
|
257
|
+
def remove_file_handler(self) -> None:
|
258
|
+
"""Remove the file handler."""
|
259
|
+
if self.file_handler:
|
260
|
+
self.logger.debug(
|
261
|
+
f"Removing file handler from the AppLog: {self.file_handler!r}."
|
262
|
+
)
|
263
|
+
self.logger.removeHandler(self.file_handler)
|
264
|
+
self.file_handler = None
|
@@ -2,40 +2,17 @@
|
|
2
2
|
Workflow persistence subsystem.
|
3
3
|
"""
|
4
4
|
|
5
|
-
import
|
6
|
-
from
|
7
|
-
import random
|
8
|
-
import string
|
9
|
-
import time
|
10
|
-
from typing import Type, Union
|
5
|
+
from __future__ import annotations
|
6
|
+
from typing import TYPE_CHECKING
|
11
7
|
|
12
|
-
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from .base import PersistentStore
|
13
10
|
|
14
|
-
from hpcflow.sdk.persistence.base import PersistentStore
|
15
|
-
from hpcflow.sdk.persistence.json import JSONPersistentStore
|
16
|
-
from hpcflow.sdk.persistence.zarr import ZarrPersistentStore, ZarrZipPersistentStore
|
17
11
|
|
18
|
-
|
19
|
-
"zarr": ZarrPersistentStore,
|
20
|
-
"zip": ZarrZipPersistentStore,
|
21
|
-
"json": JSONPersistentStore,
|
22
|
-
# "json-single": JSONPersistentStore, # TODO
|
23
|
-
}
|
24
|
-
#: The name of the default persistence store.
|
25
|
-
DEFAULT_STORE_FORMAT = "zarr"
|
26
|
-
#: The persistence formats supported.
|
27
|
-
ALL_STORE_FORMATS = tuple(_ALL_STORE_CLS.keys())
|
28
|
-
#: The persistence formats supported for creation.
|
29
|
-
ALL_CREATE_STORE_FORMATS = tuple(
|
30
|
-
k for k, v in _ALL_STORE_CLS.items() if v._features.create
|
31
|
-
)
|
32
|
-
|
33
|
-
|
34
|
-
def store_cls_from_str(store_format: str) -> Type[PersistentStore]:
|
12
|
+
def store_cls_from_str(store_format: str) -> type[PersistentStore]:
|
35
13
|
"""
|
36
14
|
Get the class that implements the persistence store from its name.
|
37
15
|
"""
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
raise ValueError(f"Store format {store_format!r} not known.")
|
16
|
+
from .discovery import store_cls_from_str as impl
|
17
|
+
|
18
|
+
return impl(store_format)
|