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.
Files changed (176) hide show
  1. hpcflow/__pyinstaller/hook-hpcflow.py +9 -6
  2. hpcflow/_version.py +1 -1
  3. hpcflow/app.py +1 -0
  4. hpcflow/data/scripts/bad_script.py +2 -0
  5. hpcflow/data/scripts/do_nothing.py +2 -0
  6. hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
  7. hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
  8. hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
  9. hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
  10. hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
  11. hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
  12. hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
  13. hpcflow/data/scripts/input_file_generator_basic.py +3 -0
  14. hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
  15. hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
  16. hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
  17. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
  18. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
  19. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
  20. hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
  21. hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
  22. hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
  23. hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +1 -1
  24. hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
  25. hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +1 -1
  26. hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
  27. hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
  28. hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
  29. hpcflow/data/scripts/output_file_parser_basic.py +3 -0
  30. hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
  31. hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
  32. hpcflow/data/scripts/script_exit_test.py +5 -0
  33. hpcflow/data/template_components/environments.yaml +1 -1
  34. hpcflow/sdk/__init__.py +26 -15
  35. hpcflow/sdk/app.py +2192 -768
  36. hpcflow/sdk/cli.py +506 -296
  37. hpcflow/sdk/cli_common.py +105 -7
  38. hpcflow/sdk/config/__init__.py +1 -1
  39. hpcflow/sdk/config/callbacks.py +115 -43
  40. hpcflow/sdk/config/cli.py +126 -103
  41. hpcflow/sdk/config/config.py +674 -318
  42. hpcflow/sdk/config/config_file.py +131 -95
  43. hpcflow/sdk/config/errors.py +125 -84
  44. hpcflow/sdk/config/types.py +148 -0
  45. hpcflow/sdk/core/__init__.py +25 -1
  46. hpcflow/sdk/core/actions.py +1771 -1059
  47. hpcflow/sdk/core/app_aware.py +24 -0
  48. hpcflow/sdk/core/cache.py +139 -79
  49. hpcflow/sdk/core/command_files.py +263 -287
  50. hpcflow/sdk/core/commands.py +145 -112
  51. hpcflow/sdk/core/element.py +828 -535
  52. hpcflow/sdk/core/enums.py +192 -0
  53. hpcflow/sdk/core/environment.py +74 -93
  54. hpcflow/sdk/core/errors.py +455 -52
  55. hpcflow/sdk/core/execute.py +207 -0
  56. hpcflow/sdk/core/json_like.py +540 -272
  57. hpcflow/sdk/core/loop.py +751 -347
  58. hpcflow/sdk/core/loop_cache.py +164 -47
  59. hpcflow/sdk/core/object_list.py +370 -207
  60. hpcflow/sdk/core/parameters.py +1100 -627
  61. hpcflow/sdk/core/rule.py +59 -41
  62. hpcflow/sdk/core/run_dir_files.py +21 -37
  63. hpcflow/sdk/core/skip_reason.py +7 -0
  64. hpcflow/sdk/core/task.py +1649 -1339
  65. hpcflow/sdk/core/task_schema.py +308 -196
  66. hpcflow/sdk/core/test_utils.py +191 -114
  67. hpcflow/sdk/core/types.py +440 -0
  68. hpcflow/sdk/core/utils.py +485 -309
  69. hpcflow/sdk/core/validation.py +82 -9
  70. hpcflow/sdk/core/workflow.py +2544 -1178
  71. hpcflow/sdk/core/zarr_io.py +98 -137
  72. hpcflow/sdk/data/workflow_spec_schema.yaml +2 -0
  73. hpcflow/sdk/demo/cli.py +53 -33
  74. hpcflow/sdk/helper/cli.py +18 -15
  75. hpcflow/sdk/helper/helper.py +75 -63
  76. hpcflow/sdk/helper/watcher.py +61 -28
  77. hpcflow/sdk/log.py +122 -71
  78. hpcflow/sdk/persistence/__init__.py +8 -31
  79. hpcflow/sdk/persistence/base.py +1360 -606
  80. hpcflow/sdk/persistence/defaults.py +6 -0
  81. hpcflow/sdk/persistence/discovery.py +38 -0
  82. hpcflow/sdk/persistence/json.py +568 -188
  83. hpcflow/sdk/persistence/pending.py +382 -179
  84. hpcflow/sdk/persistence/store_resource.py +39 -23
  85. hpcflow/sdk/persistence/types.py +318 -0
  86. hpcflow/sdk/persistence/utils.py +14 -11
  87. hpcflow/sdk/persistence/zarr.py +1337 -433
  88. hpcflow/sdk/runtime.py +44 -41
  89. hpcflow/sdk/submission/{jobscript_info.py → enums.py} +39 -12
  90. hpcflow/sdk/submission/jobscript.py +1651 -692
  91. hpcflow/sdk/submission/schedulers/__init__.py +167 -39
  92. hpcflow/sdk/submission/schedulers/direct.py +121 -81
  93. hpcflow/sdk/submission/schedulers/sge.py +170 -129
  94. hpcflow/sdk/submission/schedulers/slurm.py +291 -268
  95. hpcflow/sdk/submission/schedulers/utils.py +12 -2
  96. hpcflow/sdk/submission/shells/__init__.py +14 -15
  97. hpcflow/sdk/submission/shells/base.py +150 -29
  98. hpcflow/sdk/submission/shells/bash.py +283 -173
  99. hpcflow/sdk/submission/shells/os_version.py +31 -30
  100. hpcflow/sdk/submission/shells/powershell.py +228 -170
  101. hpcflow/sdk/submission/submission.py +1014 -335
  102. hpcflow/sdk/submission/types.py +140 -0
  103. hpcflow/sdk/typing.py +182 -12
  104. hpcflow/sdk/utils/arrays.py +71 -0
  105. hpcflow/sdk/utils/deferred_file.py +55 -0
  106. hpcflow/sdk/utils/hashing.py +16 -0
  107. hpcflow/sdk/utils/patches.py +12 -0
  108. hpcflow/sdk/utils/strings.py +33 -0
  109. hpcflow/tests/api/test_api.py +32 -0
  110. hpcflow/tests/conftest.py +27 -6
  111. hpcflow/tests/data/multi_path_sequences.yaml +29 -0
  112. hpcflow/tests/data/workflow_test_run_abort.yaml +34 -35
  113. hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
  114. hpcflow/tests/schedulers/slurm/test_slurm_submission.py +5 -2
  115. hpcflow/tests/scripts/test_input_file_generators.py +282 -0
  116. hpcflow/tests/scripts/test_main_scripts.py +866 -85
  117. hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
  118. hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
  119. hpcflow/tests/shells/wsl/test_wsl_submission.py +12 -4
  120. hpcflow/tests/unit/test_action.py +262 -75
  121. hpcflow/tests/unit/test_action_rule.py +9 -4
  122. hpcflow/tests/unit/test_app.py +33 -6
  123. hpcflow/tests/unit/test_cache.py +46 -0
  124. hpcflow/tests/unit/test_cli.py +134 -1
  125. hpcflow/tests/unit/test_command.py +71 -54
  126. hpcflow/tests/unit/test_config.py +142 -16
  127. hpcflow/tests/unit/test_config_file.py +21 -18
  128. hpcflow/tests/unit/test_element.py +58 -62
  129. hpcflow/tests/unit/test_element_iteration.py +50 -1
  130. hpcflow/tests/unit/test_element_set.py +29 -19
  131. hpcflow/tests/unit/test_group.py +4 -2
  132. hpcflow/tests/unit/test_input_source.py +116 -93
  133. hpcflow/tests/unit/test_input_value.py +29 -24
  134. hpcflow/tests/unit/test_jobscript_unit.py +757 -0
  135. hpcflow/tests/unit/test_json_like.py +44 -35
  136. hpcflow/tests/unit/test_loop.py +1396 -84
  137. hpcflow/tests/unit/test_meta_task.py +325 -0
  138. hpcflow/tests/unit/test_multi_path_sequences.py +229 -0
  139. hpcflow/tests/unit/test_object_list.py +17 -12
  140. hpcflow/tests/unit/test_parameter.py +29 -7
  141. hpcflow/tests/unit/test_persistence.py +237 -42
  142. hpcflow/tests/unit/test_resources.py +20 -18
  143. hpcflow/tests/unit/test_run.py +117 -6
  144. hpcflow/tests/unit/test_run_directories.py +29 -0
  145. hpcflow/tests/unit/test_runtime.py +2 -1
  146. hpcflow/tests/unit/test_schema_input.py +23 -15
  147. hpcflow/tests/unit/test_shell.py +23 -2
  148. hpcflow/tests/unit/test_slurm.py +8 -7
  149. hpcflow/tests/unit/test_submission.py +38 -89
  150. hpcflow/tests/unit/test_task.py +352 -247
  151. hpcflow/tests/unit/test_task_schema.py +33 -20
  152. hpcflow/tests/unit/test_utils.py +9 -11
  153. hpcflow/tests/unit/test_value_sequence.py +15 -12
  154. hpcflow/tests/unit/test_workflow.py +114 -83
  155. hpcflow/tests/unit/test_workflow_template.py +0 -1
  156. hpcflow/tests/unit/utils/test_arrays.py +40 -0
  157. hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
  158. hpcflow/tests/unit/utils/test_hashing.py +65 -0
  159. hpcflow/tests/unit/utils/test_patches.py +5 -0
  160. hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
  161. hpcflow/tests/workflows/__init__.py +0 -0
  162. hpcflow/tests/workflows/test_directory_structure.py +31 -0
  163. hpcflow/tests/workflows/test_jobscript.py +334 -1
  164. hpcflow/tests/workflows/test_run_status.py +198 -0
  165. hpcflow/tests/workflows/test_skip_downstream.py +696 -0
  166. hpcflow/tests/workflows/test_submission.py +140 -0
  167. hpcflow/tests/workflows/test_workflows.py +160 -15
  168. hpcflow/tests/workflows/test_zip.py +18 -0
  169. hpcflow/viz_demo.ipynb +6587 -3
  170. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/METADATA +8 -4
  171. hpcflow_new2-0.2.0a199.dist-info/RECORD +221 -0
  172. hpcflow/sdk/core/parallel.py +0 -21
  173. hpcflow_new2-0.2.0a189.dist-info/RECORD +0 -158
  174. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/LICENSE +0 -0
  175. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/WHEEL +0 -0
  176. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
