easylink 0.1.10__tar.gz → 0.1.11__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 (173) hide show
  1. {easylink-0.1.10 → easylink-0.1.11}/CHANGELOG.rst +4 -0
  2. {easylink-0.1.10/src/easylink.egg-info → easylink-0.1.11}/PKG-INFO +1 -1
  3. easylink-0.1.11/src/easylink/_version.py +1 -0
  4. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/pipeline_schema.py +21 -1
  5. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/step.py +119 -71
  6. {easylink-0.1.10 → easylink-0.1.11/src/easylink.egg-info}/PKG-INFO +1 -1
  7. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_step.py +37 -30
  8. easylink-0.1.10/src/easylink/_version.py +0 -1
  9. {easylink-0.1.10 → easylink-0.1.11}/.bandit +0 -0
  10. {easylink-0.1.10 → easylink-0.1.11}/.flake8 +0 -0
  11. {easylink-0.1.10 → easylink-0.1.11}/.github/CODEOWNERS +0 -0
  12. {easylink-0.1.10 → easylink-0.1.11}/.github/pull_request_template.md +0 -0
  13. {easylink-0.1.10 → easylink-0.1.11}/.github/workflows/deploy.yml +0 -0
  14. {easylink-0.1.10 → easylink-0.1.11}/.github/workflows/update_readme.yml +0 -0
  15. {easylink-0.1.10 → easylink-0.1.11}/.gitignore +0 -0
  16. {easylink-0.1.10 → easylink-0.1.11}/.readthedocs.yml +0 -0
  17. {easylink-0.1.10 → easylink-0.1.11}/Jenkinsfile +0 -0
  18. {easylink-0.1.10 → easylink-0.1.11}/Makefile +0 -0
  19. {easylink-0.1.10 → easylink-0.1.11}/README.rst +0 -0
  20. {easylink-0.1.10 → easylink-0.1.11}/docs/Makefile +0 -0
  21. {easylink-0.1.10 → easylink-0.1.11}/docs/nitpick-exceptions +0 -0
  22. {easylink-0.1.10 → easylink-0.1.11}/docs/source/_static/style.css +0 -0
  23. {easylink-0.1.10 → easylink-0.1.11}/docs/source/_templates/layout.html +0 -0
  24. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/cli.rst +0 -0
  25. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/configuration.rst +0 -0
  26. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/graph_components.rst +0 -0
  27. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/implementation.rst +0 -0
  28. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/index.rst +0 -0
  29. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/pipeline.rst +0 -0
  30. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/pipeline_graph.rst +0 -0
  31. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/pipeline_schema.rst +0 -0
  32. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/pipeline_schema_constants/development.rst +0 -0
  33. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/pipeline_schema_constants/index.rst +0 -0
  34. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/pipeline_schema_constants/testing.rst +0 -0
  35. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/rule.rst +0 -0
  36. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/runner.rst +0 -0
  37. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/step.rst +0 -0
  38. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/utilities/aggregator_utils.rst +0 -0
  39. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/utilities/data_utils.rst +0 -0
  40. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/utilities/general_utils.rst +0 -0
  41. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/utilities/index.rst +0 -0
  42. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/utilities/paths.rst +0 -0
  43. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/utilities/splitter_utils.rst +0 -0
  44. {easylink-0.1.10 → easylink-0.1.11}/docs/source/api_reference/utilities/validation_utils.rst +0 -0
  45. {easylink-0.1.10 → easylink-0.1.11}/docs/source/concepts/index.rst +0 -0
  46. {easylink-0.1.10 → easylink-0.1.11}/docs/source/concepts/pipeline_schema/index.rst +0 -0
  47. {easylink-0.1.10 → easylink-0.1.11}/docs/source/conf.py +0 -0
  48. {easylink-0.1.10 → easylink-0.1.11}/docs/source/glossary.rst +0 -0
  49. {easylink-0.1.10 → easylink-0.1.11}/docs/source/index.rst +0 -0
  50. {easylink-0.1.10 → easylink-0.1.11}/docs/source/user_guide/cli.rst +0 -0
  51. {easylink-0.1.10 → easylink-0.1.11}/docs/source/user_guide/index.rst +0 -0
  52. {easylink-0.1.10 → easylink-0.1.11}/docs/source/user_guide/tutorials/getting_started.rst +0 -0
  53. {easylink-0.1.10 → easylink-0.1.11}/docs/source/user_guide/tutorials/index.rst +0 -0
  54. {easylink-0.1.10 → easylink-0.1.11}/pyproject.toml +0 -0
  55. {easylink-0.1.10 → easylink-0.1.11}/python_versions.json +0 -0
  56. {easylink-0.1.10 → easylink-0.1.11}/pytype.cfg +0 -0
  57. {easylink-0.1.10 → easylink-0.1.11}/setup.cfg +0 -0
  58. {easylink-0.1.10 → easylink-0.1.11}/setup.py +0 -0
  59. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/__about__.py +0 -0
  60. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/__init__.py +0 -0
  61. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/cli.py +0 -0
  62. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/configuration.py +0 -0
  63. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/graph_components.py +0 -0
  64. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/images/spark_cluster/Dockerfile +0 -0
  65. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/images/spark_cluster/README.md +0 -0
  66. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/implementation.py +0 -0
  67. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/implementation_metadata.yaml +0 -0
  68. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/pipeline.py +0 -0
  69. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/pipeline_graph.py +0 -0
  70. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/pipeline_schema_constants/__init__.py +0 -0
  71. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/pipeline_schema_constants/development.py +0 -0
  72. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/pipeline_schema_constants/testing.py +0 -0
  73. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/rule.py +0 -0
  74. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/runner.py +0 -0
  75. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/README.md +0 -0
  76. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/build-containers-local.sh +0 -0
  77. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/build-containers-remote.sh +0 -0
  78. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/input_data/create_input_files.ipynb +0 -0
  79. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/input_data/input_file_1.csv +0 -0
  80. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/input_data/input_file_1.parquet +0 -0
  81. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/input_data/input_file_2.csv +0 -0
  82. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/input_data/input_file_2.parquet +0 -0
  83. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/python_pandas/README.md +0 -0
  84. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/python_pandas/dummy_step.py +0 -0
  85. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/python_pandas/python_pandas.def +0 -0
  86. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/python_pyspark/README.md +0 -0
  87. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/python_pyspark/dummy_step.py +0 -0
  88. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/python_pyspark/python_pyspark.def +0 -0
  89. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/r/README.md +0 -0
  90. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/r/dummy_step.R +0 -0
  91. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/r/r-image.def +0 -0
  92. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/steps/dev/test.py +0 -0
  93. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/utilities/__init__.py +0 -0
  94. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/utilities/aggregator_utils.py +0 -0
  95. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/utilities/data_utils.py +0 -0
  96. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/utilities/general_utils.py +0 -0
  97. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/utilities/paths.py +0 -0
  98. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/utilities/spark.smk +0 -0
  99. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/utilities/splitter_utils.py +0 -0
  100. {easylink-0.1.10 → easylink-0.1.11}/src/easylink/utilities/validation_utils.py +0 -0
  101. {easylink-0.1.10 → easylink-0.1.11}/src/easylink.egg-info/SOURCES.txt +0 -0
  102. {easylink-0.1.10 → easylink-0.1.11}/src/easylink.egg-info/dependency_links.txt +0 -0
  103. {easylink-0.1.10 → easylink-0.1.11}/src/easylink.egg-info/entry_points.txt +0 -0
  104. {easylink-0.1.10 → easylink-0.1.11}/src/easylink.egg-info/not-zip-safe +0 -0
  105. {easylink-0.1.10 → easylink-0.1.11}/src/easylink.egg-info/requires.txt +0 -0
  106. {easylink-0.1.10 → easylink-0.1.11}/src/easylink.egg-info/top_level.txt +0 -0
  107. {easylink-0.1.10 → easylink-0.1.11}/tests/__init__.py +0 -0
  108. {easylink-0.1.10 → easylink-0.1.11}/tests/conftest.py +0 -0
  109. {easylink-0.1.10 → easylink-0.1.11}/tests/e2e/test_easylink_run.py +0 -0
  110. {easylink-0.1.10 → easylink-0.1.11}/tests/e2e/test_step_types.py +0 -0
  111. {easylink-0.1.10 → easylink-0.1.11}/tests/integration/test_snakemake.py +0 -0
  112. {easylink-0.1.10 → easylink-0.1.11}/tests/integration/test_snakemake_slurm.py +0 -0
  113. {easylink-0.1.10 → easylink-0.1.11}/tests/integration/test_snakemake_spark.py +0 -0
  114. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/common/environment_local.yaml +0 -0
  115. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/common/input_data.yaml +0 -0
  116. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/common/pipeline.yaml +0 -0
  117. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/e2e/environment_slurm.yaml +0 -0
  118. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/e2e/pipeline.yaml +0 -0
  119. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/e2e/pipeline_expanded.yaml +0 -0
  120. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/integration/environment_spark_slurm.yaml +0 -0
  121. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/integration/pipeline.yaml +0 -0
  122. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/integration/pipeline_spark.yaml +0 -0
  123. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/environment_minimum.yaml +0 -0
  124. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/environment_spark_slurm.yaml +0 -0
  125. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline.yaml +0 -0
  126. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_bad_combined_implementations.yaml +0 -0
  127. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_bad_implementation.yaml +0 -0
  128. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_bad_loop_formatting.yaml +0 -0
  129. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_bad_step.yaml +0 -0
  130. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_bad_type_key.yaml +0 -0
  131. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_combine_bad_implementation_names.yaml +0 -0
  132. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_combine_bad_topology.yaml +0 -0
  133. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_combine_two_steps.yaml +0 -0
  134. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_combine_with_extra_node.yaml +0 -0
  135. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_combine_with_iteration.yaml +0 -0
  136. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_combine_with_iteration_cycle.yaml +0 -0
  137. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_combine_with_missing_node.yaml +0 -0
  138. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_combine_with_parallel.yaml +0 -0
  139. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_missing_implementation_name.yaml +0 -0
  140. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_missing_implementations.yaml +0 -0
  141. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_missing_loop_nodes.yaml +0 -0
  142. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_missing_step.yaml +0 -0
  143. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_missing_substeps.yaml +0 -0
  144. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_missing_type_key.yaml +0 -0
  145. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_nested_templated_steps.yaml +0 -0
  146. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_out_of_order.yaml +0 -0
  147. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_spark.yaml +0 -0
  148. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_type_config_mismatch.yaml +0 -0
  149. {easylink-0.1.10 → easylink-0.1.11}/tests/specifications/unit/pipeline_wrong_parallel_split_keys.yaml +0 -0
  150. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/__init__.py +0 -0
  151. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/conftest.py +0 -0
  152. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/rule_strings/aggregation_rule.txt +0 -0
  153. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/rule_strings/checkpoint_rule.txt +0 -0
  154. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/rule_strings/embarrassingly_parallel_rule.txt +0 -0
  155. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/rule_strings/implemented_rule_local.txt +0 -0
  156. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/rule_strings/implemented_rule_slurm.txt +0 -0
  157. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/rule_strings/pipeline_local.txt +0 -0
  158. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/rule_strings/pipeline_slurm.txt +0 -0
  159. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/rule_strings/target_rule.txt +0 -0
  160. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/rule_strings/validation_rule.txt +0 -0
  161. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_cli.py +0 -0
  162. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_config.py +0 -0
  163. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_data_utils.py +0 -0
  164. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_general_utils.py +0 -0
  165. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_graph_components.py +0 -0
  166. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_implementation.py +0 -0
  167. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_pipeline.py +0 -0
  168. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_pipeline_graph.py +0 -0
  169. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_pipeline_schema.py +0 -0
  170. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_rule.py +0 -0
  171. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_runner.py +0 -0
  172. {easylink-0.1.10 → easylink-0.1.11}/tests/unit/test_validations.py +0 -0
  173. {easylink-0.1.10 → easylink-0.1.11}/update_readme.py +0 -0
