hpcflow-new2 0.2.0a218__tar.gz → 0.2.0a219__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 (226) hide show
  1. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/PKG-INFO +1 -1
  2. hpcflow_new2-0.2.0a219/hpcflow/_version.py +1 -0
  3. hpcflow_new2-0.2.0a219/hpcflow/data/scripts/import_future_script.py +7 -0
  4. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/app.py +2 -1
  5. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/errors.py +6 -0
  6. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/parameters.py +21 -23
  7. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/utils.py +18 -3
  8. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/workflow.py +15 -5
  9. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/zarr.py +1 -1
  10. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/jobscript.py +15 -2
  11. hpcflow_new2-0.2.0a219/hpcflow/sdk/utils/strings.py +61 -0
  12. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/scripts/test_main_scripts.py +27 -0
  13. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_element_set.py +25 -0
  14. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_input_source.py +71 -0
  15. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_utils.py +40 -1
  16. hpcflow_new2-0.2.0a219/hpcflow/tests/unit/utils/test_strings.py +97 -0
  17. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/pyproject.toml +2 -2
  18. hpcflow_new2-0.2.0a218/hpcflow/_version.py +0 -1
  19. hpcflow_new2-0.2.0a218/hpcflow/sdk/utils/strings.py +0 -33
  20. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/LICENSE +0 -0
  21. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/README.md +0 -0
  22. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/__init__.py +0 -0
  23. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/__pyinstaller/__init__.py +0 -0
  24. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/__pyinstaller/hook-hpcflow.py +0 -0
  25. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/app.py +0 -0
  26. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/cli.py +0 -0
  27. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/demo_data_manifest/__init__.py +0 -0
  28. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/demo_data_manifest/demo_data_manifest.json +0 -0
  29. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/__init__.py +0 -0
  30. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/bad_script.py +0 -0
  31. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/demo_task_1_generate_t1_infile_1.py +0 -0
  32. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/demo_task_1_generate_t1_infile_2.py +0 -0
  33. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/demo_task_1_parse_p3.py +0 -0
  34. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/do_nothing.py +0 -0
  35. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +0 -0
  36. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +0 -0
  37. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +0 -0
  38. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +0 -0
  39. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +0 -0
  40. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +0 -0
  41. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +0 -0
  42. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/generate_t1_file_01.py +0 -0
  43. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/input_file_generator_basic.py +0 -0
  44. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/input_file_generator_basic_FAIL.py +0 -0
  45. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +0 -0
  46. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in.py +0 -0
  47. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_direct_out.py +0 -0
  48. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +0 -0
  49. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +0 -0
  50. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +0 -0
  51. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +0 -0
  52. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_direct_out_all_iters_test.py +0 -0
  53. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_direct_out_env_spec.py +0 -0
  54. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_direct_out_labels.py +0 -0
  55. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +0 -0
  56. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +0 -0
  57. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_direct_sub_param_in_direct_out.py +0 -0
  58. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +0 -0
  59. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +0 -0
  60. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_hdf5_in_obj_group.py +0 -0
  61. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +0 -0
  62. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_json_and_direct_in_json_out.py +0 -0
  63. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_json_in_json_and_direct_out.py +0 -0
  64. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_json_in_json_out.py +0 -0
  65. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_json_in_json_out_labels.py +0 -0
  66. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_json_in_obj.py +0 -0
  67. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_json_out_FAIL.py +0 -0
  68. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_json_out_obj.py +0 -0
  69. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_json_sub_param_in_json_out_labels.py +0 -0
  70. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_shell_env_vars.py +0 -0
  71. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/main_script_test_std_out_std_err.py +0 -0
  72. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/output_file_parser_basic.py +0 -0
  73. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/output_file_parser_basic_FAIL.py +0 -0
  74. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +0 -0
  75. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/parse_t1_file_01.py +0 -0
  76. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/scripts/script_exit_test.py +0 -0
  77. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/template_components/__init__.py +0 -0
  78. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/template_components/command_files.yaml +0 -0
  79. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/template_components/environments.yaml +0 -0
  80. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/template_components/parameters.yaml +0 -0
  81. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/template_components/task_schemas.yaml +0 -0
  82. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/workflows/__init__.py +0 -0
  83. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/data/workflows/workflow_1.yaml +0 -0
  84. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/examples.ipynb +0 -0
  85. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/__init__.py +0 -0
  86. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/cli.py +0 -0
  87. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/cli_common.py +0 -0
  88. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/config/__init__.py +0 -0
  89. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/config/callbacks.py +0 -0
  90. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/config/cli.py +0 -0
  91. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/config/config.py +0 -0
  92. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/config/config_file.py +0 -0
  93. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/config/errors.py +0 -0
  94. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/config/types.py +0 -0
  95. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/__init__.py +0 -0
  96. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/actions.py +0 -0
  97. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/app_aware.py +0 -0
  98. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/cache.py +0 -0
  99. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/command_files.py +0 -0
  100. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/commands.py +0 -0
  101. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/element.py +0 -0
  102. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/enums.py +0 -0
  103. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/environment.py +0 -0
  104. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/execute.py +0 -0
  105. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/json_like.py +0 -0
  106. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/loop.py +0 -0
  107. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/loop_cache.py +0 -0
  108. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/object_list.py +0 -0
  109. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/rule.py +0 -0
  110. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/run_dir_files.py +0 -0
  111. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/skip_reason.py +0 -0
  112. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/task.py +0 -0
  113. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/task_schema.py +0 -0
  114. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/test_utils.py +0 -0
  115. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/types.py +0 -0
  116. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/validation.py +0 -0
  117. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/core/zarr_io.py +0 -0
  118. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/data/__init__.py +0 -0
  119. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/data/config_file_schema.yaml +0 -0
  120. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/data/config_schema.yaml +0 -0
  121. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/data/environments_spec_schema.yaml +0 -0
  122. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/data/files_spec_schema.yaml +0 -0
  123. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/data/parameters_spec_schema.yaml +0 -0
  124. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/data/task_schema_spec_schema.yaml +0 -0
  125. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/data/workflow_spec_schema.yaml +0 -0
  126. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/demo/__init__.py +0 -0
  127. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/demo/cli.py +0 -0
  128. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/helper/__init__.py +0 -0
  129. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/helper/cli.py +0 -0
  130. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/helper/helper.py +0 -0
  131. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/helper/watcher.py +0 -0
  132. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/log.py +0 -0
  133. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/__init__.py +0 -0
  134. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/base.py +0 -0
  135. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/defaults.py +0 -0
  136. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/discovery.py +0 -0
  137. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/json.py +0 -0
  138. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/pending.py +0 -0
  139. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/store_resource.py +0 -0
  140. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/types.py +0 -0
  141. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/persistence/utils.py +0 -0
  142. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/runtime.py +0 -0
  143. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/__init__.py +0 -0
  144. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/enums.py +0 -0
  145. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/schedulers/__init__.py +0 -0
  146. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/schedulers/direct.py +0 -0
  147. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/schedulers/sge.py +0 -0
  148. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/schedulers/slurm.py +0 -0
  149. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/schedulers/utils.py +0 -0
  150. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/shells/__init__.py +0 -0
  151. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/shells/base.py +0 -0
  152. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/shells/bash.py +0 -0
  153. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/shells/os_version.py +0 -0
  154. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/shells/powershell.py +0 -0
  155. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/submission.py +0 -0
  156. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/submission/types.py +0 -0
  157. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/typing.py +0 -0
  158. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/utils/arrays.py +0 -0
  159. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/utils/deferred_file.py +0 -0
  160. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/utils/hashing.py +0 -0
  161. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/sdk/utils/patches.py +0 -0
  162. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/api/test_api.py +0 -0
  163. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/conftest.py +0 -0
  164. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/data/__init__.py +0 -0
  165. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/data/benchmark_N_elements.yaml +0 -0
  166. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/data/benchmark_script_runner.yaml +0 -0
  167. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/data/multi_path_sequences.yaml +0 -0
  168. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/data/workflow_1.json +0 -0
  169. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/data/workflow_1.yaml +0 -0
  170. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/data/workflow_1_slurm.yaml +0 -0
  171. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/data/workflow_1_wsl.yaml +0 -0
  172. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/data/workflow_test_run_abort.yaml +0 -0
  173. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/schedulers/direct_linux/test_direct_linux_submission.py +0 -0
  174. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/schedulers/sge/test_sge_submission.py +0 -0
  175. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/schedulers/slurm/test_slurm_submission.py +0 -0
  176. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/scripts/test_input_file_generators.py +0 -0
  177. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/scripts/test_non_snippet_script.py +0 -0
  178. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/scripts/test_ouput_file_parsers.py +0 -0
  179. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/shells/wsl/test_wsl_submission.py +0 -0
  180. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_action.py +0 -0
  181. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_action_rule.py +0 -0
  182. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_app.py +0 -0
  183. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_cache.py +0 -0
  184. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_cli.py +0 -0
  185. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_command.py +0 -0
  186. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_config.py +0 -0
  187. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_config_file.py +0 -0
  188. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_element.py +0 -0
  189. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_element_iteration.py +0 -0
  190. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_group.py +0 -0
  191. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_input_value.py +0 -0
  192. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_jobscript_unit.py +0 -0
  193. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_json_like.py +0 -0
  194. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_loop.py +0 -0
  195. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_meta_task.py +0 -0
  196. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_multi_path_sequences.py +0 -0
  197. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_object_list.py +0 -0
  198. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_parameter.py +0 -0
  199. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_persistence.py +0 -0
  200. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_resources.py +0 -0
  201. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_run.py +0 -0
  202. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_run_directories.py +0 -0
  203. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_runtime.py +0 -0
  204. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_schema_input.py +0 -0
  205. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_shell.py +0 -0
  206. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_slurm.py +0 -0
  207. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_submission.py +0 -0
  208. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_task.py +0 -0
  209. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_task_schema.py +0 -0
  210. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_value_sequence.py +0 -0
  211. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_workflow.py +0 -0
  212. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/test_workflow_template.py +0 -0
  213. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/utils/test_arrays.py +0 -0
  214. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/utils/test_deferred_file_writer.py +0 -0
  215. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/utils/test_hashing.py +0 -0
  216. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/utils/test_patches.py +0 -0
  217. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/unit/utils/test_redirect_std.py +0 -0
  218. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/workflows/__init__.py +0 -0
  219. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/workflows/test_directory_structure.py +0 -0
  220. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/workflows/test_jobscript.py +0 -0
  221. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/workflows/test_run_status.py +0 -0
  222. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/workflows/test_skip_downstream.py +0 -0
  223. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/workflows/test_submission.py +0 -0
  224. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/workflows/test_workflows.py +0 -0
  225. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/hpcflow/tests/workflows/test_zip.py +0 -0
  226. {hpcflow_new2-0.2.0a218 → hpcflow_new2-0.2.0a219}/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.0a218