1
2
  from datetime import timedelta
2
-
3
+ from typing import Any
4
+ from typing_extensions import TypedDict
3
5
  import pytest
4
6
 
5
7
  from hpcflow.app import app as hf
@@ -8,8 +10,8 @@ from hpcflow.sdk.core.errors import (
8
10
  MissingEnvironmentExecutableError,
9
11
  MissingEnvironmentExecutableInstanceError,
10
12
  )
13
+ from hpcflow.sdk.core.utils import timedelta_format, timedelta_parse
11
14
  from hpcflow.sdk.submission.jobscript import group_resource_map_into_jobscripts
12
- from hpcflow.sdk.submission.submission import timedelta_format, timedelta_parse
13
15
 
14
16
 
15
17
  @pytest.fixture
@@ -18,9 +20,14 @@ def null_config(tmp_path):
18
20
  hf.load_config(config_dir=tmp_path)
19
21
 
20
22
 
21
- def test_group_resource_map_into_jobscripts(null_config):
23
+ class _Example(TypedDict):
24
+ resources: list[list[int]]
25
+ expected: list[dict[str, Any]]
26
+
27
+
28
+ def test_group_resource_map_into_jobscripts(null_config) -> None:
22
29
  # x-axis corresponds to elements; y-axis corresponds to actions:
23
- examples = (
30
+ examples: tuple[_Example, ...] = (
24
31
  {
25
32
  "resources": [
26
33
  [1, 1, 1, 2, -1, 2, 4, -1, 1],
@@ -178,13 +185,13 @@ def test_group_resource_map_into_jobscripts(null_config):
178
185
  assert jobscripts_i == i["expected"]
179
186
 
180
187
 
181
- def test_timedelta_parse_format_round_trip(null_config):
188
+ def test_timedelta_parse_format_round_trip(null_config) -> None:
182
189
  td = timedelta(days=2, hours=25, minutes=92, seconds=77)
183
190
  td_str = timedelta_format(td)
184
191
  assert td_str == timedelta_format(timedelta_parse(td_str))
185
192
 
186
193
 
187
- def test_raise_missing_env_executable(new_null_config, tmp_path):
194
+ def test_raise_missing_env_executable(new_null_config, tmp_path) -> None:
188
195
  exec_name = (
189
196
  "my_executable" # null_env (the default) has no executable "my_executable"
190
197
  )
@@ -202,7 +209,7 @@ def test_raise_missing_env_executable(new_null_config, tmp_path):
202
209
  wk.add_submission()
203
210
 
204
211
 
205
- def test_raise_missing_matching_env_executable(new_null_config, tmp_path):
212
+ def test_raise_missing_matching_env_executable(new_null_config, tmp_path) -> None:
206
213
  """The executable label exists, but no a matching instance."""
207
214
  env_name = "my_hpcflow_env"
208
215
  exec_label = "my_exec_name"
@@ -240,8 +247,10 @@ def test_raise_missing_matching_env_executable(new_null_config, tmp_path):
240
247
  with pytest.raises(MissingEnvironmentExecutableInstanceError):
241
248
  wk.add_submission()
242
249
 
250
+ hf.reload_template_components() # remove extra envs
243
251
 
244
- def test_no_raise_matching_env_executable(new_null_config, tmp_path):
252
+
253
+ def test_no_raise_matching_env_executable(new_null_config, tmp_path) -> None:
245
254
  env_name = "my_hpcflow_env"
246
255
  exec_label = "my_exec_name"
247
256
  env = hf.Environment(
@@ -277,8 +286,10 @@ def test_no_raise_matching_env_executable(new_null_config, tmp_path):
277
286
  wk = hf.Workflow.from_template(wkt, path=tmp_path)
278
287
  wk.add_submission()
279
288
 
289
+ hf.reload_template_components() # remove extra envs
290
+
280
291
 
281
- def test_raise_missing_env(new_null_config, tmp_path):
292
+ def test_raise_missing_env(new_null_config, tmp_path) -> None:
282
293
  env_name = "my_hpcflow_env"
283
294
  ts = hf.TaskSchema(
284
295
  objective="test_sub",
@@ -294,7 +305,7 @@ def test_raise_missing_env(new_null_config, tmp_path):
294
305
  wk.add_submission()
295
306
 
296
307
 
297
- def test_custom_env_and_executable(new_null_config, tmp_path):
308
+ def test_custom_env_and_executable(new_null_config, tmp_path) -> None:
298
309
  env_name = "my_hpcflow_env"
299
310
  exec_label = "my_exec_name"
300
311
  env = hf.Environment(
@@ -329,82 +340,10 @@ def test_custom_env_and_executable(new_null_config, tmp_path):
329
340
  wk = hf.Workflow.from_template(wkt, path=tmp_path)
330
341
  wk.add_submission()
331
342
 
332
-
333
- def test_abort_EARs_file_creation(null_config, tmp_path):
334
- wk_name = "temp"
335
- t1 = hf.Task(
336
- schema=hf.task_schemas.test_t1_conditional_OS,
337
- sequences=[hf.ValueSequence("inputs.p1", values=[1, 2, 3])],
338
- )
339
- wkt = hf.WorkflowTemplate(name=wk_name, tasks=[t1])
340
- wk = hf.Workflow.from_template(
341
- template=wkt,
342
- path=tmp_path,
343
- )
344
- sub = wk.add_submission()
345
- wk.submissions_path.mkdir(exist_ok=True, parents=True)
346
- sub.path.mkdir(exist_ok=True)
347
- sub._write_abort_EARs_file()
348
- with sub.abort_EARs_file_path.open("rt") as fp:
349
- lines = fp.read()
350
-
351
- assert lines == "0\n0\n0\n"
352
-
353
-
354
- @pytest.mark.parametrize("run_id", [0, 1, 2])
355
- def test_abort_EARs_file_update(null_config, tmp_path, run_id):
356
- wk_name = "temp"
357
- t1 = hf.Task(
358
- schema=hf.task_schemas.test_t1_conditional_OS,
359
- sequences=[hf.ValueSequence("inputs.p1", values=[1, 2, 3])],
360
- )
361
- wkt = hf.WorkflowTemplate(name=wk_name, tasks=[t1])
362
- wk = hf.Workflow.from_template(
363
- template=wkt,
364
- path=tmp_path,
365
- )
366
- sub = wk.add_submission()
367
- wk.submissions_path.mkdir(exist_ok=True, parents=True)
368
- sub.path.mkdir(exist_ok=True)
369
- sub._write_abort_EARs_file()
370
-
371
- sub._set_run_abort(run_ID=run_id)
372
-
373
- with sub.abort_EARs_file_path.open("rt") as fp:
374
- lines = fp.read()
375
-
376
- lines_exp = ["0", "0", "0"]
377
- lines_exp[run_id] = "1"
378
- assert lines == "\n".join(lines_exp) + "\n"
379
-
380
-
381
- def test_abort_EARs_file_update_with_existing_abort(null_config, tmp_path):
382
- wk_name = "temp"
383
- t1 = hf.Task(
384
- schema=hf.task_schemas.test_t1_conditional_OS,
385
- sequences=[hf.ValueSequence("inputs.p1", values=[1, 2, 3])],
386
- )
387
- wkt = hf.WorkflowTemplate(name=wk_name, tasks=[t1])
388
- wk = hf.Workflow.from_template(
389
- template=wkt,
390
- path=tmp_path,
391
- )
392
- sub = wk.add_submission()
393
- wk.submissions_path.mkdir(exist_ok=True, parents=True)
394
- sub.path.mkdir(exist_ok=True)
395
- sub._write_abort_EARs_file()
396
-
397
- sub._set_run_abort(run_ID=1)
398
- sub._set_run_abort(run_ID=2)
399
-
400
- with sub.abort_EARs_file_path.open("rt") as fp:
401
- lines = fp.read()
402
-
403
- lines_exp = ["0", "1", "1"]
404
- assert lines == "\n".join(lines_exp) + "\n"
343
+ hf.reload_template_components() # remove extra envs
405
344
 
406
345
 
407
- def test_unique_schedulers_one_direct(new_null_config, tmp_path):
346
+ def test_unique_schedulers_one_direct(new_null_config, tmp_path) -> None:
408
347
  t1 = hf.Task(
409
348
  schema=hf.task_schemas.test_t1_conditional_OS,
410
349
  inputs={"p1": 1},
@@ -419,12 +358,15 @@ def test_unique_schedulers_one_direct(new_null_config, tmp_path):
419
358
  path=tmp_path,
420
359
  )
421
360
  sub = wk.add_submission()
361
+ assert sub is not None
422
362
  scheds = sub.get_unique_schedulers()
423
363
 
424
364
  assert len(scheds) == 1
425
365
 
426
366
 
427
- def test_unique_schedulers_one_direct_distinct_resources(new_null_config, tmp_path):
367
+ def test_unique_schedulers_one_direct_distinct_resources(
368
+ new_null_config, tmp_path
369
+ ) -> None:
428
370
  t1 = hf.Task(
429
371
  schema=hf.task_schemas.test_t1_conditional_OS,
430
372
  inputs={"p1": 1},
@@ -441,13 +383,14 @@ def test_unique_schedulers_one_direct_distinct_resources(new_null_config, tmp_pa
441
383
  path=tmp_path,
442
384
  )
443
385
  sub = wk.add_submission()
386
+ assert sub is not None
444
387
  scheds = sub.get_unique_schedulers()
445
388
 
446
389
  assert len(scheds) == 1
447
390
 
448
391
 
449
392
  @pytest.mark.slurm
450
- def test_unique_schedulers_one_SLURM(new_null_config, tmp_path):
393
+ def test_unique_schedulers_one_SLURM(new_null_config, tmp_path) -> None:
451
394
  hf.config.add_scheduler("slurm")
452
395
  t1 = hf.Task(
453
396
  schema=hf.task_schemas.test_t1_conditional_OS,
@@ -465,13 +408,16 @@ def test_unique_schedulers_one_SLURM(new_null_config, tmp_path):
465
408
  path=tmp_path,
466
409
  )
467
410
  sub = wk.add_submission()
411
+ assert sub is not None
468
412
  scheds = sub.get_unique_schedulers()
469
413
 
470
414
  assert len(scheds) == 1
471
415
 
472
416
 
473
417
  @pytest.mark.slurm
474
- def test_unique_schedulers_one_SLURM_distinct_resources(new_null_config, tmp_path):
418
+ def test_unique_schedulers_one_SLURM_distinct_resources(
419
+ new_null_config, tmp_path
420
+ ) -> None:
475
421
  hf.config.add_scheduler("slurm")
476
422
  t1 = hf.Task(
477
423
  schema=hf.task_schemas.test_t1_conditional_OS,
@@ -489,13 +435,14 @@ def test_unique_schedulers_one_SLURM_distinct_resources(new_null_config, tmp_pat
489
435
  path=tmp_path,
490
436
  )
491
437
  sub = wk.add_submission()
438
+ assert sub is not None
492
439
  scheds = sub.get_unique_schedulers()
493
440
 
494
441
  assert len(scheds) == 1
495
442
 
496
443
 
497
444
  @pytest.mark.slurm
498
- def test_unique_schedulers_two_direct_and_SLURM(new_null_config, tmp_path):
445
+ def test_unique_schedulers_two_direct_and_SLURM(new_null_config, tmp_path) -> None:
499
446
  hf.config.add_scheduler("slurm")
500
447
  t1 = hf.Task(
501
448
  schema=hf.task_schemas.test_t1_conditional_OS,
@@ -513,12 +460,13 @@ def test_unique_schedulers_two_direct_and_SLURM(new_null_config, tmp_path):
513
460
  path=tmp_path,
514
461
  )
515
462
  sub = wk.add_submission()
463
+ assert sub is not None
516
464
  scheds = sub.get_unique_schedulers()
517
465
 
518
466
  assert len(scheds) == 2
519
467
 
520
468
 
521
- def test_scheduler_config_defaults(new_null_config, tmp_path):
469
+ def test_scheduler_config_defaults(new_null_config, tmp_path) -> None:
522
470
  """Check default options defined in the config are merged into jobscript resources."""
523
471
  hf.config.set("schedulers.direct.defaults.options", {"a": "c"})
524
472
 
@@ -540,5 +488,6 @@ def test_scheduler_config_defaults(new_null_config, tmp_path):
540
488
  path=tmp_path,
541
489
  )
542
490
  sub = wk.add_submission()
491
+ assert sub is not None
543
492
  assert sub.jobscripts[0].resources.scheduler_args == {"options": {"a": "c"}}
544
493
  assert sub.jobscripts[1].resources.scheduler_args == {"options": {"a": "b"}}