@@ -1,3 +1,7 @@
1
+ **0.1.11 - 3/28/25**
2
+
3
+ - Refactor the ImplementationGraph recursion logic for clarity
4
+
1
5
  **0.1.10 - 3/25/25**
2
6
 
3
7
  - Make InputSlots and OutputSlots mutable
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easylink
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: Research repository for the EasyLink ER ecosystem project.
5
5
  Home-page: https://github.com/ihmeuw/easylink
6
6
  Author: The EasyLink developers
@@ -0,0 +1 @@
1
+ __version__ = "0.1.11"
@@ -13,7 +13,7 @@ from pathlib import Path
13
13
 
14
14
  from layered_config_tree import LayeredConfigTree
15
15
 
16
- from easylink.graph_components import EdgeParams
16
+ from easylink.graph_components import EdgeParams, ImplementationGraph
17
17
  from easylink.pipeline_schema_constants import ALLOWED_SCHEMA_PARAMS
18
18
  from easylink.step import HierarchicalStep, NonLeafConfigurationState, Step
19
19
 
@@ -54,6 +54,26 @@ class PipelineSchema(HierarchicalStep):
54
54
  def __repr__(self) -> str:
55
55
  return f"PipelineSchema.{self.name}"
56
56
 
57
+ def get_implementation_graph(self) -> ImplementationGraph:
58
+ """Gets the :class:`~easylink.graph_components.ImplementationGraph`.
59
+
60
+ The ``PipelineSchema`` is by definition a :class:`~easylink.step.HierarchicalStep`
61
+ which has a :class:`~easylink.graph_components.StepGraph` containing
62
+ sub-:class:`Steps<easylink.step.Step>` that need to be unrolled. This method
63
+ recursively traverses that ``StepGraph`` and its childrens' ``StepGraphs``
64
+ until all sub-``Steps`` are in a :class:`~easylink.step.LeafConfigurationState`,
65
+ i.e. all ``Steps`` are implemented by a single ``Implementation`` and we
66
+ have the desired ``ImplementationGraph``.
67
+
68
+ Returns
69
+ -------
70
+ The ``ImplementationGraph`` of this ``PipelineSchema``.
71
+ """
72
+ implementation_graph = ImplementationGraph()
73
+ self.add_nodes_to_implementation_graph(implementation_graph)
74
+ self.add_edges_to_implementation_graph(implementation_graph)
75
+ return implementation_graph
76
+
57
77
  def validate_step(
58
78
  self, pipeline_config: LayeredConfigTree, input_data_config: LayeredConfigTree
59
79
  ) -> dict[str, list[str]]:
@@ -15,7 +15,6 @@ import copy
15
15
  from abc import ABC, abstractmethod
16
16
  from collections import defaultdict
17
17
  from collections.abc import Iterable
18
- from typing import Any
19
18
 
20
19
  from layered_config_tree import LayeredConfigTree
21
20
 
@@ -250,18 +249,25 @@ class Step:
250
249
  ]
251
250
  return errors
252
251
 
253
- def get_implementation_graph(self) -> ImplementationGraph:
254
- """Gets this ``Step's`` :class:`~easylink.graph_components.ImplementationGraph`.
252
+ def add_nodes_to_implementation_graph(
253
+ self, implementation_graph: ImplementationGraph
254
+ ) -> None:
255
+ """Adds the ``Implementations`` related to this ``Step`` as nodes to the :class:`~easylink.graph_components.ImplementationGraph`.
255
256
 
256
- The ``ImplementationGraph`` and how it is determined depends on whether
257
- this ``Step`` is a leaf or a non-leaf, i.e. what its :attr:`configuration_state`
258
- is.
257
+ How the nodes get added depends on whether this ``Step`` is a leaf or a non-leaf,
258
+ i.e. what its :attr:`configuration_state` is.
259
+ """
260
+ self.configuration_state.add_nodes_to_implementation_graph(implementation_graph)
259
261
 
260
- Returns
261
- -------
262
- The ``ImplementationGraph`` of this ``Step`` based on its ``configuration_state``.
262
+ def add_edges_to_implementation_graph(
263
+ self, implementation_graph: ImplementationGraph
264
+ ) -> None:
265
+ """Adds the edges of this ``Step's`` ``Implementation(s)`` to the :class:`~easylink.graph_components.ImplementationGraph`.
266
+
267
+ How the edges get added depends on whether this ``Step`` is a leaf or a non-leaf,
268
+ i.e. what its :attr:`configuration_state` is.
263
269
  """
264
- return self.configuration_state.get_implementation_graph()
270
+ self.configuration_state.add_edges_to_implementation_graph(implementation_graph)
265
271
 
266
272
  def get_implementation_edges(self, edge: EdgeParams) -> list[EdgeParams]:
267
273
  """Gets the edge information for the ``Implementation`` related to this ``Step``.