3
+ Version: 0.2.0a219
4
4
  Summary: Computational workflow management
5
5
  License: MPL-2.0
6
6
  Author: aplowman
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0a219"
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ def import_future_script():
5
+ """Used to test the `__future__` import is moved to the top of the file in the
6
+ generated script in the case of `resources.combine_scripts == True`"""
7
+ pass
@@ -1794,7 +1794,8 @@ class BaseApp(metaclass=Singleton):
1794
1794
  for comp_type in TEMPLATE_COMP_TYPES:
1795
1795
  with open_text_resource(package, f"{comp_type}.yaml") as fh:
1796
1796
  SDK_logger.info(f"Parsing file as YAML: {fh.name!r}")
1797
- components[comp_type] = read_YAML_str(fh.read())
1797
+ source = f"from {Path(fh.name)!r}"
1798
+ components[comp_type] = read_YAML_str(fh.read(), source=source)
1798
1799
 
1799
1800
  return components
1800
1801
 
@@ -1020,3 +1020,9 @@ class MissingElementGroup(ValueError):
1020
1020
  f"Adding elements to task {task_name!r}: "
1021
1021
  f"no element group named {group_name!r} found for input {input_path!r}."
1022
1022
  )
1023
+
1024
+
1025
+ class YAMLError(ValueError):
1026
+ """
1027
+ A problem with parsing a YAML file.
1028
+ """
@@ -2788,31 +2788,31 @@ class InputSource(JSONLike):
2788
2788
 
