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
@@ -0,0 +1,24 @@
1
+ """
2
+ Utility base class for making classes aware of the overall application context.
3
+ """
4
+ from __future__ import annotations
5
+ from typing import TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from typing import ClassVar
9
+ from ..app import BaseApp
10
+
11
+
12
+ class AppAware:
13
+ """
14
+ A base class that marks its subclasses as aware of the application.
15
+
16
+ Attributes
17
+ ----------
18
+ _app: BaseApp
19
+ A class attribute that holds the application instance.
20
+ """
21
+
22
+ __slots__: ClassVar[tuple[str, ...]] = ()
23
+ _app: ClassVar[BaseApp]
24
+ _app_attr: ClassVar[str] = "_app"
hpcflow/sdk/core/cache.py CHANGED
@@ -2,42 +2,62 @@
2
2
  Dependency resolution cache.
3
3
  """
4
4
 
5
+ from __future__ import annotations
5
6
  from collections import defaultdict
6
7
  from dataclasses import dataclass
7
- from typing import Set, Dict
8
+ from itertools import chain
9
+ from typing import TYPE_CHECKING
8
10
 
9
11
  from hpcflow.sdk.log import TimeIt
10
12
 
13
+ if TYPE_CHECKING:
14
+ from collections.abc import Sequence
15
+ from typing_extensions import Self
16
+ from .element import Element, ElementIteration
17
+ from .actions import ElementActionRun
18
+ from .workflow import Workflow
19
+ from ..persistence.base import StoreEAR, StoreElement, StoreElementIter
20
+
11
21
 
12
22
  @dataclass
13
- class DependencyCache:
14
- """Class to bulk-retrieve dependencies between elements, iterations, and runs."""
23
+ class ObjectCache:
24
+ """Class to bulk-retrieve and store elements, iterations, runs and their various
25
+ dependencies."""
26
+
27
+ #: The elements of the workflow that this cache was built from.
28
+ elements: list[Element] | None = None
29
+ #: The iterations of the workflow that this cache was built from.
30
+ iterations: list[ElementIteration] | None = None
31
+ #: The runs of the workflow that this cache was built from.
32
+ runs: list[ElementActionRun] | None = None
15
33
 
16
34
  #: What EARs (by ID) a given EAR depends on.
17
- run_dependencies: Dict[int, Set]
35
+ run_dependencies: dict[int, set[int]] | None = None
18
36
  #: What EARs (by ID) are depending on a given EAR.
19
- run_dependents: Dict[int, Set]
37
+ run_dependents: dict[int, set[int]] | None = None
20
38
  #: What EARs (by ID) a given iteration depends on.
21
- iter_run_dependencies: Dict[int, Set]
39
+ iter_run_dependencies: dict[int, set[int]] | None = None
22
40
  #: What iterations (by ID) a given iteration depends on.
23
- iter_iter_dependencies: Dict[int, Set]
41
+ iter_iter_dependencies: dict[int, set[int]] | None = None
24
42
  #: What iterations (by ID) a given element depends on.
25
- elem_iter_dependencies: Dict[int, Set]
43
+ elem_iter_dependencies: dict[int, set[int]] | None = None
26
44
  #: What elements (by ID) a given element depends on.
27
- elem_elem_dependencies: Dict[int, Set]
45
+ elem_elem_dependencies: dict[int, set[int]] | None = None
28
46
  #: What elements (by ID) are depending on a given element.
29
- elem_elem_dependents: Dict[int, Set]
47
+ elem_elem_dependents: dict[int, set[int]] | None = None
30
48
  #: Transitive closure of :py:attr:`elem_elem_dependents`.
31
- elem_elem_dependents_rec: Dict[int, Set]
32
-
33
- #: The elements of the workflow that this cache was built from.
34
- elements: Dict
35
- #: The iterations of the workflow that this cache was built from.
36
- iterations: Dict
49
+ elem_elem_dependents_rec: dict[int, set[int]] | None = None
37
50
 
38
51
  @classmethod
39
52
  @TimeIt.decorator
40
- def build(cls, workflow):
53
+ def build(
54
+ cls,
55
+ workflow: Workflow,
56
+ dependencies: bool = False,
57
+ elements: bool = False,
58
+ iterations: bool = False,
59
+ runs: bool = False,
60
+ ):
41
61
  """
42
62
  Build a cache instance.
43
63
 
@@ -45,59 +65,108 @@ class DependencyCache:
45
65
  ----------
46
66
  workflow: ~hpcflow.app.Workflow
47
67
  The workflow to build the cache from.