@@ -387,7 +393,7 @@ class IOStep(Step):
387
393
  The internal configuration of this ``Step``, i.e. it should not include
388
394
  the ``Step's`` name.
389
395
  combined_implementations
390
- The configuration for any implementations to be combined.
396
+ The configuration for any ``Implementations`` to be combined.
391
397
  input_data_config
392
398
  The input data configuration for the entire pipeline.
393
399
  """
@@ -395,8 +401,10 @@ class IOStep(Step):
395
401
  self, step_config, combined_implementations, input_data_config
396
402
  )
397
403
 
398
- def get_implementation_graph(self) -> ImplementationGraph:
399
- """Gets this ``Step's`` :class:`~easylink.graph_components.ImplementationGraph`.
404
+ def add_nodes_to_implementation_graph(
405
+ self, implementation_graph: ImplementationGraph
406
+ ) -> None:
407
+ """Adds this ``IOStep's`` ``Implementation`` as a node to the :class:`~easylink.graph_components.ImplementationGraph`.
400
408
 
401
409
  Notes
402
410
  -----
@@ -404,19 +412,22 @@ class IOStep(Step):
404
412
  via an :class:`~easylink.implementation.Implementation`. As such, we
405
413
  leverage the :class:`~easylink.implementation.NullImplementation` class
406
414
  to generate the graph node.
407
-
408
- Returns
409
- -------
410
- The ``ImplementationGraph`` of this ``Step``.
411
415
  """
412
- implementation_graph = ImplementationGraph()
413
416
  implementation_graph.add_node_from_implementation(
414
417
  self.name,
415
418
  implementation=NullImplementation(
416
419
  self.name, self.input_slots.values(), self.output_slots.values()
417
420
  ),
418
421
  )
419
- return implementation_graph
422
+
423
+ def add_edges_to_implementation_graph(self, implementation_graph):
424
+ """Adds the edges of this ``Step's`` ``Implementation`` to the ``ImplementationGraph``.
425
+
426
+ ``IOSteps`` do not have edges within them in the ``ImplementationGraph``,
427
+ since they are represented by a single ``NullImplementation`` node, and so we
428
+ simply pass.
429
+ """
430
+ pass
420
431
 
421
432
 
422
433
  class InputStep(IOStep):
@@ -1394,8 +1405,17 @@ class ConfigurationState(ABC):
1394
1405
  """The input data configuration for the entire pipeline."""
1395
1406
 
1396
1407
  @abstractmethod
1397
- def get_implementation_graph(self) -> ImplementationGraph:
1398
- """Resolves the graph composed of ``Steps`` into one composed of ``Implementations``."""
1408
+ def add_nodes_to_implementation_graph(
1409
+ self, implementation_graph: ImplementationGraph
1410
+ ) -> None:
1411
+ """Adds this ``Step's`` ``Implementation(s)`` as nodes to the :class:`~easylink.graph_components.ImplementationGraph`."""
1412
+ pass
1413
+
1414
+ @abstractmethod
1415
+ def add_edges_to_implementation_graph(
1416
+ self, implementation_graph: ImplementationGraph
1417
+ ) -> None:
1418
+ """Adds the edges of this ``Step's`` ``Implementation(s)`` to the :class:`~easylink.graph_components.ImplementationGraph`."""
1399
1419
  pass
1400
1420
 
1401
1421
  @abstractmethod
@@ -1438,19 +1458,16 @@ class LeafConfigurationState(ConfigurationState):
1438
1458
  else self.step_config.implementation
1439
1459
  )
1440
1460
 
1441
- def get_implementation_graph(self) -> ImplementationGraph:
1442
- """Gets this ``Step's`` :class:`~easylink.graph_components.ImplementationGraph`.
1461
+ def add_nodes_to_implementation_graph(
1462
+ self, implementation_graph: ImplementationGraph
1463
+ ) -> None:
1464
+ """Adds this ``Step's`` :class:`~easylink.implementation.Implementation` as a node to the :class:`~easylink.graph_components.ImplementationGraph`.
1443
1465
 
1444
1466
  A ``Step`` in a leaf configuration state by definition has no sub-``Steps``
1445
1467
  to unravel; we are able to directly instantiate an :class:`~easylink.implementation.Implementation`