2789
2789
  Examples
2790
2790
  --------
2791
- task.[task_ref].input
2792
- task.[task_ref].output
2793
- local
2794
- default
2795
- import.[import_ref]
2791
+ For a local task input source, use:
2792
+
2793
+ >>> InputSource.from_string("local")
2794
+
2795
+ For a schema input default source, use:
2796
+
2797
+ >>> InputSource.from_string("default")
2798
+
2799
+ For task input sources, specify either the task insert ID (typically this is just
2800
+ the task index within the workflow), or the task's unique name, which is usually
2801
+ just the associated task schema's objective, but if multiple tasks use the same
2802
+ schema, it will be suffixed by an index, starting from one.
2803
+
2804
+ >>> InputSource.from_string("task.0.input")
2805
+ >>> InputSource.from_string("task.my_task.input")
2796
2806
  """
2797
2807
  return cls(**cls._parse_from_string(str_defn))
2798
2808
 
2799
2809
  @staticmethod
2800
2810
  def _parse_from_string(str_defn: str) -> dict[str, Any]:
2801
- """Parse a dot-delimited string definition of an InputSource.
2802
-
2803
- Examples
2804
- --------
2805
- task.[task_ref].input
2806
- task.[task_ref].output
2807
- local
2808
- default
2809
- import.[import_ref]
2810
- """
2811
+ """Parse a dot-delimited string definition of an InputSource."""
2811
2812
  parts = str_defn.split(".")
2812
2813
  source_type = get_enum_by_name_or_val(InputSourceType, parts[0])
2813
- task_ref: int | None = None
2814
+ task_ref: int | str | None = None
2814
2815
  task_source_type: TaskSourceType | None = None
2815
- import_ref: int | None = None
2816
2816
  if (
2817
2817
  (
2818
2818
  source_type in (InputSourceType.LOCAL, InputSourceType.DEFAULT)
@@ -2826,22 +2826,20 @@ class InputSource(JSONLike):
2826
2826
  if source_type is InputSourceType.TASK:
2827
2827
  # TODO: does this include element_iters?
2828
2828
  try:
2829
+ # assume specified by task insert ID
2829
2830
  task_ref = int(parts[1])
2830
2831
  except ValueError:
2831
- pass
2832
+ # assume specified by task unique name
2833
+ task_ref = parts[1]
2832
2834
  try:
2833
2835
  task_source_type = get_enum_by_name_or_val(TaskSourceType, parts[2])
2834
2836
  except IndexError:
2835
2837
  task_source_type = TaskSourceType.OUTPUT
2836
2838
  elif source_type is InputSourceType.IMPORT:
2837
- try:
2838
- import_ref = int(parts[1])
2839
- except ValueError:
2840
- pass
2839
+ raise NotImplementedError("Import input sources are not yet supported.")
2841
2840
 
2842
2841
  return {
2843
2842
  "source_type": source_type,
2844
- "import_ref": import_ref,
2845
2843
  "task_ref": task_ref,
2846
2844
  "task_source_type": task_source_type,
2847
2845
  }
@@ -30,12 +30,14 @@ import fsspec # type: ignore
30
30
  import numpy as np
31
31
 
32
32
  from ruamel.yaml import YAML
33
+ from ruamel.yaml.error import MarkedYAMLError
33
34
  from watchdog.utils.dirsnapshot import DirectorySnapshot
34
35
 
35
36
  from hpcflow.sdk.core.errors import (
36
37
  ContainerKeyError,
37
38
  InvalidIdentifier,
38
39
  MissingVariableSubstitutionError,
40
+ YAMLError,
39
41
  )
40
42
  from hpcflow.sdk.log import TimeIt
41
43
  from hpcflow.sdk.utils.deferred_file import DeferredFileWriter
@@ -412,7 +414,10 @@ def substitute_string_vars(string: str, variables: dict[str, str]):
412
414
 
413
415
  @TimeIt.decorator
414
416
  def read_YAML_str(
415
- yaml_str: str, typ="safe", variables: dict[str, str] | Literal[False] | None = None
417
+ yaml_str: str,
418
+ typ="safe",
419
+ variables: dict[str, str] | Literal[False] | None = None,
420
+ source: str | None = None,
416
421
  ) -> Any:
417
422
  """Load a YAML string. This will produce basic objects.
