hpcflow-new2 0.2.0a107__tar.gz → 0.2.0a109__tar.gz

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 (134) hide show
  1. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/PKG-INFO +1 -1
  2. hpcflow_new2-0.2.0a109/hpcflow/_version.py +1 -0
  3. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/app.py +12 -1
  4. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/cli.py +15 -3
  5. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/cli_common.py +6 -0
  6. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/config/cli.py +26 -1
  7. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/config/config.py +15 -2
  8. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/actions.py +27 -15
  9. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/command_files.py +6 -12
  10. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/task.py +11 -0
  11. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/task_schema.py +21 -0
  12. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/workflow.py +14 -1
  13. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/cli.py +7 -1
  14. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_action.py +37 -0
  15. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_task.py +7 -0
  16. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/pyproject.toml +2 -2
  17. hpcflow_new2-0.2.0a107/hpcflow/_version.py +0 -1
  18. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/README.md +0 -0
  19. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/__init__.py +0 -0
  20. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/__pyinstaller/__init__.py +0 -0
  21. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/__pyinstaller/hook-hpcflow.py +0 -0
  22. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/app.py +0 -0
  23. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/cli.py +0 -0
  24. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/examples.ipynb +0 -0
  25. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/__init__.py +0 -0
  26. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/config/__init__.py +0 -0
  27. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/config/callbacks.py +0 -0
  28. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/config/config_file.py +0 -0
  29. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/config/errors.py +0 -0
  30. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/__init__.py +0 -0
  31. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/commands.py +0 -0
  32. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/element.py +0 -0
  33. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/environment.py +0 -0
  34. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/errors.py +0 -0
  35. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/json_like.py +0 -0
  36. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/loop.py +0 -0
  37. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/object_list.py +0 -0
  38. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/parallel.py +0 -0
  39. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/parameters.py +0 -0
  40. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/rule.py +0 -0
  41. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/test_utils.py +0 -0
  42. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/utils.py +0 -0
  43. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/validation.py +0 -0
  44. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/core/zarr_io.py +0 -0
  45. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/__init__.py +0 -0
  46. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/config_file_schema.yaml +0 -0
  47. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/config_schema.yaml +0 -0
  48. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/environments_spec_schema.yaml +0 -0
  49. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/files_spec_schema.yaml +0 -0
  50. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/parameters_spec_schema.yaml +0 -0
  51. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/task_schema_spec_schema.yaml +0 -0
  52. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/template_components/__init__.py +0 -0
  53. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/template_components/command_files.yaml +0 -0
  54. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/template_components/environments.yaml +0 -0
  55. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/template_components/parameters.yaml +0 -0
  56. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/template_components/task_schemas.yaml +0 -0
  57. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/data/workflow_spec_schema.yaml +0 -0
  58. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/__init__.py +0 -0
  59. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/data/__init__.py +0 -0
  60. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/data/workflow_1.json +0 -0
  61. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/data/workflow_1.yaml +0 -0
  62. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/data/workflow_1_slurm.yaml +0 -0
  63. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/data/workflow_1_wsl.yaml +0 -0
  64. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/data/workflow_test_run_abort.yaml +0 -0
  65. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/scripts/__init__.py +0 -0
  66. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/scripts/demo_task_1_generate_t1_infile_1.py +0 -0
  67. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/scripts/demo_task_1_generate_t1_infile_2.py +0 -0
  68. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/scripts/demo_task_1_parse_p3.py +0 -0
  69. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/scripts/generate_t1_file_01.py +0 -0
  70. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/scripts/parse_t1_file_01.py +0 -0
  71. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/scripts/test_main_script.py +0 -0
  72. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/workflows/__init__.py +0 -0
  73. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/demo/workflows/workflow_1.yaml +0 -0
  74. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/helper/__init__.py +0 -0
  75. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/helper/cli.py +0 -0
  76. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/helper/helper.py +0 -0
  77. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/helper/watcher.py +0 -0
  78. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/log.py +0 -0
  79. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/persistence/__init__.py +0 -0
  80. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/persistence/base.py +0 -0
  81. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/persistence/json.py +0 -0
  82. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/persistence/pending.py +0 -0
  83. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/persistence/store_resource.py +0 -0
  84. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/persistence/utils.py +0 -0
  85. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/persistence/zarr.py +0 -0
  86. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/runtime.py +0 -0
  87. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/scripting/__init__.py +0 -0
  88. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/__init__.py +0 -0
  89. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/jobscript.py +0 -0
  90. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/jobscript_info.py +0 -0
  91. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/schedulers/__init__.py +0 -0
  92. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/schedulers/direct.py +0 -0
  93. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/schedulers/sge.py +0 -0
  94. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/schedulers/slurm.py +0 -0
  95. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/schedulers/utils.py +0 -0
  96. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/shells/__init__.py +0 -0
  97. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/shells/base.py +0 -0
  98. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/shells/bash.py +0 -0
  99. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/shells/os_version.py +0 -0
  100. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/shells/powershell.py +0 -0
  101. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/submission/submission.py +0 -0
  102. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/sdk/typing.py +0 -0
  103. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/conftest.py +0 -0
  104. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/schedulers/direct_linux/test_direct_linux_submission.py +0 -0
  105. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/schedulers/slurm/test_slurm_submission.py +0 -0
  106. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/shells/wsl/test_wsl_submission.py +0 -0
  107. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_action_rule.py +0 -0
  108. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_app.py +0 -0
  109. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_cli.py +0 -0
  110. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_command.py +0 -0
  111. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_config.py +0 -0
  112. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_config_file.py +0 -0
  113. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_element.py +0 -0
  114. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_element_iteration.py +0 -0
  115. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_element_set.py +0 -0
  116. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_input_source.py +0 -0
  117. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_input_value.py +0 -0
  118. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_json_like.py +0 -0
  119. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_loop.py +0 -0
  120. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_object_list.py +0 -0
  121. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_parameter.py +0 -0
  122. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_persistence.py +0 -0
  123. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_resources.py +0 -0
  124. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_runtime.py +0 -0
  125. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_schema_input.py +0 -0
  126. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_shell.py +0 -0
  127. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_submission.py +0 -0
  128. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_task_schema.py +0 -0
  129. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_utils.py +0 -0
  130. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_value_sequence.py +0 -0
  131. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_workflow.py +0 -0
  132. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/unit/test_workflow_template.py +0 -0
  133. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/tests/workflows/test_workflows.py +0 -0
  134. {hpcflow_new2-0.2.0a107 → hpcflow_new2-0.2.0a109}/hpcflow/viz_demo.ipynb +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hpcflow-new2
