1313import pathlib
1414import uuid
1515from enum import Enum
16- from types import ModuleType
16+ from types import FunctionType , ModuleType
1717from typing import Any , Callable , Collection , Dict , FrozenSet , List , Optional , Set , Tuple , Type
1818
1919import hamilton .lifecycle .base as lifecycle_base
@@ -142,17 +142,18 @@ def update_dependencies(
142142 return nodes
143143
144144
145- def create_function_graph (
145+ def compile_to_nodes (
146146 * functions : List [Tuple [str , Callable ]],
147147 config : Dict [str , Any ],
148148 adapter : lifecycle_base .LifecycleAdapterSet = None ,
149149 fg : Optional ["FunctionGraph" ] = None ,
150- allow_module_overrides : bool = False ,
150+ allow_node_level_overrides : bool = False ,
151151) -> Dict [str , node .Node ]:
152152 """Creates a graph of all available functions & their dependencies.
153153 :param modules: A set of modules over which one wants to compute the function graph
154154 :param config: Dictionary that we will inspect to get values from in building the function graph.
155155 :param adapter: The adapter that adapts our node type checking based on the context.
156+ :param allow_node_level_overrides: Whether or not to allow node names to override each other
156157 :return: list of nodes in the graph.
157158 If it needs to be more complicated, we'll return an actual networkx graph and get all the rest of the logic for free
158159 """
@@ -170,7 +171,7 @@ def create_function_graph(
170171 for n in fm_base .resolve_nodes (f , config ):
171172 if n .name in config :
172173 continue # This makes sure we overwrite things if they're in the config...
173- if n .name in nodes and not allow_module_overrides :
174+ if n .name in nodes and not allow_node_level_overrides :
174175 raise ValueError (
175176 f"Cannot define function { n .name } more than once."
176177 f" Already defined by function { f } "
@@ -713,13 +714,43 @@ def __init__(
713714 self .nodes = nodes
714715 self .adapter = adapter
715716
717+ @staticmethod
718+ def compile (
719+ modules : List [ModuleType ],
720+ functions : List [FunctionType ],
721+ config : Dict [str , Any ],
722+ adapter : lifecycle_base .LifecycleAdapterSet = None ,
723+ allow_node_overrides : bool = False ,
724+ ) -> "FunctionGraph" :
725+ """Base level static function for compiling a function graph. Note
726+ that this can both use functions (E.G. passing them directly) and modules
727+ (passing them in and crawling.
728+
729+ :param modules: Modules to use
730+ :param functions: Functions to use
731+ :param config: Config to use for setting up the DAG
732+ :param adapter: Adapter to use for node resolution
733+ :param allow_node_overrides: Whether or not to allow node level overrides.
734+ :return: The compiled function graph
735+ """
736+ module_functions = sum ([find_functions (module ) for module in modules ], [])
737+ nodes = compile_to_nodes (
738+ * module_functions ,
739+ * functions ,
740+ config = config ,
741+ adapter = adapter ,
742+ allow_node_level_overrides = allow_node_overrides ,
743+ )
744+ return FunctionGraph (nodes , config , adapter )
745+
716746 @staticmethod
717747 def from_modules (
718748 * modules : ModuleType ,
719749 config : Dict [str , Any ],
720750 adapter : lifecycle_base .LifecycleAdapterSet = None ,
721751 allow_module_overrides : bool = False ,
722- ):
752+ additional_functions : List [FunctionType ],
753+ ) -> "FunctionGraph" :
723754 """Initializes a function graph from the specified modules. Note that this was the old
724755 way we constructed FunctionGraph -- this is not a public-facing API, so we replaced it
725756 with a constructor that takes in nodes directly. If you hacked in something using
@@ -732,28 +763,28 @@ def from_modules(
732763 :return: a function graph.
733764 """
734765
735- functions = sum ([ find_functions ( module ) for module in modules ], [])
736- return FunctionGraph . from_functions (
737- * functions ,
766+ return FunctionGraph . compile (
767+ modules = modules ,
768+ functions = [] ,
738769 config = config ,
739770 adapter = adapter ,
740- allow_module_overrides = allow_module_overrides ,
771+ allow_node_overrides = allow_module_overrides ,
741772 )
742773
743774 @staticmethod
744775 def from_functions (
745- * functions ,
776+ * functions : FunctionType ,
746777 config : Dict [str , Any ],
747778 adapter : lifecycle_base .LifecycleAdapterSet = None ,
748779 allow_module_overrides : bool = False ,
749780 ) -> "FunctionGraph" :
750- nodes = create_function_graph (
751- * functions ,
781+ return FunctionGraph .compile (
782+ modules = [],
783+ functions = functions ,
752784 config = config ,
753785 adapter = adapter ,
754- allow_module_overrides = allow_module_overrides ,
786+ allow_node_overrides = allow_module_overrides ,
755787 )
756- return FunctionGraph (nodes , config , adapter )
757788
758789 def with_nodes (self , nodes : Dict [str , Node ]) -> "FunctionGraph" :
759790 """Creates a new function graph with the additional specified nodes.
0 commit comments