418
423
 
@@ -426,11 +431,21 @@ def read_YAML_str(
426
431
  String variables to substitute in `yaml_str`. Substitutions will be attempted if
427
432
  the file looks to contain variable references (like "<<var:name>>"). If set to
428
433
  `False`, no substitutions will occur.
434
+ source:
435
+ Used to document the source of the YAML string if raising a parsing error.
436
+ Typically, this should be a string that starts with "from ...", e.g.
437
+ "from the file path '/path/to/bad/file'".
429
438
  """
430
439
  if variables is not False and "<<var:" in yaml_str:
431
440
  yaml_str = substitute_string_vars(yaml_str, variables=variables or {})
432
441
  yaml = YAML(typ=typ)
433
- return yaml.load(yaml_str)
442
+ try:
443
+ return yaml.load(yaml_str)
444
+ except MarkedYAMLError as err: # includes `ScannerError` and `ParserError`
445
+ source_str = f"{source} " if source else ""
446
+ raise YAMLError(
447
+ f"The YAML string {source_str}is not formatted correctly."
448
+ ) from err
434
449
 
435
450
 
436
451
  @TimeIt.decorator
@@ -452,7 +467,7 @@ def read_YAML_file(
452
467
  """
453
468
  with fsspec.open(path, "rt") as f:
454
469
  yaml_str: str = f.read()
455
- return read_YAML_str(yaml_str, typ=typ, variables=variables)
470
+ return read_YAML_str(yaml_str, typ=typ, variables=variables, source=f"from {path!r}")
456
471
 
457
472
 
458
473
  def write_YAML_file(obj, path: str | Path, typ: str = "safe") -> None:
@@ -578,7 +578,13 @@ class WorkflowTemplate(JSONLike):
578
578
  set to `False`, no substitutions will occur, which may result in an invalid
579
579
  workflow template!
580
580
  """
581
- return cls._from_data(read_YAML_str(string, variables=variables))
581
+ return cls._from_data(
582
+ read_YAML_str(
583
+ string,
584
+ variables=variables,
585
+ source="(from the inline workflow template definition)",
586
+ )
587
+ )
582
588
 
583
589
  @classmethod
584
590
  def _check_name(cls, data: dict[str, Any], path: PathLike) -> None:
@@ -962,9 +968,12 @@ class Workflow(AppAware):
962
968
  f"({task.name!r})..."
963
969
  )
964
970
  wk._add_task(task)
965
- if status:
966
- status.update(f"Preparing to add {len(template.loops)} loops...")
967
971
  if template.loops:
972
+ if status:
973
+ status.update(
974
+ f"Preparing to add {len(template.loops)} loops; building "
975
+ f"cache..."
976
+ )
968
977
  # TODO: if loop with non-initialisable actions, will fail
969
978
  cache = LoopCache.build(workflow=wk, loops=template.loops)
970
979
  for idx, loop in enumerate(template.loops):
@@ -979,6 +988,8 @@ class Workflow(AppAware):
979
988
  f"Added {len(template.loops)} loops. "
980
989
  f"Committing to store..."
981
990
  )
991
+ elif status:
992
+ status.update("Committing to store...")
982
993
  except (Exception, NotImplementedError):
983
994
  if status:
984
995
  status.stop()
@@ -4235,8 +4246,7 @@ class Workflow(AppAware):
4235
4246
  input_source.task_ref = uniq_names_cur[input_source.task_ref]
4236
4247
  except KeyError:
4237
4248
  raise InvalidInputSourceTaskReference(
4238
- f"Input source {input_source.to_string()!r} refers to a missing "
4239
- f"or inaccessible task: {input_source.task_ref!r}."
4249
+ input_source, task_ref=input_source.task_ref
4240
4250
  )
4241
4251
 
4242
4252
  @TimeIt.decorator
@@ -124,7 +124,7 @@ def _encode_numpy_array(
124
124
  new_idx = (
125
125
  max((int(i.removeprefix("arr_")) for i in param_arr_group.keys()), default=-1) + 1
126
126
  )
127
- param_arr_group.create_dataset(name=f"arr_{new_idx}", data=obj)
127
+ param_arr_group.create_dataset(name=f"arr_{new_idx}", data=obj, chunks=obj.shape)
128
128
  type_lookup["arrays"].append([path, new_idx])
129
129
 
130
130
  return len(type_lookup["arrays"]) - 1
@@ -24,6 +24,7 @@ from hpcflow.sdk.core.errors import (
24
24
  from hpcflow.sdk.typing import hydrate
25
25
  from hpcflow.sdk.core.json_like import ChildObjectSpec, JSONLike
26
26
  from hpcflow.sdk.core.utils import nth_value, parse_timestamp, current_timestamp
27
+ from hpcflow.sdk.utils.strings import extract_py_from_future_imports
27
28
  from hpcflow.sdk.log import TimeIt
28
29
  from hpcflow.sdk.submission.schedulers import QueuedScheduler
29
30
  from hpcflow.sdk.submission.schedulers.direct import DirectScheduler
@@ -1942,10 +1943,13 @@ class Jobscript(JSONLike):
1942
1943
  tab_indent = " "
1943
1944
 
1944
1945
  script_funcs_lst: list[str] = []
1946
+ future_imports: set[str] = set()
1945
1947
  for act_name, (_, snip_path) in script_data.items():
1946
1948
  main_func_name = snip_path.stem
1947
1949
  with snip_path.open("rt") as fp:
1948
1950
  script_str = fp.read()
1951
+ script_str, future_imports_i = extract_py_from_future_imports(script_str)
1952
+ future_imports.update(future_imports_i)
1949
1953
  script_funcs_lst.append(
1950
1954
  dedent(
1951
1955
  """\
@@ -2325,13 +2329,22 @@ class Jobscript(JSONLike):
2325
2329
  func_invoc_lines=indent(func_invoc_lines, tab_indent * 4),
2326
2330
  )
