hpcflow-new2 0.2.0a190__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.
Files changed (130) hide show
  1. hpcflow/__pyinstaller/hook-hpcflow.py +1 -0
  2. hpcflow/_version.py +1 -1
  3. hpcflow/data/scripts/bad_script.py +2 -0
  4. hpcflow/data/scripts/do_nothing.py +2 -0
  5. hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
  6. hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
  7. hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
  8. hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
  9. hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
  10. hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
  11. hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
  12. hpcflow/data/scripts/input_file_generator_basic.py +3 -0
  13. hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
  14. hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
  15. hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
  16. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
  17. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
  18. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
  19. hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
  20. hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
  21. hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
  22. hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
  23. hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
  24. hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
  25. hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
  26. hpcflow/data/scripts/output_file_parser_basic.py +3 -0
  27. hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
  28. hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
  29. hpcflow/data/scripts/script_exit_test.py +5 -0
  30. hpcflow/data/template_components/environments.yaml +1 -1
  31. hpcflow/sdk/__init__.py +5 -0
  32. hpcflow/sdk/app.py +150 -89
  33. hpcflow/sdk/cli.py +263 -84
  34. hpcflow/sdk/cli_common.py +99 -5
  35. hpcflow/sdk/config/callbacks.py +38 -1
  36. hpcflow/sdk/config/config.py +102 -13
  37. hpcflow/sdk/config/errors.py +19 -5
  38. hpcflow/sdk/config/types.py +3 -0
  39. hpcflow/sdk/core/__init__.py +25 -1
  40. hpcflow/sdk/core/actions.py +914 -262
  41. hpcflow/sdk/core/cache.py +76 -34
  42. hpcflow/sdk/core/command_files.py +14 -128
  43. hpcflow/sdk/core/commands.py +35 -6
  44. hpcflow/sdk/core/element.py +122 -50
  45. hpcflow/sdk/core/errors.py +58 -2
  46. hpcflow/sdk/core/execute.py +207 -0
  47. hpcflow/sdk/core/loop.py +408 -50
  48. hpcflow/sdk/core/loop_cache.py +4 -4
  49. hpcflow/sdk/core/parameters.py +382 -37
  50. hpcflow/sdk/core/run_dir_files.py +13 -40
  51. hpcflow/sdk/core/skip_reason.py +7 -0
  52. hpcflow/sdk/core/task.py +119 -30
  53. hpcflow/sdk/core/task_schema.py +68 -0
  54. hpcflow/sdk/core/test_utils.py +66 -27
  55. hpcflow/sdk/core/types.py +54 -1
  56. hpcflow/sdk/core/utils.py +78 -7
  57. hpcflow/sdk/core/workflow.py +1538 -336
  58. hpcflow/sdk/data/workflow_spec_schema.yaml +2 -0
  59. hpcflow/sdk/demo/cli.py +7 -0
  60. hpcflow/sdk/helper/cli.py +1 -0
  61. hpcflow/sdk/log.py +42 -15
  62. hpcflow/sdk/persistence/base.py +405 -53
  63. hpcflow/sdk/persistence/json.py +177 -52
  64. hpcflow/sdk/persistence/pending.py +237 -69
  65. hpcflow/sdk/persistence/store_resource.py +3 -2
  66. hpcflow/sdk/persistence/types.py +15 -4
  67. hpcflow/sdk/persistence/zarr.py +928 -81
  68. hpcflow/sdk/submission/jobscript.py +1408 -489
  69. hpcflow/sdk/submission/schedulers/__init__.py +40 -5
  70. hpcflow/sdk/submission/schedulers/direct.py +33 -19
  71. hpcflow/sdk/submission/schedulers/sge.py +51 -16
  72. hpcflow/sdk/submission/schedulers/slurm.py +44 -16
  73. hpcflow/sdk/submission/schedulers/utils.py +7 -2
  74. hpcflow/sdk/submission/shells/base.py +68 -20
  75. hpcflow/sdk/submission/shells/bash.py +222 -129
  76. hpcflow/sdk/submission/shells/powershell.py +200 -150
  77. hpcflow/sdk/submission/submission.py +852 -119
  78. hpcflow/sdk/submission/types.py +18 -21
  79. hpcflow/sdk/typing.py +24 -5
  80. hpcflow/sdk/utils/arrays.py +71 -0
  81. hpcflow/sdk/utils/deferred_file.py +55 -0
  82. hpcflow/sdk/utils/hashing.py +16 -0
  83. hpcflow/sdk/utils/patches.py +12 -0
  84. hpcflow/sdk/utils/strings.py +33 -0
  85. hpcflow/tests/api/test_api.py +32 -0
  86. hpcflow/tests/conftest.py +19 -0
  87. hpcflow/tests/data/multi_path_sequences.yaml +29 -0
  88. hpcflow/tests/data/workflow_test_run_abort.yaml +34 -35
  89. hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
  90. hpcflow/tests/scripts/test_input_file_generators.py +282 -0
  91. hpcflow/tests/scripts/test_main_scripts.py +821 -70
  92. hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
  93. hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
  94. hpcflow/tests/shells/wsl/test_wsl_submission.py +6 -0
  95. hpcflow/tests/unit/test_action.py +176 -0
  96. hpcflow/tests/unit/test_app.py +20 -0
  97. hpcflow/tests/unit/test_cache.py +46 -0
  98. hpcflow/tests/unit/test_cli.py +133 -0
  99. hpcflow/tests/unit/test_config.py +122 -1
  100. hpcflow/tests/unit/test_element_iteration.py +47 -0
  101. hpcflow/tests/unit/test_jobscript_unit.py +757 -0
  102. hpcflow/tests/unit/test_loop.py +1332 -27
  103. hpcflow/tests/unit/test_meta_task.py +325 -0
  104. hpcflow/tests/unit/test_multi_path_sequences.py +229 -0
  105. hpcflow/tests/unit/test_parameter.py +13 -0
  106. hpcflow/tests/unit/test_persistence.py +190 -8
  107. hpcflow/tests/unit/test_run.py +109 -3
  108. hpcflow/tests/unit/test_run_directories.py +29 -0
  109. hpcflow/tests/unit/test_shell.py +20 -0
  110. hpcflow/tests/unit/test_submission.py +5 -76
  111. hpcflow/tests/unit/utils/test_arrays.py +40 -0
  112. hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
  113. hpcflow/tests/unit/utils/test_hashing.py +65 -0
  114. hpcflow/tests/unit/utils/test_patches.py +5 -0
  115. hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
  116. hpcflow/tests/workflows/__init__.py +0 -0
  117. hpcflow/tests/workflows/test_directory_structure.py +31 -0
  118. hpcflow/tests/workflows/test_jobscript.py +332 -0
  119. hpcflow/tests/workflows/test_run_status.py +198 -0
  120. hpcflow/tests/workflows/test_skip_downstream.py +696 -0
  121. hpcflow/tests/workflows/test_submission.py +140 -0
  122. hpcflow/tests/workflows/test_workflows.py +142 -2
  123. hpcflow/tests/workflows/test_zip.py +18 -0
  124. hpcflow/viz_demo.ipynb +6587 -3
  125. {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a199.dist-info}/METADATA +7 -4
  126. hpcflow_new2-0.2.0a199.dist-info/RECORD +221 -0
  127. hpcflow_new2-0.2.0a190.dist-info/RECORD +0 -165
  128. {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a199.dist-info}/LICENSE +0 -0
  129. {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a199.dist-info}/WHEEL +0 -0
  130. {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a199.dist-info}/entry_points.txt +0 -0