3
- Version: 0.2.0a107
3
+ Version: 0.2.0a109
4
4
  Summary: Computational workflow management
5
5
  License: MIT
6
6
  Author: aplowman
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0a109"
@@ -1108,6 +1108,7 @@ class BaseApp(metaclass=Singleton):
1108
1108
  JS_parallelism: Optional[bool] = None,
1109
1109
  wait: Optional[bool] = False,
1110
1110
  add_to_known: Optional[bool] = True,
1111
+ return_idx: Optional[bool] = False,
1111
1112
  ) -> Dict[int, int]:
1112
1113
  """Generate and submit a new {app_name} workflow from a file or string containing a
1113
1114
  workflow template parametrisation.
@@ -1150,6 +1151,9 @@ class BaseApp(metaclass=Singleton):
1150
1151
  add_to_known
1151
1152
  If True, add the new submission to the known-submissions file, which is
1152
1153
  used by the `show` command to monitor current and recent submissions.
1154
+ return_idx
1155
+ If True, return a dict representing the jobscript indices submitted for each
1156
+ submission.
1153
1157
  """
1154
1158
 
1155
1159
  self.API_logger.info("make_and_submit_workflow called")
@@ -1169,6 +1173,7 @@ class BaseApp(metaclass=Singleton):
1169
1173
  JS_parallelism=JS_parallelism,
1170
1174
  wait=wait,
1171
1175
  add_to_known=add_to_known,
1176
+ return_idx=return_idx,
1172
1177
  )