2327
2331
 
2332
+ future_imports_str = (
2333
+ f"from __future__ import {', '.join(future_imports)}\n\n"
2334
+ if future_imports
2335
+ else ""
2336
+ )
2328
2337
  script = dedent(
2329
2338
  """\
2330
- {script_funcs}
2339
+ {future_imports_str}{script_funcs}
2331
2340
  if __name__ == "__main__":
2332
2341
  {main}
2333
2342
  """
2334
- ).format(script_funcs=script_funcs, main=indent(main, tab_indent))
2343
+ ).format(
2344
+ future_imports_str=future_imports_str,
2345
+ script_funcs=script_funcs,
2346
+ main=indent(main, tab_indent),
2347
+ )
2335
2348
 
2336
2349
  num_elems = [i.num_elements for i in self.blocks]
2337
2350
  num_acts = [len(i) for i in action_scripts]
@@ -0,0 +1,61 @@
1
+ from typing import Iterable
2
+ import re
3
+
4
+
5
+ def shorten_list_str(
6
+ lst: Iterable, items: int = 10, end_num: int = 1, placeholder: str = "..."
7
+ ) -> str:
8
+ """Format a list as a string, including only some maximum number of items.
9
+
10
+ Parameters
11
+ ----------
12
+ lst:
13
+ The list to format in a shortened form.
14
+ items:
15
+ The total number of items to include in the formatted list.
16
+ end_num:
17
+ The number of items to include at the end of the formatted list.
18
+ placeholder
19
+ The placeholder to use to replace excess items in the formatted list.
20
+
21
+ Examples
22
+ --------
23
+ >>> shorten_list_str(list(range(20)), items=5)
24
+ '[0, 1, 2, 3, ..., 19]'
25
+
26
+ """
27
+ lst = list(lst)
28
+ if len(lst) <= items + 1: # (don't replace only one item)
29
+ lst_short = lst
30
+ else:
31
+ start_num = items - end_num
32
+ lst_short = lst[:start_num] + ["..."] + lst[-end_num:]
33
+
34
+ return "[" + ", ".join(f"{i}" for i in lst_short) + "]"
35
+
36
+
37
+ def extract_py_from_future_imports(py_str: str) -> tuple[str, set[str]]:
38
+ """
39
+ Remove any `from __future__ import <feature>` lines from a string of Python code, and
40
+ return the modified string, and a list of `<feature>`s that were imported.
41
+
42
+ Notes
43
+ -----
44
+ This is required when generated a combined-scripts jobscript that concatenates
45
+ multiple Python scripts into one script. If `__future__` statements are included in
46
+ these individual scripts, they must be moved to the top of the file [1].
47
+
48
+ References
49
+ ----------
50
+ [1] https://docs.python.org/3/reference/simple_stmts.html#future-statements
51
+
52
+ """
53
+
54
+ pattern = r"^from __future__ import (.*)\n"
55
+ if future_imports := (set(re.findall(pattern, py_str, flags=re.MULTILINE) or ())):
56
+ future_imports = {
57
+ j.strip() for i in future_imports for j in i.split(",") if j.strip()
58
+ }
59
+ py_str = re.sub(pattern, "", py_str, flags=re.MULTILINE)
60
+
61
+ return (py_str, future_imports)
@@ -6,6 +6,7 @@ import time
6
6
  import pytest