@@ -6,10 +6,12 @@ rules:
6
6
  - name
7
7
  - source_file
8
8
  - resources
9
+ - config
9
10
  - environments
10
11
  - env_presets
11
12
  - template_components
12
13
  - tasks
14
+ - meta_tasks
13
15
  - loops
14
16
  - store_kwargs
15
17
  - merge_resources
hpcflow/sdk/demo/cli.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """
2
2
  CLI components for demonstration code.
3
3
  """
4
+
4
5
  from __future__ import annotations
5
6
  from pathlib import Path
6
7
  from random import randint
@@ -25,12 +26,14 @@ from hpcflow.sdk.cli_common import (
25
26
  cancel_opt,
26
27
  submit_status_opt,
27
28
  make_status_opt,
29
+ add_sub_opt,
28
30
  )
29
31
 
30
32
  if TYPE_CHECKING:
31
33
  from collections.abc import Iterable
32
34
  from typing import Literal
33
35
  from ..app import BaseApp
36
+ from ..core.workflow import Workflow
34
37
 
35
38
 
36
39
  def get_demo_software_CLI(app: BaseApp):
@@ -116,6 +119,7 @@ def get_demo_workflow_CLI(app: BaseApp):
116
119
  @ts_name_fmt_option
117
120
  @variables_option
118
121
  @make_status_opt
122
+ @add_sub_opt
119
123
  def make_demo_workflow(
120
124
  workflow_name: str,
121
125
  format: Literal["json", "yaml"] | None,
@@ -127,6 +131,7 @@ def get_demo_workflow_CLI(app: BaseApp):
127
131
  ts_name_fmt: str | None = None,
128
132
  variables: Iterable[tuple[str, str]] = (),
129
133
  status: bool = True,
134
+ add_submission: bool = False,
130
135
  ):