1446
- and generate an ``ImplementationGraph`` from it.
1447
-
1448
- Returns
1449
- -------
1450
- The ``ImplementationGraph`` related to this ``Step``.
1468
+ and add it to the ``ImplementationGraph``.
1451
1469
  """
1452
1470
  step = self._step
1453
- implementation_graph = ImplementationGraph()
1454
1471
  if self.is_combined:
1455
1472
  if isinstance(step, EmbarrassinglyParallelStep):
1456
1473
  raise NotImplementedError(
@@ -1475,7 +1492,15 @@ class LeafConfigurationState(ConfigurationState):
1475
1492
  step.implementation_node_name,
1476
1493
  implementation=implementation,
1477
1494
  )
1478
- return implementation_graph
1495
+
1496
+ def add_edges_to_implementation_graph(self, implementation_graph) -> None:
1497
+ """Adds the edges for this ``Step's`` ``Implementation`` to the ``ImplementationGraph``.
1498
+
1499
+ ``Steps`` in a ``LeafConfigurationState`` do not actually have edges within them
1500
+ (they are represented by a single node in the ``ImplementationGraph``) and so
1501
+ we simply pass.
1502
+ """
1503
+ pass
1479
1504
 
1480
1505
  def get_implementation_edges(self, edge: EdgeParams) -> list[EdgeParams]:
1481
1506
  """Gets the edge information for the ``Implementation`` related to this ``Step``.
@@ -1543,7 +1568,8 @@ class NonLeafConfigurationState(ConfigurationState):
1543
1568
  for; it should not include the ``Step's`` name (though it must include
1544
1569
  the sub-step names).
1545
1570
  combined_implementations
1546
- The configuration for any implementations to be combined.
1571
+ The configuration for any :class:`Implementations<easylink.implementation.Implementation>`
1572
+ to be combined.
1547
1573
  input_data_config
1548
1574
  The input data configuration for the entire pipeline.
1549
1575
 
@@ -1585,61 +1611,62 @@ class NonLeafConfigurationState(ConfigurationState):
1585
1611
  self._nodes = step.step_graph.nodes
1586
1612
  self._configure_subgraph_steps()
1587
1613
 
1588
- def get_implementation_graph(self) -> ImplementationGraph:
1589
- """Gets this ``Step's`` :class:`~easylink.graph_components.ImplementationGraph`.
1614
+ def add_nodes_to_implementation_graph(
1615
+ self, implementation_graph: ImplementationGraph
1616
+ ) -> None:
1617
+ """Adds this ``Step's`` ``Implementations`` as nodes to the ``ImplementationGraph``.
1590
1618
 
1591
- A ``Step`` in a non-leaf configuration state by definition has a ``StepGraph``
1592
- containing sub-``Steps`` that need to be unrolled. This method recursively
1593
- traverses that ``StepGraph`` and its childrens' ``StepGraphs`` until all
1594
- sub-``Steps`` are in a :class:`LeafConfigurationState`, i.e. all ``Steps``
1595
- are implemented by a single ``Implementation`` and we have our desired
1596
- ``ImplementationGraph``.
1619
+ This is a recursive function; it calls itself until all sub-``Steps``
1620
+ are of a ``LeafConfigurationState`` and have had their corresponding
1621
+ ``Implementations`` added as nodes to the ``ImplementationGraph``.
1622
+ """
1623
+ for node in self._step.step_graph.nodes:
1624
+ substep = self._step.step_graph.nodes[node]["step"]
1625
+ substep.add_nodes_to_implementation_graph(implementation_graph)
1597
1626
 
1598
- Returns
1599
- -------
1600
- The ``ImplementationGraph`` of this ``Step``.
1627
+ def add_edges_to_implementation_graph(
1628
+ self, implementation_graph: ImplementationGraph
1629
+ ) -> None:
1630
+ """Adds the edges of this ``Step's`` ``Implementations`` to the ``ImplementationGraph``.
1601
1631
 
1602
- Notes
1603
- -----
1604
- This method is first called on the entire :class:`~easylink.pipeline_schema.PipelineSchema`
1605
- when constructing the :class:`~easylink.pipeline_graph.PipelineGraph`
1606
- to run.
1632
+ This method does two things:
1633
+ 1. Adds the edges *at this level* (i.e. at the ``Step`` tied to this
1634
+ ``NonLeafConfigurationState``) to the ``ImplementationGraph``.
1635
+ 2. Recursively traverses all sub-steps and adds their edges to the
1636
+ ``ImplementationGraph``.
1607
1637
 