7
7
 
8
8
  from hpcflow.app import app as hf
9
+ from hpcflow.sdk.core.enums import EARStatus
9
10
  from hpcflow.sdk.core.test_utils import P1_parameter_cls as P1
10
11
 
11
12
  # note: when testing the frozen app, we might not have MatFlow installed in the built in
@@ -1332,3 +1333,29 @@ def test_combine_scripts_script_data_multiple_input_file_formats(
1332
1333
  assert isinstance(t1_p3, hf.ElementParameter)
1333
1334
  assert t0_p2.value == p1_val + 100
1334
1335
  assert t1_p3.value == p1_val + 100
1336
+
1337
+
1338
+ @pytest.mark.integration
1339
+ @pytest.mark.skipif("hf.run_time_info.is_frozen")
1340
+ def test_combine_scripts_from_future_import(null_config, tmp_path: Path):
1341
+ s1 = hf.TaskSchema(
1342
+ objective="t1",
1343
+ actions=[
1344
+ hf.Action(
1345
+ script="<<script:import_future_script.py>>",
1346
+ script_exe="python_script",
1347
+ environments=[hf.ActionEnvironment(environment="python_env")],
1348
+ ),
1349
+ ],
1350
+ )
1351
+
1352
+ wk = hf.Workflow.from_template_data(
1353
+ template_name="test_future_import",
1354
+ tasks=[hf.Task(schema=s1)],
1355
+ resources={"any": {"combine_scripts": True}},
1356
+ path=tmp_path,
1357
+ )
1358
+ wk.submit(status=False, add_to_known=False, wait=True)
1359
+
1360
+ run = wk.get_EARs_from_IDs([0])[0]
1361
+ assert run.status is EARStatus.success
@@ -121,3 +121,28 @@ def test_nesting_order_paths_raise(null_config) -> None:
121
121
 
122
122
  def test_nesting_order_paths_no_raise(null_config) -> None:
123
123
  hf.ElementSet(nesting_order={"inputs.p1": 1, "resources.any": 2, "repeats": 3})
124
+
125
+
126
+ def test_input_source_str_dict_list_str_list_dict_equivalence(null_config) -> None:
127
+ inp_source_dict: dict[str, str | int] = {
128
+ "source_type": "task",
129
+ "task_source_type": "output",
130
+ "task_ref": 0,
131
+ }
132
+ inp_source_str = "task.0.output"
133
+ inp_source_list_dict = [inp_source_dict]
134
+ inp_source_list_str = [inp_source_str]
135
+ assert (
136
+ hf.ElementSet.from_json_like(
137
+ {"input_sources": {"p1": inp_source_dict}}
138
+ ).input_sources
139
+ == hf.ElementSet.from_json_like(
140
+ {"input_sources": {"p1": inp_source_list_dict}}
141
+ ).input_sources
142
+ == hf.ElementSet.from_json_like(
143
+ {"input_sources": {"p1": inp_source_str}}
144
+ ).input_sources
145
+ == hf.ElementSet.from_json_like(
146
+ {"input_sources": {"p1": inp_source_list_str}}
147
+ ).input_sources
148
+ )
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+ from textwrap import dedent
2
3
  from typing import TYPE_CHECKING
3
4
  import numpy as np
4
5
  import pytest
@@ -183,6 +184,7 @@ def test_input_source_from_string_task_same_default_task_source() -> None:
183
184
  )