131
136
  wk = app.make_demo_workflow(
132
137
  workflow_name=workflow_name,
@@ -139,7 +144,9 @@ def get_demo_workflow_CLI(app: BaseApp):
139
144
  ts_name_fmt=ts_name_fmt,
140
145
  variables=dict(variables),
141
146
  status=status,
147
+ add_submission=add_submission,
142
148
  )
149
+ assert isinstance(wk, Workflow)
143
150
  click.echo(wk.path)
144
151
 
145
152
  @demo_workflow.command("go")
hpcflow/sdk/helper/cli.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Common Click command line options related to the helper.
3
3
  """
4
+
4
5
  from __future__ import annotations
5
6
  from typing import TYPE_CHECKING
6
7
 
hpcflow/sdk/log.py CHANGED
@@ -58,6 +58,17 @@ class TimeIt:
58
58
  #: Preceding trace indices.
59
59
  trace_idx_prev: ClassVar[list[int]] = []
60
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
71
+
61
72
  @classmethod
62
73
  def decorator(cls, func: Callable[P, T]) -> Callable[P, T]:
63
74
  """
@@ -167,6 +178,14 @@ class TimeIt:
167
178
  else:
168
179
  print(out_str)
169
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
+
170
189
 
171
190
  class AppLog:
172
191
  """
@@ -176,11 +195,11 @@ class AppLog:
176
195
  #: Default logging level for the console.
177
196
  DEFAULT_LOG_CONSOLE_LEVEL: ClassVar = "WARNING"
178
197
  #: Default logging level for log files.
179
- DEFAULT_LOG_FILE_LEVEL: ClassVar = "INFO"
198
+ DEFAULT_LOG_FILE_LEVEL: ClassVar = "WARNING"
180
199
 
181
200
  def __init__(self, app: BaseApp, log_console_level: str | None = None) -> None:
182
201
  #: The application context.
183
- self.app = app
202
+ self._app = app
184
203
  #: The base logger for the application.
185
204
  self.logger = logging.getLogger(app.package_name)
186
205
  self.logger.setLevel(logging.DEBUG)
@@ -188,6 +207,7 @@ class AppLog:
188
207
  self.console_handler = self.__add_console_logger(
189
208
  level=log_console_level or AppLog.DEFAULT_LOG_CONSOLE_LEVEL
190
209
  )
210
+ self.file_handler: logging.FileHandler | None = None
191
211
 
192
212
  def __add_console_logger(self, level: str, fmt: str | None = None) -> logging.Handler:
193
213
  fmt = fmt or "%(levelname)s %(name)s: %(message)s"
@@ -197,23 +217,29 @@ class AppLog:
197
217
  self.logger.addHandler(handler)
198
218
  return handler
199
219
 
200
- def update_console_level(self, new_level: str) -> None:
220
+ def update_console_level(self, new_level: str | None = None) -> None:
201
221
  """
202
222
  Set the logging level for console messages.
203
223
  """
204
- if new_level:
205
- self.console_handler.setLevel(new_level.upper())
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())
206
231
 
207
232
  def add_file_logger(
208
233
  self,
209
- path: Path,
234
+ path: str | Path,
210
235
  level: str | None = None,
211
236
  fmt: str | None = None,
212
237
  max_bytes: int | None = None,
213
- ) -> logging.Handler:
238
+ ) -> None:
214
239
  """
215
240
  Add a log file.
216
241
  """
242
+ path = Path(path)
217
243
  fmt = fmt or "%(asctime)s %(levelname)s %(name)s: %(message)s"
218
244
  level = level or AppLog.DEFAULT_LOG_FILE_LEVEL
219
245
  max_bytes = max_bytes or int(10e6)
@@ -226,12 +252,13 @@ class AppLog:
226
252
  handler.setFormatter(logging.Formatter(fmt))
227
253
  handler.setLevel(level.upper())
228
254
  self.logger.addHandler(handler)
229
- return handler
255
+ self.file_handler = handler
230
256
 
231
- def remove_file_handlers(self) -> None:
232
- """Remove all file handlers."""
233
- # TODO: store a `file_handlers` attribute as well as `console_handlers`
234
- for hdlr in self.logger.handlers:
235
- if isinstance(hdlr, logging.FileHandler):
236
- self.logger.debug(f"Removing file handler from the AppLog: {hdlr!r}.")
237
- self.logger.removeHandler(hdlr)
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