68
+ dependencies
69
+ If True, calculate dependencies.
70
+ elements
71
+ If True, include elements in the cache.
72
+ iterations
73
+ If True, include iterations in the cache.
74
+ runs
75
+ If True, include runs in the cache.
76
+
48
77
  """
78
+ kwargs = {}
79
+ if dependencies:
80
+ kwargs.update(cls._get_dependencies(workflow))
81
+
82
+ if elements:
83
+ kwargs["elements"] = workflow.get_all_elements()
84
+
85
+ if iterations:
86
+ kwargs["iterations"] = workflow.get_all_element_iterations()
87
+
88
+ if runs:
89
+ kwargs["runs"] = workflow.get_all_EARs()
90
+
91
+ return cls(**kwargs)
92
+
93
+ @classmethod
94
+ @TimeIt.decorator
95
+ def _get_dependencies(cls, workflow: Workflow):
96
+ def _get_recursive_deps(elem_id: int, seen_ids: list[int] | None = None):
97
+ if seen_ids is None:
98
+ seen_ids = [elem_id]
99
+ elif elem_id in seen_ids:
100
+ # stop recursion
101
+ return set()
102
+ else:
103
+ seen_ids.append(elem_id)
104
+ return set(elem_elem_dependents[elem_id]).union(
105
+ [
106
+ j
107
+ for i in elem_elem_dependents[elem_id]
108
+ for j in _get_recursive_deps(i, seen_ids)
109
+ if j != elem_id
110
+ ]
111
+ )
112
+
49
113
  num_iters = workflow.num_element_iterations
50
114
  num_elems = workflow.num_elements
51
115
  num_runs = workflow.num_EARs
52
116
 
53
- all_store_runs = workflow._store.get_EARs(list(range(num_runs)))
54
- all_store_iters = workflow._store.get_element_iterations(list(range(num_iters)))
55
- all_store_elements = workflow._store.get_elements(list(range(num_elems)))
117
+ all_store_runs: Sequence[StoreEAR] = workflow._store.get_EARs(range(num_runs))
118
+ all_store_iters: Sequence[
119
+ StoreElementIter
120
+ ] = workflow._store.get_element_iterations(range(num_iters))
121
+ all_store_elements: Sequence[StoreElement] = workflow._store.get_elements(
122
+ range(num_elems)
123
+ )
56
124
  all_param_sources = workflow.get_all_parameter_sources()
57
- all_data_idx = [
125
+ all_data_idx = (
58
126
  {
59
127
  k: v if isinstance(v, list) else [v]
60
- for k, v in i.data_idx.items()
61
- if k not in ("repeats.",)
128
+ for k, v in store_ear.data_idx.items()
129
+ if not k.startswith("repeats.")
62
130
  }
63
- for i in all_store_runs
64
- ]
131
+ for store_ear in all_store_runs
132
+ )
65
133
 
66
134
  # run dependencies and dependents
67
- run_dependencies = {}
68
- run_dependents = defaultdict(set)
69
- for idx, i in enumerate(all_data_idx):
70
- run_i_sources = set()
71
- for j in i.values():
72
- for k in j:
73
- run_k = all_param_sources[k].get("EAR_ID")
74
- if run_k is not None and run_k != idx:
75
- run_i_sources.add(run_k)
135
+ run_dependencies: dict[int, set[int]] = {}
136
+ run_dependents: defaultdict[int, set[int]] = defaultdict(set)
137
+ for idx, dict_i in enumerate(all_data_idx):
138
+ run_i_sources = set(
139
+ run_k
140
+ for dat_idx_k in chain.from_iterable(dict_i.values())
141
+ if (run_k := all_param_sources[dat_idx_k].get("EAR_ID")) is not None
142
+ and run_k != idx
143
+ )
76
144
  run_dependencies[idx] = run_i_sources
77
145
  for m in run_i_sources:
78
146
  run_dependents[m].add(idx)
79
147
 
80
- # add missing:
81
- for k in range(num_runs):
82
- run_dependents[k]
83
-
84
- run_dependents = dict(run_dependents)
148
+ # add missing and downgrade to dict:
149
+ for run_idx in range(num_runs):
150
+ run_dependents[run_idx]
151
+ run_dependents.default_factory = None
85
152
 
86
153
  # iteration dependencies
87
154
  all_iter_run_IDs = {
88
- i.id_: [k for j in i.EAR_IDs.values() for k in j] for i in all_store_iters
155
+ iter_.id_: tuple(chain.from_iterable((iter_.EAR_IDs or {}).values()))
156
+ for iter_ in all_store_iters
89
157
  }
90
158
  # for each iteration, which runs does it depend on?
91
159
  iter_run_dependencies = {
92
- k: set(j for i in v for j in run_dependencies[i])
160
+ k: set(j for idx in v for j in run_dependencies[idx])
93
161
  for k, v in all_iter_run_IDs.items()
94
162
  }
95
163
 
96
164
  # for each run, which iteration does it belong to?
97
- all_run_iter_IDs = {}
98
- for iter_ID, run_IDs in all_iter_run_IDs.items():
99
- for run_ID in run_IDs:
100
- all_run_iter_IDs[run_ID] = iter_ID
165
+ all_run_iter_IDs = {
166
+ run_ID: iter_ID
167
+ for iter_ID, run_IDs in all_iter_run_IDs.items()
168
+ for run_ID in run_IDs
169
+ }
101
170
 
102
171
  # for each iteration, which iterations does it depend on?
103
172
  iter_iter_dependencies = {
@@ -105,52 +174,45 @@ class DependencyCache:
105
174
  for k, v in iter_run_dependencies.items()
106
175
  }
107
176
 
108
- all_elem_iter_IDs = {i.id_: i.iteration_IDs for i in all_store_elements}
177
+ all_elem_iter_IDs = {el.id_: el.iteration_IDs for el in all_store_elements}
109
178
 
110
179
  elem_iter_dependencies = {
111
- k: set(j for i in v for j in iter_iter_dependencies[i])
112
- for k, v in all_elem_iter_IDs.items()
180
+ elem_ID: set(j for i in iter_IDs for j in iter_iter_dependencies[i])
181
+ for elem_ID, iter_IDs in all_elem_iter_IDs.items()
113
182
  }
114
183
 
115
184
  # for each iteration, which element does it belong to?
116
- all_iter_elem_IDs = {}
117
- for elem_ID, iter_IDs in all_elem_iter_IDs.items():
118
- for iter_ID in iter_IDs:
119
- all_iter_elem_IDs[iter_ID] = elem_ID
185
+ all_iter_elem_IDs = {
186
+ iter_ID: elem_ID
187
+ for elem_ID, iter_IDs in all_elem_iter_IDs.items()
188
+ for iter_ID in iter_IDs
189
+ }
120
190
 
121
191
  # element dependencies
122
192
  elem_elem_dependencies = {
123
- k: set(all_iter_elem_IDs[i] for i in v)
124
- for k, v in elem_iter_dependencies.items()
193
+ k: set(all_iter_elem_IDs[i] for i in dep_set)
194
+ for k, dep_set in elem_iter_dependencies.items()
125
195
  }
126
196
 
127
197
  # for each element, which elements depend on it (directly)?
128
- elem_elem_dependents = defaultdict(set)
129
- for k, v in elem_elem_dependencies.items():
130
- for i in v:
198
+ elem_elem_dependents: defaultdict[int, set[int]] = defaultdict(set)
199
+ for k, dep_set in elem_elem_dependencies.items():
200
+ for i in dep_set:
131
201
  elem_elem_dependents[i].add(k)
132
202
 
133
203
  # for each element, which elements depend on it (recursively)?
134
- elem_elem_dependents_rec = defaultdict(set)
135
- for k in list(elem_elem_dependents):
136
- for i in elem_elem_dependents[k]:
137
- elem_elem_dependents_rec[k].add(i)
138
- elem_elem_dependents_rec[k].update(
139
- {m for m in elem_elem_dependents[i] if m != k}
140
- )
141
-
142
- # add missing keys:
143
- for k in range(num_elems):
144
- elem_elem_dependents[k]
145
- elem_elem_dependents_rec[k]
146
-
147
- elem_elem_dependents = dict(elem_elem_dependents)
148
- elem_elem_dependents_rec = dict(elem_elem_dependents_rec)
149
-
150
- elements = workflow.get_all_elements()
151
- iterations = workflow.get_all_element_iterations()
152
-
153
- return cls(
204
+ elem_elem_dependents_rec: defaultdict[int, set[int]] = defaultdict(set)
205
+ for i in list(elem_elem_dependents):
206
+ elem_elem_dependents_rec[i] = _get_recursive_deps(i)
207
+
208
+ # add missing keys and downgrade to dict:
209
+ for elem_idx in range(num_elems):
210
+ elem_elem_dependents[elem_idx]
211
+ elem_elem_dependents_rec[elem_idx]
212
+ elem_elem_dependents.default_factory = None
213
+ elem_elem_dependents_rec.default_factory = None
214
+
215
+ return dict(
154
216
  run_dependencies=run_dependencies,
155
217
  run_dependents=run_dependents,
156
218
  iter_run_dependencies=iter_run_dependencies,
@@ -159,6 +221,4 @@ class DependencyCache:
159
221
  elem_elem_dependencies=elem_elem_dependencies,
160
222
  elem_elem_dependents=elem_elem_dependents,
161
223
  elem_elem_dependents_rec=elem_elem_dependents_rec,
162
- elements=elements,
163
- iterations=iterations,
164
224
  )