1173
1178
 
1174
1179
  def _make_demo_workflow(
@@ -1240,6 +1245,7 @@ class BaseApp(metaclass=Singleton):
1240
1245
  JS_parallelism: Optional[bool] = None,
1241
1246
  wait: Optional[bool] = False,
1242
1247
  add_to_known: Optional[bool] = True,
1248
+ return_idx: Optional[bool] = False,
1243
1249
  ) -> Dict[int, int]:
1244
1250
  """Generate and submit a new {app_name} workflow from a file or string containing a
1245
1251
  workflow template parametrisation.
@@ -1279,6 +1285,9 @@ class BaseApp(metaclass=Singleton):
1279
1285
  add_to_known
1280
1286
  If True, add the new submission to the known-submissions file, which is
1281
1287
  used by the `show` command to monitor current and recent submissions.
1288
+ return_idx
1289
+ If True, return a dict representing the jobscript indices submitted for each
1290
+ submission.
1282
1291
  """
1283
1292
 
1284
1293
  self.API_logger.info("make_and_submit_demo_workflow called")
@@ -1297,6 +1306,7 @@ class BaseApp(metaclass=Singleton):
1297
1306
  JS_parallelism=JS_parallelism,
1298
1307
  wait=wait,
1299
1308
  add_to_known=add_to_known,
1309
+ return_idx=return_idx,
1300
1310
  )
1301
1311
 
1302
1312
  def _submit_workflow(
@@ -1304,6 +1314,7 @@ class BaseApp(metaclass=Singleton):
1304
1314
  workflow_path: PathLike,
1305
1315
  JS_parallelism: Optional[bool] = None,
1306
1316
  wait: Optional[bool] = False,
1317
+ return_idx: Optional[bool] = False,
1307
1318
  ) -> Dict[int, int]:
1308
1319
  """Submit an existing {app_name} workflow.
1309
1320
 
@@ -1319,7 +1330,7 @@ class BaseApp(metaclass=Singleton):
1319
1330
 
1320
1331
  self.API_logger.info("submit_workflow called")
1321
1332
  wk = self.Workflow(workflow_path)
1322
- return wk.submit(JS_parallelism=JS_parallelism, wait=wait)
1333
+ return wk.submit(JS_parallelism=JS_parallelism, wait=wait, return_idx=return_idx)
1323
1334
 
1324
1335
  def _run_hpcflow_tests(self, *args):
1325
1336
  """Run hpcflow test suite. This function is only available from derived apps."""
@@ -22,6 +22,7 @@ from hpcflow.sdk.cli_common import (
22
22
  js_parallelism_option,
23
23
  wait_option,
24
24
  add_to_known_opt,
25
+ print_idx_opt,
25
26
  )
26
27
  from hpcflow.sdk.helper.cli import get_helper_CLI
27
28
  from hpcflow.sdk.submission.shells import ALL_SHELLS
@@ -104,6 +105,7 @@ def _make_API_CLI(app):
104
105
  @js_parallelism_option
105
106
  @wait_option
106
107
  @add_to_known_opt
108
+ @print_idx_opt
107
109
  def make_and_submit_workflow(
108
110
  template_file_or_str,
109
111
  string,
@@ -117,6 +119,7 @@ def _make_API_CLI(app):
117
119
  js_parallelism=None,
118
120
  wait=False,
119
121
  add_to_known=True,
122
+ print_idx=False,
120
123
  ):
121
124
  """Generate and submit a new {app_name} workflow.
122
125
 
@@ -124,7 +127,7 @@ def _make_API_CLI(app):
124
127
  format, or a YAML/JSON string.
125
128
 