184
185
 
185
186
 
187
+ @pytest.mark.skip(reason="Import not yet implemented.")
186
188
  def test_input_source_from_string_import() -> None:
187
189
  import_ref = 0
188
190
  assert hf.InputSource.from_string(f"import.{import_ref}") == hf.InputSource(
@@ -1283,3 +1285,72 @@ def test_input_source_inputs_from_multiple_element_sets_with_sub_parameter_seque
1283
1285
  {"a": 5, "b": 22},
1284
1286
  {"a": 5, "b": 22},
1285
1287
  ]
1288
+
1289
+
1290
+ def test_input_source_task_ref_equivalence(null_config, tmp_path):
1291
+ yml = dedent(
1292
+ """\
1293
+ name: test
1294
+ template_components:
1295
+ task_schemas:
1296
+ - objective: t1
1297
+ inputs:
1298
+ - parameter: p1
1299
+ tasks:
1300
+ - schema: t1
1301
+ inputs:
1302
+ p1: 100 # all subsequent tasks will source from this input
1303
+
1304
+ - schema: t1 # t1_2
1305
+ input_sources: # single source dict; by task insert ID
1306
+ p1:
1307
+ source_type: task
1308
+ task_source_type: input
1309
+ task_ref: 0
1310
+
1311
+ - schema: t1 # t1_3
1312
+ input_sources: # as a list of dicts; by task insert ID
1313
+ p1:
1314
+ - source_type: task
1315
+ task_source_type: input
1316
+ task_ref: 0
1317
+
1318
+ - schema: t1 # t1_4
1319
+ input_sources: # as a single source dict; by task unique name
1320
+ p1:
1321
+ source_type: task
1322
+ task_source_type: input
1323
+ task_ref: t1_1
1324
+
1325
+ - schema: t1 # t1_5
1326
+ input_sources: # as a list of dicts; by task unique name
1327
+ p1:
1328
+ - source_type: task
1329
+ task_source_type: input
1330
+ task_ref: t1_1
1331
+
1332
+ - schema: t1 # t1_6
1333
+ input_sources: # single source string; by task insert ID
1334
+ p1: task.0.input
1335
+
1336
+ - schema: t1 # t1_7
1337
+ input_sources: # as a list of strings; by task insert ID
1338
+ p1:
1339
+ - task.0.input
1340
+
1341
+ - schema: t1 # t1_8
1342
+ input_sources: # single source string; by task unique name
1343
+ p1: task.t1_1.input
1344
+
1345
+ - schema: t1 # t1_9
1346
+ input_sources: # as a list of strings; by task unique name
1347
+ p1:
1348
+ - task.t1_1.input
1349
+
1350
+ """
1351
+ )
1352
+ wk = hf.Workflow.from_YAML_string(YAML_str=yml, path=tmp_path)
1353
+
1354
+ all_sources = (task.elements[0].input_sources["inputs.p1"] for task in wk.tasks[1:])
1355
+ all_task_refs = (src.task_ref for src in all_sources)
1356
+ assert all(task_ref == 0 for task_ref in all_task_refs)
@@ -1,9 +1,14 @@
1
1
  from pathlib import Path
2
+ from textwrap import dedent
2
3
  import pytest
3
4
  import zarr # type: ignore
4
5
  import numpy as np
5
6
  from numpy.typing import NDArray
6
- from hpcflow.sdk.core.errors import InvalidIdentifier, MissingVariableSubstitutionError
7
+ from hpcflow.sdk.core.errors import (
8
+ InvalidIdentifier,
9
+ MissingVariableSubstitutionError,
10
+ YAMLError,
11
+ )
7
12
 