1638
+ Note that to achieve (1), edges must be mapped from being between steps at
1639
+ this level of the hierarchy, all the way down to being between concrete implementations.
1640
+ Mapping each edge down to the implementation level is *itself* a recursive
1641
+ operation (see ``get_implementation_edges``).
1608
1642
  """
1609
- implementation_graph = ImplementationGraph()
1610
- self.add_nodes(implementation_graph)
1611
- self.add_edges(implementation_graph)
1612
- return implementation_graph
1613
-
1614
- def add_nodes(self, implementation_graph: ImplementationGraph) -> None:
1615
- """Adds nodes for each ``Step`` to the ``ImplementationGraph``."""
1616
- for node in self._nodes:
1617
- step = self._nodes[node]["step"]
1618
- implementation_graph.update(step.get_implementation_graph())
1619
-
1620
- def add_edges(self, implementation_graph: ImplementationGraph) -> None:
1621
- """Adds the edges to the ``ImplementationGraph``."""
1643
+ # Add the edges at this level (i.e. the edges at this `self._step`)
1622
1644
  for source, target, edge_attrs in self._step.step_graph.edges(data=True):
1623
- all_edges = []
1624
1645
  edge = EdgeParams.from_graph_edge(source, target, edge_attrs)
1625
- parent_source_step = self._nodes[source]["step"]
1626
- parent_target_step = self._nodes[target]["step"]
1646
+ source_step = self._nodes[source]["step"]
1647
+ target_step = self._nodes[target]["step"]
1627
1648
 
1628
- source_edges = parent_source_step.get_implementation_edges(edge)
1649
+ source_edges = source_step.get_implementation_edges(edge)
1629
1650
  for source_edge in source_edges:
1630
- for target_edge in parent_target_step.get_implementation_edges(source_edge):
1631
- all_edges.append(target_edge)
1651
+ for target_edge in target_step.get_implementation_edges(source_edge):
1652
+ implementation_graph.add_edge_from_params(target_edge)
1632
1653
 
1633
- for edge in all_edges:
1634
- implementation_graph.add_edge_from_params(edge)
1654
+ # Recurse through all sub-steps and add the edges between them
1655
+ for node in self._step.step_graph.nodes:
1656
+ substep = self._step.step_graph.nodes[node]["step"]
1657
+ substep.add_edges_to_implementation_graph(implementation_graph)
1635
1658
 
1636
1659
  def get_implementation_edges(self, edge: EdgeParams) -> list[EdgeParams]:
1637
- """Gets the edge information for the ``Implementation`` related to this ``Step``.
1660
+ """Gets the edges for the ``Implementation`` related to this ``Step``.
1661
+
1662
+ This method maps an edge between ``Steps`` in this ``Step's`` ``StepGraph``
1663
+ to one or more edges between ``Implementations`` by applying ``SlotMappings``.
1638
1664
 
1639
1665
  Parameters
1640
1666
  ----------
1641
1667
  edge
1642
- The ``Step's`` edge information to be propagated to the ``ImplementationGraph``.
1668
+ The edge information of the edge in the ``StepGraph`` to be mapped to
1669
+ the ``Implementation`` level.
1643
1670
 
1644
1671
  Raises
1645
1672
  ------
@@ -1648,7 +1675,28 @@ class NonLeafConfigurationState(ConfigurationState):
1648
1675
 
1649
1676
  Returns
1650
1677
  -------
1651
- The ``Implementation's`` edge information.
1678
+ A list of edges between ``Implementations`` which are ready to add to
1679
+ the ``ImplementationGraph``.
1680
+
1681
+ Notes
1682
+ -----
1683
+ In EasyLink, an edge (in either a ``StepGraph`` or ``ImplementationGraph``)
1684
+ sconnects two ``Slot``.
1685
+
1686
+ The core of this method is to map the ``Slots`` on the ``StepGraph`` edge
1687
+ to the corresponding ``Slots`` on ``Implementations``.
1688
+
1689
+ At each level in the step hierarchy, ``SlotMappings`` indicate how to map
1690
+ a ``Slot`` to the level below in the hierarchy.
1691
+
1692
+ This method recurses through the step hierarchy until it reaches the leaf
1693
+ ``Steps`` relevant to this edge in order to compose all the ``SlotMappings``
1694
+ that should apply to it.
1695
+
1696
+ Because a single ``Step`` can become multiple nodes in the ``ImplementationGraph``
1697
+ (e.g. a :class:`TemplatedStep`), a single edge between ``Steps`` may actually
1698
+ become multiple edges between ``Implementations``, which is why this method
1699
+ can return a list.
1652
1700
  """
1653
1701
  implementation_edges = []
1654
1702
  if edge.source_node == self._step.name:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easylink
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: Research repository for the EasyLink ER ecosystem project.
5
5
  Home-page: https://github.com/ihmeuw/easylink
6
6
  Author: The EasyLink developers
@@ -17,6 +17,7 @@ from layered_config_tree import LayeredConfigTree
17
17
  from easylink.configuration import Config