126
129
  """
127
- app.make_and_submit_workflow(
130
+ out = app.make_and_submit_workflow(
128
131
  template_file_or_str=template_file_or_str,
129
132
  is_string=string,
130
133
  template_format=format,
@@ -137,7 +140,10 @@ def _make_API_CLI(app):
137
140
  JS_parallelism=js_parallelism,
138
141
  wait=wait,
139
142
  add_to_known=add_to_known,
143
+ return_idx=print_idx,
140
144
  )
145
+ if print_idx:
146
+ click.echo(out)
141
147
 
142
148
  @click.command(context_settings={"ignore_unknown_options": True})
143
149
  @click.argument("py_test_args", nargs=-1, type=click.UNPROCESSED)
@@ -288,14 +294,20 @@ def _make_workflow_CLI(app):
288
294
  @js_parallelism_option
289
295
  @wait_option
290
296
  @add_to_known_opt
297
+ @print_idx_opt
291
298
  @click.pass_context
292
- def submit_workflow(ctx, js_parallelism=None, wait=False, add_to_known=True):
299
+ def submit_workflow(
300
+ ctx, js_parallelism=None, wait=False, add_to_known=True, print_idx=False
301
+ ):
293
302
  """Submit the workflow."""
294
- ctx.obj["workflow"].submit(
303
+ out = ctx.obj["workflow"].submit(
295
304
  JS_parallelism=js_parallelism,
296
305
  wait=wait,
297
306
  add_to_known=add_to_known,
307
+ return_idx=print_idx,
298
308
  )
309
+ if print_idx:
310
+ click.echo(out)
299
311
 
300
312
  @workflow.command(name="wait")
301
313
  @click.option(
@@ -79,3 +79,9 @@ add_to_known_opt = click.option(
79
79
  default=True,
80
80
  help="If True, add this submission to the known-submissions file.",
81
81
  )
82
+ print_idx_opt = click.option(
83
+ "--print-idx",
84
+ help="If True, print the submitted jobscript indices for each submission index.",
85
+ is_flag=True,
86
+ default=False,
87
+ )
@@ -289,7 +289,32 @@ def get_config_CLI(app):
289
289
  defaults = json.loads(defaults)
290
290
  else:
291
291
  defaults = {}
292
- ctx.obj["config"].add_scheduler(name, defaults=defaults)
292
+ ctx.obj["config"].add_scheduler(name, **defaults)
293
+ ctx.obj["config"].save()
294
+
295
+ @config.command()
296
+ @click.argument("name")
297
+ @click.option("--defaults")
298
+ @click.pass_context
299
+ @CLI_exception_wrapper_gen(ConfigError)
300
+ def add_shell(ctx, name, defaults):
301
+ if defaults:
302
+ defaults = json.loads(defaults)
303
+ else:
304
+ defaults = {}
305
+ ctx.obj["config"].add_shell(name, **defaults)
306
+ ctx.obj["config"].save()
307
+
308
+ @config.command()
309
+ @click.option("--defaults")
310
+ @click.pass_context
311
+ @CLI_exception_wrapper_gen(ConfigError)
312
+ def add_shell_wsl(ctx, defaults):
313
+ if defaults:
314
+ defaults = json.loads(defaults)
315
+ else:
316
+ defaults = {}
317
+ ctx.obj["config"].add_shell_WSL(**defaults)
293
318
  ctx.obj["config"].save()
294
319
 
295
320
  @config.command()
@@ -737,11 +737,24 @@ class Config:
737
737
  self._logger.info(f"Resetting config file to defaults.")
738
738
  self._app.reset_config()
739
739
 
740
- def add_scheduler(self, scheduler, **kwargs):
740
+ def add_scheduler(self, scheduler, **defaults):
741
741
  if scheduler in self.get("schedulers"):
742
742
  print(f"Scheduler {scheduler!r} already exists.")
743
743
  return
744
- self.update(f"schedulers.{scheduler}", kwargs)
744
+ self.update(f"schedulers.{scheduler}.defaults", defaults)
745
+
746
+ def add_shell(self, shell, **defaults):
747
+ if shell in self.get("shells"):
748
+ return
749
+ if shell.lower() == "wsl":
750
+ # check direct_posix scheduler is added:
751
+ self.add_scheduler("direct_posix")
752
+ self.update(f"shells.{shell}.defaults", defaults)
753
+
754
+ def add_shell_WSL(self, **defaults):
755
+ if "WSL_executable" not in defaults:
756
+ defaults["WSL_executable"] = "wsl.exe"
757
+ self.add_shell("wsl", **defaults)
745
758
 
746
759
  def import_from_file(self, file_path, rename=True, make_new=False):
747
760
  """Import config items from a (remote or local) YAML file. Existing config items