8
13
  from hpcflow.sdk.core.utils import (
9
14
  JSONLikeDirSnapShot,
@@ -16,6 +21,7 @@ from hpcflow.sdk.core.utils import (
16
21
  nth_key,
17
22
  nth_value,
18
23
  process_string_nodes,
24
+ read_YAML_str,
19
25
  replace_items,
20
26
  check_valid_py_identifier,
21
27
  reshape,
@@ -575,3 +581,36 @@ def test_nth_key_raises():
575
581
 
576
582
  with pytest.raises(Exception):
577
583
  nth_key(dct, -1)
584
+
585
+
586
+ def test_read_YAML_str():
587
+ good_yaml = dedent(
588
+ """\
589
+ a: 1
590
+ b: 2
591
+ """
592
+ )
593
+ assert read_YAML_str(good_yaml) == {"a": 1, "b": 2}
594
+
595
+
596
+ def test_read_YAML_str_raise_on_bad_indent():
597
+ bad_yaml = dedent(
598
+ """\
599
+ a: 1
600
+ b: 2
601
+ """
602
+ )
603
+ with pytest.raises(YAMLError):
604
+ read_YAML_str(bad_yaml)
605
+
606
+
607
+ def test_read_YAML_str_raise_on_mixed_tabs_spaces():
608
+ bad_yaml = dedent(
609
+ """\
610
+ a:
611
+ a1: 2 # this has a space indent
612
+ a2: 3 # this has a tab indent
613
+ """
614
+ )
615
+ with pytest.raises(YAMLError):
616
+ read_YAML_str(bad_yaml)
@@ -0,0 +1,97 @@
1
+ from textwrap import dedent
2
+
3
+ from hpcflow.sdk.utils.strings import extract_py_from_future_imports
4
+
5
+
6
+ def test_extract_py_from_future_imports_none():
7
+ py_str = dedent(
8
+ """\
9
+
10
+ def my_function():
11
+ print("blah!")
12
+ """
13
+ )
14
+ new_str, imports = extract_py_from_future_imports(py_str)
15
+ assert imports == set()
16
+ assert new_str == py_str
17
+
18
+
19
+ def test_extract_py_from_future_imports_single():
20
+ py_str = dedent(
21
+ """\
22
+ from __future__ import annotations
23
+
24
+ def my_function():
25
+ print("blah!")
26
+ """
27
+ )
28
+ new_str, imports = extract_py_from_future_imports(py_str)
29
+ assert imports == {"annotations"}
30
+ assert new_str == dedent(
31
+ """\
32
+
33
+ def my_function():
34
+ print("blah!")
35
+ """
36
+ )
37
+
38
+
39
+ def test_extract_py_from_future_imports_multi():
40
+ py_str = dedent(
41
+ """\
42
+ from __future__ import annotations, feature_2
43
+
44
+ def my_function():
45
+ print("blah!")
46
+ """
47
+ )
48
+ new_str, imports = extract_py_from_future_imports(py_str)
49
+ assert imports == {"annotations", "feature_2"}
50
+ assert new_str == dedent(
51
+ """\
52
+
53
+ def my_function():
54
+ print("blah!")
55
+ """
56
+ )
57
+
58
+
59
+ def test_extract_py_from_future_imports_trailing_comma():
60
+ py_str = dedent(
61
+ """\
62
+ from __future__ import annotations,
63
+
64
+ def my_function():
65
+ print("blah!")
66
+ """
67
+ )
68
+ new_str, imports = extract_py_from_future_imports(py_str)
69
+ assert imports == {"annotations"}
70
+ assert new_str == dedent(
71
+ """\
72
+
73
+ def my_function():
74
+ print("blah!")
75
+ """
76
+ )
77
+
78
+
79
+ def test_extract_py_from_future_imports_multi_lines():
80
+ py_str = dedent(
81
+ """\
82
+ from __future__ import annotations, feature_2
83
+ from __future__ import feature_2, feature_3,
84
+
85
+ def my_function():
86
+ print("blah!")
87
+ """
88
+ )
89
+ new_str, imports = extract_py_from_future_imports(py_str)
90
+ assert imports == {"annotations", "feature_2", "feature_3"}
91
+ assert new_str == dedent(
92
+ """\
93
+
94
+ def my_function():
95
+ print("blah!")
96
+ """
97
+ )
@@ -1,7 +1,7 @@
1
1
 
2
2
  [tool.poetry]
3
3
  name = "hpcflow-new2"
4
- version = "0.2.0a218"
4
+ version = "0.2.0a219"
5
5
 
6
6
  description = "Computational workflow management"
7
7
  authors = ["aplowman <adam.plowman@manchester.ac.uk>"]
@@ -100,7 +100,7 @@ hook-dirs = "hpcflow.__pyinstaller:get_hook_dirs"
100
100
 
101
101
  [tool.commitizen]
102
102
  name = "cz_conventional_commits"
103
- version = "0.2.0a218"
103
+ version = "0.2.0a219"
104
104
  tag_format = "v$version"
105
105
  version_files = [
106
106
  "pyproject.toml:version",
@@ -1 +0,0 @@
1
- __version__ = "0.2.0a218"