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
@@ -2,42 +2,41 @@ doc: |
2
2
  A workflow to sleep a specified number of seconds, and then set an output parameter
3
3
  `is_finished` to the string "true". This is used for testing the run-abort
4
4
  functionality.
5
- parameters:
6
- - type: sleep_time_seconds
7
- - type: is_finished
8
- task_schemas:
9
- - objective: sleep
10
- inputs:
11
- - parameter: sleep_time_seconds
12
- outputs:
13
- - parameter: is_finished
14
- actions:
15
- - abortable: true
16
- rules:
17
- - path: resources.os_name
18
- condition: { value.equal_to: posix }
19
- commands:
20
- - command: sleep <<parameter:sleep_time_seconds>>
21
- - abortable: true
22
- rules:
23
- - path: resources.os_name
24
- condition: { value.equal_to: nt }
25
- commands:
26
- - command: Start-Sleep <<parameter:sleep_time_seconds>>
27
- - rules:
28
- - path: resources.os_name
29
- condition: { value.equal_to: posix }
30
- commands:
31
- - command: echo "true"
32
- stdout: <<parameter:is_finished>>
33
- - rules:
34
- - path: resources.os_name
35
- condition: { value.equal_to: nt }
36
- commands:
37
- - command: Write-Output "true"
38
- stdout: <<parameter:is_finished>>
5
+
6
+ template_components:
7
+ task_schemas:
8
+ - objective: sleep
9
+ inputs:
10
+ - parameter: sleep_time_seconds
11
+ outputs:
12
+ - parameter: is_finished
13
+ actions:
14
+ - abortable: true
15
+ rules:
16
+ - path: resources.os_name
17
+ condition: { value.equal_to: posix }
18
+ commands:
19
+ - command: sleep <<parameter:sleep_time_seconds>>
20
+ - abortable: true
21
+ rules:
22
+ - path: resources.os_name
23
+ condition: { value.equal_to: nt }
24
+ commands:
25
+ - command: Start-Sleep <<parameter:sleep_time_seconds>>
26
+ - rules:
27
+ - path: resources.os_name
28
+ condition: { value.equal_to: posix }
29
+ commands:
30
+ - command: echo "true"
31
+ stdout: <<parameter:is_finished>>
32
+ - rules:
33
+ - path: resources.os_name
34
+ condition: { value.equal_to: nt }
35
+ commands:
36
+ - command: Write-Output "true"
37
+ stdout: <<parameter:is_finished>>
39
38
 
40
39
  tasks:
41
40
  - schema: sleep
42
41
  inputs:
43
- sleep_time_seconds: 3600 # 1 hour
42
+ sleep_time_seconds: 300 # 5 minutes
@@ -0,0 +1,36 @@
1
+ import pytest
2
+ from hpcflow.app import app as hf
3
+
4
+
5
+ def test_SGE_process_resources_multi_core_with_parallel_env(null_config):
6
+
7
+ scheduler_config = {
8
+ "parallel_environments": {
9
+ None: {"num_cores": [1, 1, 1]}, # [start, step, stop]
10
+ "my_parallel_env": {"num_cores": [2, 1, 32]},
11
+ }
12
+ }
13
+
14
+ scheduler = hf.SGEPosix()
15
+ resources = hf.ElementResources(num_cores=2, SGE_parallel_env="my_parallel_env")
16
+
17
+ scheduler.process_resources(resources, scheduler_config)
18
+
19
+ assert resources.num_cores == 2
20
+ assert resources.SGE_parallel_env == "my_parallel_env"
21
+
22
+
23
+ def test_SGE_process_resources_raises_on_single_core_with_parallel_env(null_config):
24
+
25
+ scheduler_config = {
26
+ "parallel_environments": {
27
+ None: {"num_cores": [1, 1, 1]}, # [start, step, stop]
28
+ "my_parallel_env": {"num_cores": [2, 1, 32]},
29
+ }
30
+ }
31
+
32
+ scheduler = hf.SGEPosix()
33
+ resources = hf.ElementResources(num_cores=1, SGE_parallel_env="my_parallel_env")
34
+
35
+ with pytest.raises(ValueError):
36
+ scheduler.process_resources(resources, scheduler_config)
@@ -1,11 +1,14 @@
1
+ from pathlib import Path
1
2
  import pytest
2
3
  from hpcflow.app import app as hf
3
4
  from hpcflow.sdk.core.test_utils import make_test_data_YAML_workflow
4
5
 
5
6
 
6
7
  @pytest.mark.slurm
7
- def test_workflow_1(tmp_path, null_config):
8
+ def test_workflow_1(tmp_path: Path, null_config):
8
9
  hf.config.add_scheduler("slurm")
9
10
  wk = make_test_data_YAML_workflow("workflow_1_slurm.yaml", path=tmp_path)
10
11
  wk.submit(wait=True, add_to_known=False)
11
- assert wk.tasks[0].elements[0].outputs.p2.value == "201"
12
+ p2 = wk.tasks[0].elements[0].outputs.p2
13
+ assert isinstance(p2, hf.ElementParameter)
14
+ assert p2.value == "201"
@@ -0,0 +1,282 @@
1
+ import os
2
+ import time
3
+
4
+ import pytest
5
+ from hpcflow.app import app as hf
6
+
7
+
8
+ @pytest.mark.integration
9
+ @pytest.mark.skipif("hf.run_time_info.is_frozen")
10
+ def test_input_file_generator_creates_file(null_config, tmp_path):
11
+
12
+ inp_file = hf.FileSpec(label="my_input_file", name="my_input_file.txt")
13
+
14
+ if os.name == "nt":
15
+ cmd = "Get-Content <<file:my_input_file>>"
16
+ else:
17
+ cmd = "cat <<file:my_input_file>>"
18
+
19
+ s1 = hf.TaskSchema(
20
+ objective="t1",
21
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p1"))],
22
+ actions=[
23
+ hf.Action(
24
+ commands=[hf.Command(cmd)],
25
+ input_file_generators=[
26
+ hf.InputFileGenerator(
27
+ input_file=inp_file,
28
+ inputs=[hf.Parameter("p1")],
29
+ script="<<script:input_file_generator_basic.py>>",
30
+ ),
31
+ ],
32
+ environments=[hf.ActionEnvironment(environment="python_env")],
33
+ )
34
+ ],
35
+ )
36
+ p1_val = 101
37
+ t1 = hf.Task(schema=s1, inputs={"p1": p1_val})
38
+ wk = hf.Workflow.from_template_data(
39
+ tasks=[t1],
40
+ template_name="input_file_generator_test",
41
+ path=tmp_path,
42
+ )
43
+ wk.submit(wait=True, add_to_known=False)
44
+
45
+ # check the input file is written
46
+ run_0 = wk.get_all_EARs()[0]
47
+ exec_path = run_0.get_directory()
48
+ inp_file_path = exec_path.joinpath(inp_file.name.name)
49
+ inp_file_contents = inp_file_path.read_text()
50
+ assert inp_file_contents.strip() == str(p1_val)
51
+
52
+ # check the command successfully printed the file contents to stdout:
53
+ std_out = wk.submissions[0].jobscripts[0].direct_stdout_path.read_text()
54
+ assert std_out.strip() == str(p1_val)
55
+
56
+
57
+ @pytest.mark.integration
58
+ @pytest.mark.skipif("hf.run_time_info.is_frozen")
59
+ def test_IFG_std_stream_redirect_on_exception(new_null_config, tmp_path):
60
+ """Test exceptions raised by the app during execution of a IFG script are printed to the
61
+ std-stream redirect file (and not the jobscript's standard error file)."""
62
+
63
+ # define a custom python environment which redefines the `WK_PATH` shell variable to
64
+ # a nonsense value so the app cannot load the workflow and thus raises an exception
65
+
66
+ app_caps = hf.package_name.upper()
67
+ if os.name == "nt":
68
+ env_cmd = f'$env:{app_caps}_WK_PATH = "nonsense_path"'
69
+ else:
70
+ env_cmd = f'export {app_caps}_WK_PATH="nonsense_path"'
71
+
72
+ env_cmd += "; python <<script_path>> <<args>>"
73
+ bad_env = hf.Environment(
74
+ name="bad_python_env",
75
+ executables=[
76
+ hf.Executable(
77
+ label="python_script",
78
+ instances=[
79
+ hf.ExecutableInstance(
80
+ command=env_cmd,
81
+ num_cores=1,
82
+ parallel_mode=None,
83
+ )
84
+ ],
85
+ )
86
+ ],
87
+ )
88
+ hf.envs.add_object(bad_env, skip_duplicates=True)
89
+
90
+ inp_file = hf.FileSpec(label="my_input_file", name="my_input_file.txt")
91
+ s1 = hf.TaskSchema(
92
+ objective="t1",
93
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p1"))],
94
+ actions=[
95
+ hf.Action(
96
+ input_file_generators=[
97
+ hf.InputFileGenerator(
98
+ input_file=inp_file,
99
+ inputs=[hf.Parameter("p1")],
100
+ script="<<script:input_file_generator_basic.py>>",
101
+ ),
102
+ ],
103
+ environments=[hf.ActionEnvironment(environment="bad_python_env")],
104
+ )
105
+ ],
106
+ )
107
+
108
+ p1_val = 101
109
+ t1 = hf.Task(schema=s1, inputs={"p1": p1_val})
110
+ wk = hf.Workflow.from_template_data(
111
+ tasks=[t1], template_name="input_file_generator_test", path=tmp_path
112
+ )
113
+ wk.submit(wait=True, add_to_known=False, status=False)
114
+
115
+ # jobscript stderr should be empty
116
+ assert not wk.submissions[0].jobscripts[0].direct_stderr_path.read_text()
117
+
118
+ # std stream file has workflow not found traceback
119
+ run = wk.get_all_EARs()[0]
120
+ std_stream_path = run.get_app_std_path()
121
+ assert std_stream_path.is_file()
122
+ assert "WorkflowNotFoundError" in std_stream_path.read_text()
123
+
124
+ hf.reload_template_components() # remove extra envs
125
+
126
+
127
+ @pytest.mark.integration
128
+ @pytest.mark.skipif("hf.run_time_info.is_frozen")
129
+ def test_IFG_std_out_std_err_not_redirected(null_config, tmp_path):
130
+ """Test that standard error and output streams from an IFG script are written to the jobscript
131
+ standard error and output files."""
132
+ inp_file = hf.FileSpec(label="my_input_file", name="my_input_file.txt")
133
+ s1 = hf.TaskSchema(
134
+ objective="t1",
135
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p1"))],
136
+ actions=[
137
+ hf.Action(
138
+ input_file_generators=[
139
+ hf.InputFileGenerator(
140
+ input_file=inp_file,
141
+ inputs=[hf.Parameter("p1")],
142
+ script="<<script:input_file_generator_test_stdout_stderr.py>>",
143
+ ),
144
+ ],
145
+ environments=[hf.ActionEnvironment(environment="python_env")],
146
+ )
147
+ ],
148
+ )
149
+ p1_val = 101
150
+ stdout_msg = str(p1_val)
151
+ stderr_msg = str(p1_val)
152
+ t1 = hf.Task(schema=s1, inputs={"p1": p1_val})
153
+ wk = hf.Workflow.from_template_data(
154
+ tasks=[t1],
155
+ template_name="input_file_generator_test",
156
+ path=tmp_path,
157
+ )
158
+ wk.submit(wait=True, add_to_known=False)
159
+
160
+ if wk.submissions[0].jobscripts[0].resources.combine_jobscript_std:
161
+ std_out_err = wk.submissions[0].jobscripts[0].direct_std_out_err_path.read_text()
162
+ assert std_out_err.strip() == f"{stdout_msg}\n{stderr_msg}"
163
+ else:
164
+ std_out = wk.submissions[0].jobscripts[0].direct_stdout_path.read_text()
165
+ std_err = wk.submissions[0].jobscripts[0].direct_stderr_path.read_text()
166
+ assert std_out.strip() == stdout_msg
167
+ assert std_err.strip() == stderr_msg
168
+
169
+
170
+ @pytest.mark.integration
171
+ @pytest.mark.skipif("hf.run_time_info.is_frozen")
172
+ def test_IFG_pass_env_spec(null_config, tmp_path):
173
+ inp_file = hf.FileSpec(label="my_input_file", name="my_input_file.txt")
174
+
175
+ if os.name == "nt":
176
+ cmd = "Get-Content <<file:my_input_file>>"
177
+ else:
178
+ cmd = "cat <<file:my_input_file>>"
179
+
180
+ s1 = hf.TaskSchema(
181
+ objective="t1",
182
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p1"))],
183
+ actions=[
184
+ hf.Action(
185
+ commands=[hf.Command(cmd)],
186
+ input_file_generators=[
187
+ hf.InputFileGenerator(
188
+ input_file=inp_file,
189
+ inputs=[hf.Parameter("p1")],
190
+ script="<<script:env_specifier_test/input_file_generator_pass_env_spec.py>>",
191
+ script_pass_env_spec=True,
192
+ ),
193
+ ],
194
+ environments=[hf.ActionEnvironment(environment="python_env")],
195
+ )
196
+ ],
197
+ )
198
+ p1_val = 101
199
+ t1 = hf.Task(schema=s1, inputs={"p1": p1_val})
200
+ wk = hf.Workflow.from_template_data(
201
+ tasks=[t1],
202
+ template_name="input_file_generator_pass_env_spec",
203
+ path=tmp_path,
204
+ )
205
+ wk.submit(wait=True, add_to_known=False, status=False)
206
+
207
+ # check the command successfully printed the env spec and file contents to stdout:
208
+ std_out = wk.submissions[0].jobscripts[0].direct_stdout_path.read_text()
209
+ assert std_out.strip() == f"{{'name': 'python_env'}}\n{str(p1_val)}"
210
+
211
+
212
+ @pytest.mark.integration
213
+ @pytest.mark.skipif("hf.run_time_info.is_frozen")
214
+ def test_env_specifier_in_input_file_generator_script_path(new_null_config, tmp_path):
215
+
216
+ py_env = hf.Environment(
217
+ name="python_env",
218
+ specifiers={"version": "v1"},
219
+ executables=[
220
+ hf.Executable(
221
+ label="python_script",
222
+ instances=[
223
+ hf.ExecutableInstance(
224
+ command="python <<script_path>> <<args>>",
225
+ num_cores=1,
226
+ parallel_mode=None,
227
+ )
228
+ ],
229
+ )
230
+ ],
231
+ )
232
+ hf.envs.add_object(py_env, skip_duplicates=True)
233
+
234
+ inp_file = hf.FileSpec(label="my_input_file", name="my_input_file.txt")
235
+
236
+ if os.name == "nt":
237
+ cmd = "Get-Content <<file:my_input_file>>"
238
+ else:
239
+ cmd = "cat <<file:my_input_file>>"
240
+
241
+ s1 = hf.TaskSchema(
242
+ objective="t1",
243
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p1"))],
244
+ actions=[
245
+ hf.Action(
246
+ commands=[hf.Command(cmd)],
247
+ input_file_generators=[
248
+ hf.InputFileGenerator(
249
+ input_file=inp_file,
250
+ inputs=[hf.Parameter("p1")],
251
+ script="<<script:env_specifier_test/<<env:version>>/input_file_generator_basic.py>>",
252
+ ),
253
+ ],
254
+ environments=[hf.ActionEnvironment(environment="python_env")],
255
+ )
256
+ ],
257
+ )
258
+ p1_val = 101
259
+ t1 = hf.Task(
260
+ schema=s1,
261
+ inputs={"p1": p1_val},
262
+ environments={"python_env": {"version": "v1"}},
263
+ )
264
+ wk = hf.Workflow.from_template_data(
265
+ tasks=[t1],
266
+ template_name="input_file_generator_test_env_specifier",
267
+ path=tmp_path,
268
+ )
269
+ wk.submit(wait=True, add_to_known=False, status=False)
270
+
271
+ # check the input file is written
272
+ run_0 = wk.get_all_EARs()[0]
273
+ exec_path = run_0.get_directory()
274
+ inp_file_path = exec_path.joinpath(inp_file.name.name)
275
+ inp_file_contents = inp_file_path.read_text()
276
+ assert inp_file_contents.strip() == str(p1_val)
277
+
278
+ # check the command successfully printed the file contents to stdout:
279
+ std_out = wk.submissions[0].jobscripts[0].direct_stdout_path.read_text()
280
+ assert std_out.strip() == str(p1_val)
281
+
282
+ hf.reload_template_components() # remove extra envs