@@ -513,16 +513,14 @@ class ElementActionRun:
513
513
  outputs[out_typ] = self.get(f"outputs.{out_typ}")
514
514
  return outputs
515
515
 
516
- def compose_source(self) -> str:
516
+ def compose_source(self, snip_path: Path) -> str:
517
517
  """Generate the file contents of this source."""
518
518
 
519
- script_name = self.action.get_script_name(self.action.script)
520
- script_key = self.action.get_app_data_script_path(self.action.script)
521
- script_path = self.app.scripts.get(script_key)
522
- with script_path.open("rt") as fp:
519
+ script_name = snip_path.name
520
+ with snip_path.open("rt") as fp:
523
521
  script_str = fp.read()
524
522
 
525
- is_python = script_path.suffix == ".py"
523
+ is_python = snip_path.suffix == ".py"
526
524
  if is_python:
527
525
  py_imports = dedent(
528
526
  """\
@@ -639,10 +637,12 @@ class ElementActionRun:
639
637
 
640
638
  # write the script if it is specified as a app data script, otherwise we assume
641
639
  # the script already exists in the working directory:
642
- if self.action.script and self.action.is_app_data_script(self.action.script):
643
- script_name = self.action.get_script_name(self.action.script)
640
+ snip_path = self.action.get_snippet_script_path(self.action.script)
641
+ if snip_path:
642
+ script_name = snip_path.name
643
+ source_str = self.compose_source(snip_path)
644
644
  with Path(script_name).open("wt", newline="\n") as fp:
645
- fp.write(self.compose_source())
645
+ fp.write(source_str)
646
646
 
647
647
  def _param_dump_JSON(self, dump_path: Path):
648
648
  with dump_path.open("wt") as fp:
@@ -1358,15 +1358,16 @@ class Action(JSONLike):
1358
1358
  )
1359
1359
 
1360
1360
  @staticmethod
1361
- def is_app_data_script(script: str) -> bool:
1361
+ def is_snippet_script(script: str) -> bool:
1362
+ """Returns True if the provided script string represents a script snippets that is
1363
+ to be modified before execution (e.g. to receive and provide parameter data)."""
1362
1364
  return script.startswith("<<script:")
1363
1365
 
1364
1366
  @classmethod
1365
1367
  def get_script_name(cls, script: str) -> str:
1366
1368
  """Return the script name."""
1367
- if cls.is_app_data_script(script):
1368
- # an app data script:
1369
- pattern = r"\<\<script:(?:.*\/)*(.*:?)\>\>"
1369
+ if cls.is_snippet_script(script):
1370
+ pattern = r"\<\<script:(?:.*(?:\/|\\))*(.*)\>\>"
1370
1371
  match_obj = re.match(pattern, script)
1371
1372
  return match_obj.group(1)
1372
1373
  else:
@@ -1374,8 +1375,8 @@ class Action(JSONLike):
1374
1375
  return script
1375
1376
 
1376
1377
  @classmethod
1377
- def get_app_data_script_path(cls, script) -> str:
1378
- if not cls.is_app_data_script(script):
1378
+ def get_snippet_script_str(cls, script) -> str:
1379
+ if not cls.is_snippet_script(script):
1379
1380
  raise ValueError(
1380
1381
  f"Must be an app-data script name (e.g. "
1381
1382
  f"<<script:path/to/app/data/script.py>>), but received {script}"
@@ -1384,6 +1385,17 @@ class Action(JSONLike):
1384
1385
  match_obj = re.match(pattern, script)
1385
1386
  return match_obj.group(1)
1386
1387
 
1388
+ @classmethod
1389
+ def get_snippet_script_path(cls, script_path) -> Path:
1390
+ if not cls.is_snippet_script(script_path):
1391
+ return False
1392
+
1393
+ path = cls.get_snippet_script_str(script_path)
1394
+ if path in cls.app.scripts:
1395
+ path = cls.app.scripts.get(path)
1396
+
1397
+ return Path(path)
1398
+
1387
1399
  @staticmethod
1388
1400
  def get_param_dump_file_stem(js_idx: int, js_act_idx: int):
1389
1401
  return f"js_{js_idx}_act_{js_act_idx}_inputs"
@@ -134,12 +134,9 @@ class InputFileGenerator(JSONLike):
134
134
  def compose_source(self, action) -> str:
135
135
  """Generate the file contents of this input file generator source."""
136
136
 
137
- script_name = self.script
138
- script_key = action.get_app_data_script_path(self.script)
139
- script_path = self.app.scripts.get(script_key)
140
- script_main_func = Path(script_name).stem
141
-
142
- with script_path.open("rt") as fp:
137
+ snip_path = action.get_snippet_script_path(self.script)
138
+ script_main_func = snip_path.stem
139
+ with snip_path.open("rt") as fp:
143
140
  script_str = fp.read()
144
141
 
145
142
  main_block = dedent(
@@ -261,12 +258,9 @@ class OutputFileParser(JSONLike):
261
258
  def compose_source(self, action) -> str:
262
259
  """Generate the file contents of this output file parser source."""
263
260
 
264
- script_name = self.script
265
- script_key = action.get_app_data_script_path(self.script)
266
- script_path = self.app.scripts.get(script_key)
267
- script_main_func = Path(script_name).stem
268
-
269
- with script_path.open("rt") as fp:
261
+ snip_path = action.get_snippet_script_path(self.script)
262
+ script_main_func = snip_path.stem
263
+ with snip_path.open("rt") as fp:
270
264
  script_str = fp.read()
271
265
 
272
266
  main_block = dedent(
@@ -222,6 +222,17 @@ class ElementSet(JSONLike):
222
222
  return tuple(self._element_local_idx_range)
223
223
 
224
224
  def _validate(self):
225
+
226
+ # support inputs passed as a dict:
227
+ _inputs = []
228
+ try:
229
+ for k, v in self.inputs.items():
230
+ _inputs.append(self.app.InputValue(parameter=k, value=v))
231
+ except AttributeError:
232
+ pass
233
+ else:
234
+ self.inputs = _inputs
235
+
225
236
  inp_paths = [i.normalised_inputs_path for i in self.inputs]
226
237
  dup_inp_paths = get_duplicate_items(inp_paths)
227
238
  if dup_inp_paths:
@@ -217,6 +217,27 @@ class TaskSchema(JSONLike):
217
217
  tab_cmds_i = Table(show_header=False, box=None)
218
218
  tab_cmds_i.add_column(justify="right")
219
219
  tab_cmds_i.add_column()
220
+ if act.rules:
221
+ seen_rules = [] # bug: some rules seem to be repeated
222
+ for act_rule_j in act.rules:
223
+ if act_rule_j.rule in seen_rules:
224
+ continue
225
+ else:
226
+ seen_rules.append(act_rule_j.rule)
227
+ r_path = ""
228
+ if act_rule_j.rule.check_missing:
229
+ r_cond = f"check missing: {act_rule_j.rule.check_missing}"
230
+ elif act_rule_j.rule.check_exists:
231
+ r_cond = f"check exists: {act_rule_j.rule.check_exists}"
232
+ elif act_rule_j.rule.condition:
233
+ r_path = f"{act_rule_j.rule.path}: "
234
+ r_cond = str(act_rule_j.rule.condition.to_json_like())
235
+ else:
236
+ continue
237
+ tab_cmds_i.add_row(
238
+ "[italic]rule:[/italic]",
239
+ escape(f"{r_path}{r_cond}"),
240
+ )
220
241
  tab_cmds_i.add_row(
221
242
  "[italic]scope:[/italic]",
222
243
  escape(act.get_precise_scope().to_string()),
@@ -127,6 +127,7 @@ class WorkflowTemplate(JSONLike):
127
127
  loops: Optional[List[app.Loop]] = field(default_factory=lambda: [])
128
128
  workflow: Optional[app.Workflow] = None
129
129
  resources: Optional[Dict[str, Dict]] = None
130
+ source_file: Optional[str] = field(default=None, compare=False)
130
131
 
131
132
  def __post_init__(self):
132
133
  self.resources = self.app.ResourceList.normalise(self.resources)
@@ -230,6 +231,7 @@ class WorkflowTemplate(JSONLike):
230
231
  cls.app.logger.debug("parsing workflow template from a YAML file")
231
232
  data = read_YAML_file(path)
232
233
  cls._check_name(data, path)
234
+ data["source_file"] = str(path)
233
235
  return cls._from_data(data)
234
236
 
235
237
  @classmethod
@@ -257,6 +259,7 @@ class WorkflowTemplate(JSONLike):
257
259
  cls.app.logger.debug("parsing workflow template from a JSON file")
258
260
  data = read_JSON_file(path)
259
261
  cls._check_name(data, path)
262
+ data["source_file"] = str(path)
260
263
  return cls._from_data(data)
261
264
 
262
265
  @classmethod
@@ -1359,6 +1362,11 @@ class Workflow:
1359
1362
  # actually make template inputs/resources persistent, now the workflow exists:
1360
1363
  wk_dummy.make_persistent(wk)
1361
1364
 
1365
+ if template.source_file:
1366
+ wk.artifacts_path.mkdir(exist_ok=False)
1367
+ src = Path(template.source_file)
1368
+ wk.artifacts_path.joinpath(src.name).write_text(src.read_text())
1369
+
1362
1370
  return wk
1363
1371
 
1364
1372
  def to_zip(self, log=None) -> str:
@@ -1805,6 +1813,7 @@ class Workflow:
1805
1813
  print_stdout: Optional[bool] = False,
1806
1814
  wait: Optional[bool] = False,
1807
1815
  add_to_known: Optional[bool] = True,
1816
+ return_idx: Optional[bool] = False,
1808
1817
  ) -> Dict[int, int]:
1809
1818
  """Submit the workflow for execution.
1810
1819
 
@@ -1824,6 +1833,9 @@ class Workflow:
1824
1833
  add_to_known
1825
1834
  If True, add the submitted submissions to the known-submissions file, which is
1826
1835
  used by the `show` command to monitor current and recent submissions.
1836
+ return_idx
1837
+ If True, return a dict representing the jobscript indices submitted for each
1838
+ submission.
1827
1839
  """
1828
1840
 
1829
1841
  console = rich.console.Console()
@@ -1858,7 +1870,8 @@ class Workflow:
1858
1870
  if wait:
1859
1871
  self.wait(submitted_js)
1860
1872
 
1861
- return submitted_js
1873
+ if return_idx:
1874
+ return submitted_js
1862
1875
 
1863
1876
  def wait(self, sub_js: Optional[Dict] = None):
1864
1877
  """Wait for the completion of specified/all submitted jobscripts."""
@@ -14,6 +14,7 @@ from hpcflow.sdk.cli_common import (
14
14
  js_parallelism_option,
15
15
  wait_option,
16
16
  add_to_known_opt,
17
+ print_idx_opt,
17
18
  )
18
19
 
19
20
 
@@ -130,6 +131,7 @@ def get_demo_workflow_CLI(app):
130
131
  @js_parallelism_option
131
132
  @wait_option
132
133
  @add_to_known_opt
134
+ @print_idx_opt
133
135
  def make_and_submit_demo_workflow(
134
136
  workflow_name,
135
137
  format,
@@ -142,8 +144,9 @@ def get_demo_workflow_CLI(app):
142
144
  js_parallelism=None,
143
145
  wait=False,
144
146
  add_to_known=True,
147
+ print_idx=False,
145
148
  ):
146
- app.make_and_submit_demo_workflow(
149
+ out = app.make_and_submit_demo_workflow(
147
150
  workflow_name=workflow_name,
148
151
  template_format=format,
149
152
  path=path,
@@ -155,7 +158,10 @@ def get_demo_workflow_CLI(app):
155
158
  JS_parallelism=js_parallelism,
156
159
  wait=wait,
157
160
  add_to_known=add_to_known,
161
+ return_idx=print_idx,
158
162
  )
163
+ if print_idx:
164
+ click.echo(out)
159
165
 
160
166
  @demo_workflow.command("copy")
161
167
  @click.argument("workflow_name")
@@ -1,3 +1,4 @@
1
+ from pathlib import Path
1
2
  import pytest
2
3
 
3
4
  from hpcflow.app import app as hf
@@ -215,3 +216,39 @@ def test_get_command_input_types_label_sub_parameters_false_no_sub_param():
215
216
  def test_get_command_input_types_label_sub_parameters_false_with_sub_parameter():
216
217
  act = hf.Action(commands=[hf.Command("Write-Output (<<parameter:p1[one].a>> + 100)")])
217
218
  assert act.get_command_input_types(sub_parameters=False) == ("p1[one]",)
219
+
220
+
221
+ def test_get_script_name(null_config):
222
+ expected = {
223
+ "<<script:/software/hello.py>>": "hello.py",
224
+ "<<script:software/hello.py>>": "hello.py",
225
+ r"<<script:C:\long\path\to\script.py>>": "script.py",
226
+ "/path/to/script.py": "/path/to/script.py",
227
+ }
228
+ for k, v in expected.items():
229
+ assert hf.Action.get_script_name(k) == v
230
+
231
+
232
+ def test_is_snippet_script(null_config):
233
+ expected = {
234
+ "<<script:/software/hello.py>>": True,
235
+ "<<script:software/hello.py>>": True,
236
+ r"<<script:C:\long\path\to\script.py>>": True,
237
+ "/path/to/script.py": False,
238
+ }
239
+ for k, v in expected.items():
240
+ assert hf.Action.is_snippet_script(k) == v
241
+
242
+
243
+ def test_get_snippet_script_path(null_config):
244
+ expected = {
245
+ "<<script:/software/hello.py>>": Path("/software/hello.py"),
246
+ "<<script:software/hello.py>>": Path("software/hello.py"),
247
+ r"<<script:C:\long\path\to\script.py>>": Path(r"C:\long\path\to\script.py"),
248
+ }
249
+ for k, v in expected.items():
250
+ assert hf.Action.get_snippet_script_path(k) == v
251
+
252
+
253
+ def test_get_snippet_script_path_False(null_config):
254
+ assert not hf.Action.get_snippet_script_path("/path/to/script.py")
@@ -2083,3 +2083,10 @@ def test_path_to_PV_classes_resources_path_ignored(path_to_PV_classes_workflow):
2083
2083
  assert path_to_PV_classes_workflow.tasks.t1._paths_to_PV_classes(
2084
2084
  paths_1
2085
2085
  ) == path_to_PV_classes_workflow.tasks.t1._paths_to_PV_classes(paths_2)
2086
+
2087
+
2088
+ def test_input_values_specified_by_dict(null_config):
2089
+ ts = hf.TaskSchema(objective="t1", inputs=[hf.SchemaInput("p1")])
2090
+ t1 = hf.Task(schema=ts, inputs=[hf.InputValue(parameter="p1", value=101)])
2091
+ t2 = hf.Task(schema=ts, inputs={"p1": 101})
2092
+ assert t1 == t2
@@ -1,7 +1,7 @@
1
1
 
2
2
  [tool.poetry]
3
3
  name = "hpcflow-new2"
4
- version = "0.2.0a107"
4
+ version = "0.2.0a109"
5
5
 
6
6
  description = "Computational workflow management"
7
7
  authors = ["aplowman <adam.plowman@manchester.ac.uk>"]
@@ -68,7 +68,7 @@ hook-dirs = "hpcflow.__pyinstaller:get_hook_dirs"
68
68
 
69
69
  [tool.commitizen]
70
70
  name = "cz_conventional_commits"
71
- version = "0.2.0a107"
71
+ version = "0.2.0a109"
72
72
  tag_format = "v$version"
73
73
  version_files = [
74
74
  "pyproject.toml:version",
@@ -1 +0,0 @@
1
- __version__ = "0.2.0a107"