18
18
  from easylink.graph_components import (
19
19
  EdgeParams,
20
+ ImplementationGraph,
20
21
  InputSlot,
21
22
  InputSlotMapping,
22
23
  OutputSlot,
@@ -85,11 +86,9 @@ def test_io_step_slots(io_step_params: dict[str, Any]) -> None:
85
86
  assert step.output_slots == {"file1": OutputSlot("file1")}
86
87
 
87
88
 
88
- def test_io_get_implementation_graph(
89
- io_step_params: dict[str, Any], default_config: Config
90
- ) -> None:
89
+ def test_io_implementation_graph(io_step_params: dict[str, Any]) -> None:
91
90
  step = IOStep(**io_step_params)
92
- subgraph = step.get_implementation_graph()
91
+ subgraph = _create_implementation_graph(step)
93
92
  assert list(subgraph.nodes) == ["io"]
94
93
  assert list(subgraph.edges) == []
95
94
 
@@ -107,12 +106,12 @@ def test_basic_step_slots(basic_step_params: dict[str, Any]) -> None:
107
106
  assert step.output_slots == {"step_1_main_output": OutputSlot("step_1_main_output")}
108
107
 
109
108
 
110
- def test_basic_step_get_implementation_graph(
109
+ def test_basic_step_implementation_graph(
111
110
  basic_step_params: dict[str, Any], default_config: Config
112
111
  ) -> None:
113
112
  step = Step(**basic_step_params)
114
113
  step.set_configuration_state(default_config["pipeline"]["steps"][step.name], {}, {})
115
- subgraph = step.get_implementation_graph()
114
+ subgraph = _create_implementation_graph(step)
116
115
  assert list(subgraph.nodes) == ["step_1_python_pandas"]
117
116
  assert list(subgraph.edges) == []
118
117
 
@@ -178,7 +177,7 @@ def test_hierarchical_step_slots(hierarchical_step_params: dict[str, Any]) -> No
178
177
  assert step.output_slots == {"step_4_main_output": OutputSlot("step_4_main_output")}
179
178
 
180
179
 
181
- def test_hierarchical_step_get_implementation_graph(
180
+ def test_hierarchical_step_implementation_graph(
182
181
  hierarchical_step_params: dict[str, Any]
183
182
  ) -> None:
184
183
  step = HierarchicalStep(**hierarchical_step_params)
@@ -186,11 +185,11 @@ def test_hierarchical_step_get_implementation_graph(
186
185
  {"implementation": {"name": "step_4_python_pandas", "configuration": {}}}
187
186
  )
188
187
  step.set_configuration_state(step_config, {}, {})
189
- subgraph = step.get_implementation_graph()
188
+ subgraph = _create_implementation_graph(step)
190
189
  assert list(subgraph.nodes) == ["step_4_python_pandas"]
191
190
  assert list(subgraph.edges) == []
192
191
 
193
- # Test get_implementation_graph for substeps
192
+ # Test implementation_graph for substeps
194
193
  step_config = LayeredConfigTree(
195
194
  {
196
195
  "substeps": {
@@ -210,7 +209,7 @@ def test_hierarchical_step_get_implementation_graph(
210
209
  }
211
210
  )
212
211
  step.set_configuration_state(step_config, {}, {})
213
- subgraph = step.get_implementation_graph()
212
+ subgraph = _create_implementation_graph(step)
214
213
  assert list(subgraph.nodes) == [
215
214
  "step_4a_python_pandas",
216
215
  "step_4b_python_pandas",
@@ -357,14 +356,14 @@ def test_loop_step_slots(loop_step_params: dict[str, Any]) -> None:
357
356
  ]
358
357
 
359
358
 
360
- def test_loop_get_implementation_graph(
359
+ def test_loop_implementation_graph(
361
360
  mocker, loop_step_params: dict[str, Any], default_config: Config
362
361
  ) -> None:
363
362
  mocker.patch("easylink.implementation.Implementation._load_metadata")
364
363
  mocker.patch("easylink.implementation.Implementation.validate", return_value=[])
365
364
  step = LoopStep(**loop_step_params)
366
365
  step.set_configuration_state(default_config["pipeline"]["steps"][step.name], {}, {})
367
- subgraph = step.get_implementation_graph()
366
+ subgraph = _create_implementation_graph(step)
368
367
  assert list(subgraph.nodes) == ["step_3_python_pandas"]
369
368
  assert list(subgraph.edges) == []
370
369
 
@@ -397,7 +396,7 @@ def test_loop_get_implementation_graph(
397
396
  },
398
397
  )
399
398
  step.set_configuration_state(step_config, {}, {})
400
- subgraph = step.get_implementation_graph()
399
+ subgraph = _create_implementation_graph(step)
401
400
  assert list(subgraph.nodes) == [
402
401
  "step_3_loop_1_step_3_python_pandas",
403
402
  "step_3_loop_2_step_3a_step_3a_python_pandas",
@@ -512,7 +511,7 @@ def test_parallel_step_slots(parallel_step_params: dict[str, Any]) -> None:
512
511
  assert step.output_slots == {"step_1_main_output": OutputSlot("step_1_main_output")}
513
512
 
514
513
 
515
- def test_parallel_step_get_implementation_graph(
514
+ def test_parallel_step_implementation_graph(
516
515
  mocker, parallel_step_params: dict[str, Any]
517
516
  ) -> None:
518
517
  mocker.patch("easylink.implementation.Implementation._load_metadata")
@@ -570,7 +569,7 @@ def test_parallel_step_get_implementation_graph(
570
569
  },
571
570
  )
572
571
  step.set_configuration_state(step_config, {}, {})
573
- subgraph = step.get_implementation_graph()
572
+ subgraph = _create_implementation_graph(step)
574
573
  assert set(subgraph.nodes) == {
575
574
  "step_1_parallel_split_1_step_1a_step_1a_python_pandas",
576
575
  "step_1_parallel_split_1_step_1b_step_1b_python_pandas",
@@ -626,7 +625,7 @@ def test_parallel_step_get_implementation_graph(
626
625
 
627
626
 
628
627
  @pytest.mark.parametrize("step_type", ["parallel", "loop"])
629
- def test_templated_get_implementation_graph_no_multiplicity(
628
+ def test_templated_implementation_graph_no_multiplicity(
630
629
  step_type, parallel_step_params: dict[str, Any], loop_step_params: dict[str, Any], mocker
631
630
  ) -> None:
632
631
  """Tests that we can handle TemplatedStep but with no multiplicity."""
@@ -655,7 +654,7 @@ def test_templated_get_implementation_graph_no_multiplicity(
655
654
  },
656
655
  )
657
656
  step.set_configuration_state(step_config, {}, {})
658
- subgraph = step.get_implementation_graph()
657
+ subgraph = _create_implementation_graph(step)
659
658
  assert set(subgraph.nodes) == {
660
659
  f"{step.name}a_python_pandas",
661
660
  f"{step.name}b_python_pandas",
@@ -967,12 +966,10 @@ def test_choice_step_slots(choice_step_params: dict[str, Any]) -> None:
967
966
  }
968
967
 
969
968
 
970
- def test_simple_choice_step_get_implementation_graph(
971
- choice_step_params: dict[str, Any]
972
- ) -> None:
969
+ def test_simple_choice_step_implementation_graph(choice_step_params: dict[str, Any]) -> None:
973
970
  step = ChoiceStep(**choice_step_params)
974
971
 
975
- # Test get_implementation_graph for single step (no substeps)
972
+ # Test implementation_graph for single step (no substeps)
976
973
  step_config = LayeredConfigTree(
977
974
  {
978
975
  "type": "simple",
@@ -986,11 +983,11 @@ def test_simple_choice_step_get_implementation_graph(
986
983
  # Need to validate in order to set the step graph an mappings prior to calling `set_configuration_state`
987
984
  step.validate_step(step_config, {}, {})
988
985
  step.set_configuration_state(step_config, {}, {})
989
- subgraph = step.get_implementation_graph()
986
+ subgraph = _create_implementation_graph(step)
990
987
  assert list(subgraph.nodes) == ["step_4_python_pandas"]
991
988
  assert list(subgraph.edges) == []
992
989
 
993
- # Test get_implementation_graph for a step with substeps
990
+ # Test implementation_graph for a step with substeps
994
991
  step_config = LayeredConfigTree(
995
992
  {
996
993
  "type": "simple",
@@ -1011,7 +1008,7 @@ def test_simple_choice_step_get_implementation_graph(
1011
1008
  }
1012
1009
  )
1013
1010
  step.set_configuration_state(step_config, {}, {})
1014
- subgraph = step.get_implementation_graph()
1011
+ subgraph = _create_implementation_graph(step)
1015
1012
  assert list(subgraph.nodes) == [
1016
1013
  "step_4a_python_pandas",
1017
1014
  "step_4b_r",
@@ -1036,9 +1033,7 @@ def test_simple_choice_step_get_implementation_graph(
1036
1033
  assert edge in subgraph.edges(data=True)
1037
1034
 
1038
1035
 
1039
- def test_complex_choice_step_get_implementation_graph(
1040
- choice_step_params: dict[str, Any]
1041
- ) -> None:
1036
+ def test_complex_choice_step_implementation_graph(choice_step_params: dict[str, Any]) -> None:
1042
1037
  step = ChoiceStep(**choice_step_params)
1043
1038
 
1044
1039
  step_config = LayeredConfigTree(
@@ -1072,7 +1067,7 @@ def test_complex_choice_step_get_implementation_graph(
1072
1067
  # Need to validate in order to set the step graph and mappings prior to calling `set_configuration_state`
1073
1068
  step.validate_step(step_config, {}, {})
1074
1069
  step.set_configuration_state(step_config, {}, {})
1075
- subgraph = step.get_implementation_graph()
1070
+ subgraph = _create_implementation_graph(step)
1076
1071
  assert list(subgraph.nodes) == [
1077
1072
  "step_5_python_pandas",
1078
1073
  "step_6_loop_1_step_6_python_pandas",
@@ -1147,7 +1142,7 @@ def test_embarrassingly_parallel_step_slots(
1147
1142
  }
1148
1143
 
1149
1144
 
1150
- def test_embarrassingly_parallel_step_get_implementation_graph(
1145
+ def test_embarrassingly_parallel_step_implementation_graph(
1151
1146
  embarrassingly_parallel_step_params: dict[str, Any]
1152
1147
  ) -> None:
1153
1148
  step = EmbarrassinglyParallelStep(**embarrassingly_parallel_step_params)
@@ -1155,7 +1150,7 @@ def test_embarrassingly_parallel_step_get_implementation_graph(
1155
1150
  {"implementation": {"name": "step_3_python_pandas", "configuration": {}}}
1156
1151
  )
1157
1152
  step.set_configuration_state(step_config, {}, {})
1158
- subgraph = step.get_implementation_graph()
1153
+ subgraph = _create_implementation_graph(step)
1159
1154
  assert list(subgraph.nodes) == ["step_3_python_pandas"]
1160
1155
  assert list(subgraph.edges) == []
1161
1156
 
@@ -1279,3 +1274,15 @@ def test_embarrassingly_parallel_step__validation(
1279
1274
  )
1280
1275
  for msg in expected:
1281
1276
  assert msg in error_msg
1277
+
1278
+
1279
+ ####################
1280
+ # Helper functions #
1281
+ ####################
1282
+
1283
+
1284
+ def _create_implementation_graph(step: Step) -> ImplementationGraph:
1285
+ implementation_graph = ImplementationGraph()
1286
+ step.add_nodes_to_implementation_graph(implementation_graph)
1287
+ step.add_edges_to_implementation_graph(implementation_graph)
1288
+ return implementation_graph
@@ -1 +0,0 @@
1
- __version__ = "0.1.10"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes