@@ -16,19 +16,23 @@ class WorkflowRenderer:
1616 """Render a generation plan into the final standalone Python source."""
1717
1818 def render (self , plan : GenerationPlan ) -> str :
19- workflow_literal = self .format_python_literal (plan .workflow_data )
20- if plan .metadata_workflow_data is None :
21- extra_pnginfo_literal = "None"
22- else :
23- extra_pnginfo_literal = self .format_python_literal (
24- {"workflow" : plan .metadata_workflow_data }
25- )
19+ final_code = "\n " .join (
20+ self ._build_static_imports (plan )
21+ + ["" ]
22+ + self ._build_workflow_section (plan )
23+ + ["" ]
24+ + self ._build_execution_section (plan )
25+ + ["" ]
26+ + self ._build_entrypoint_section ()
27+ )
28+ return black .format_str (final_code , mode = black .Mode ())
2629
30+ def _build_static_imports (self , plan : GenerationPlan ) -> list [str ]:
31+ """Build imports and embedded helper definitions for standalone scripts."""
2732 # Auto-discover all helpers from contributing runtime modules.
2833 # Reads source files, strips imports, embeds definitions — so internal
2934 # cross-calls always resolve (no NameError from missing __all__ entries).
3035 embedded_helpers = get_embedded_helpers ()
31-
3236 static_imports = [
3337 "# Imports" ,
3438 "import gc" ,
@@ -42,20 +46,22 @@ def render(self, plan: GenerationPlan) -> str:
4246 "from typing import Sequence, Mapping, Any, Union" ,
4347 "" ,
4448 "log = logging.getLogger(__name__)" ,
45- ] + [ embedded_helpers ]
46-
49+ embedded_helpers ,
50+ ]
4751 if plan .custom_nodes :
4852 static_imports .append (f"\n { inspect .getsource (import_custom_nodes )} \n " )
49- custom_nodes_call = "import_custom_nodes()"
50- else :
51- custom_nodes_call = None
53+ return static_imports
5254
53- imports_code = []
54- for module_name in sorted (plan .import_statements .keys ()):
55- class_names = ", " .join (sorted (plan .import_statements [module_name ]))
56- imports_code .append (f"from { module_name } import { class_names } " )
57-
58- workflow_section = [
55+ def _build_workflow_section (self , plan : GenerationPlan ) -> list [str ]:
56+ """Build workflow and PNG metadata literals."""
57+ workflow_literal = self .format_python_literal (plan .workflow_data )
58+ if plan .metadata_workflow_data is None :
59+ extra_pnginfo_literal = "None"
60+ else :
61+ extra_pnginfo_literal = self .format_python_literal (
62+ {"workflow" : plan .metadata_workflow_data }
63+ )
64+ return [
5965 "# Workflow data" ,
6066 "def build_workflow() -> dict[str, Any]:" ,
6167 f" return { workflow_literal } " ,
@@ -68,17 +74,22 @@ def render(self, plan: GenerationPlan) -> str:
6874 "extra_pnginfo = build_extra_pnginfo()" ,
6975 ]
7076
77+ def _build_execution_section (self , plan : GenerationPlan ) -> list [str ]:
78+ """Build the bootstrap, import, loop, and cleanup body."""
7179 execution_section = [
7280 "# Workflow execution" ,
7381 "def main(unload_models: bool | None = None):" ,
7482 " bootstrap_comfyui_runtime()" ,
7583 " add_extra_model_paths()" ,
7684 ]
77- if custom_nodes_call :
78- execution_section .append (f" { custom_nodes_call } " )
85+ if plan .custom_nodes :
86+ execution_section .append (" import_custom_nodes()" )
87+
88+ imports_code = self ._build_imports_code (plan )
7989 if imports_code :
8090 execution_section .extend (["" , " # Node imports" ])
8191 execution_section .extend (f" { line } " for line in imports_code )
92+
8293 execution_section .extend (
8394 [
8495 "" ,
@@ -105,24 +116,26 @@ def render(self, plan: GenerationPlan) -> str:
105116 " cleanup_comfyui_runtime(unload_models=unload_models)" ,
106117 ]
107118 )
119+ return execution_section
108120
109- entrypoint_section = [
121+ @staticmethod
122+ def _build_imports_code (plan : GenerationPlan ) -> list [str ]:
123+ """Build sorted node import statements for the main function."""
124+ imports_code = []
125+ for module_name in sorted (plan .import_statements .keys ()):
126+ class_names = ", " .join (sorted (plan .import_statements [module_name ]))
127+ imports_code .append (f"from { module_name } import { class_names } " )
128+ return imports_code
129+
130+ @staticmethod
131+ def _build_entrypoint_section () -> list [str ]:
132+ """Build the standalone script entrypoint."""
133+ return [
110134 "# Entrypoint" ,
111135 'if __name__ == "__main__":' ,
112136 " main()" ,
113137 ]
114138
115- final_code = "\n " .join (
116- static_imports
117- + ["" ]
118- + workflow_section
119- + ["" ]
120- + execution_section
121- + ["" ]
122- + entrypoint_section
123- )
124- return black .format_str (final_code , mode = black .Mode ())
125-
126139 @staticmethod
127140 def format_python_literal (value : Any ) -> str :
128141 return pformat (value , sort_dicts = False )
0 commit comments