From 306ab96a46205e98a9c266fec50aacac0c03a18a Mon Sep 17 00:00:00 2001 From: tlakshmi Date: Wed, 20 Nov 2024 14:10:47 +0100 Subject: [PATCH 1/7] Instantiate nodes before passing arguments to functions --- pyironflow/create_macro.py | 100 +++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 pyironflow/create_macro.py diff --git a/pyironflow/create_macro.py b/pyironflow/create_macro.py new file mode 100644 index 00000000..062673ae --- /dev/null +++ b/pyironflow/create_macro.py @@ -0,0 +1,100 @@ +from pyiron_workflow.type_hinting import type_hint_to_tuple +import typing + +def get_import_path(obj): + module = obj.__module__ if hasattr(obj, "__module__") else obj.__class__.__module__ + # name = obj.__name__ if hasattr(obj, "__name__") else obj.__class__.__name__ + name = obj.__name__ if "__name__" in dir(obj) else obj.__class__.__name__ + path = f"{module}.{name}" + if path == "numpy.ndarray": + path = "numpy.array" + return path + + + +def get_input_types_from_hint(node_input: dict): + + new_type = "" + + for listed_type in list(type_hint_to_tuple(node_input.type_hint)): + if listed_type.__name__ != "NoneType": + new_type = new_type + listed_type.__name__ + "|" + + new_type = new_type[:-1] + + for listed_type in list(type_hint_to_tuple(node_input.type_hint)): + if listed_type.__name__ == "NoneType": + new_type = "Optional[" + new_type + "]" + + return new_type + +def custom(wf = dict, name = str): + + imports = list("") + var_def = "" + + file = open('../pyiron_nodes/' + name + '.py', 'w') + + for i, (k, v) in enumerate(wf.children.items()): + rest, n = get_import_path(v).rsplit('.', 1) + new_import = " from " + rest + " import " + n + imports.append(new_import) + list_inputs = list(v.inputs.channel_dict.keys()) + + for j in list(v.inputs): + if ((v.label + "__" + j.label) in list(wf.inputs.channel_dict.keys())): + if str(j) == ("NOT_DATA" or "None"): + value = "None" + elif type(j.value) == str: + value = "'" + j.value + "'" + else: + value = str(j.value) + var_def = var_def + v.label + "_" + j.label + ": " + get_input_types_from_hint(j)+ " = " + value + ", " + + var_def = var_def[:-2] + + count = 0 + new_list = list("") + for ic, (out, inp) in enumerate(wf.graph_as_dict["edges"]["data"].keys()): + out_node, out_port = out.split('/')[2].split('.') + inp_node, inp_port = inp.split('/')[2].split('.') + new_list.append([out_node, inp_node, inp_port]) + + + file.write( +'''from pyiron_workflow import as_function_node, as_macro_node +from typing import Optional + +@as_macro_node() +def ''' + name + '''(wf, ''' + var_def + '''): +''') + for j in imports: + file.write(j + "\n") + + for i, (k, v) in enumerate(wf.children.items()): + rest, n = get_import_path(v).rsplit('.', 1) + file.write(" wf." + v.label + " = " + n + "()\n") + + for i, (k, v) in enumerate(wf.children.items()): + rest, n = get_import_path(v).rsplit('.', 1) + + node_def ="" + + for j in list(wf.inputs.channel_dict.keys()): + node_label, input_label =j.rsplit('__', 1) + if v.label == node_label: + node_def = node_def + input_label + " = " + node_label + "_" + input_label+ ", " + + for p in new_list: + if v.label == p[1]: + node_def = node_def + p[2] + " = wf."+ p[0] + ", " + node_def = node_def[:-2] + file.write(" wf." + v.label + ".set_input_values" + "(" + node_def + ")\n") + + + rest, n = list(wf.outputs.channel_dict.keys())[0].rsplit('__', 1) + file.write(" return wf." + rest) + print(wf.children.items()) + file.close() + + return From 9320696b425ac1e05b9d5b293dfc9b3c2b5ebbf5 Mon Sep 17 00:00:00 2001 From: tlakshmi Date: Wed, 20 Nov 2024 14:12:18 +0100 Subject: [PATCH 2/7] field and button for macro creation in workflow widget --- js/CustomNode.jsx | 5 +- js/widget.jsx | 123 ++++++++++++++++++++++++++++++++++++---- pyironflow/reactflow.py | 97 +++++++++++++++++++------------ 3 files changed, 175 insertions(+), 50 deletions(-) diff --git a/js/CustomNode.jsx b/js/CustomNode.jsx index 3648f757..1e341e7c 100644 --- a/js/CustomNode.jsx +++ b/js/CustomNode.jsx @@ -51,8 +51,7 @@ export default memo(({ data }) => { console.log('source: ', data.label) model.set("commands", `source: ${data.label}`); model.save_changes(); - } - + } const renderLabel = (label) => { return ( @@ -154,7 +153,7 @@ export default memo(({ data }) => { context(data.label, index, convertedValue); }} style={{ - width: '15px', + width: '20px', height: '10px', fontSize: '6px', backgroundColor: getBackgroundColor(value, inp_type) diff --git a/js/widget.jsx b/js/widget.jsx index abee14ce..11ef1e4a 100644 --- a/js/widget.jsx +++ b/js/widget.jsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState, useEffect, createContext } from 'react'; +import React, { useCallback, useState, useEffect, createContext, useSelection } from 'react'; import { createRender, useModel } from "@anywidget/react"; import ELK from 'elkjs/lib/elk.bundled.js'; import { @@ -9,6 +9,7 @@ import { applyEdgeChanges, applyNodeChanges, addEdge, + useOnSelectionChange, } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; @@ -40,6 +41,27 @@ export const UpdateDataContext = createContext(null); // const nodeTypes = { textUpdater: TextUpdaterNode, customNode: CustomNode }; +function SelectionDisplay() { + const [selectedNodes, setSelectedNodes] = useState([]); + const [selectedEdges, setSelectedEdges] = useState([]); + + // the passed handler has to be memoized, otherwise the hook will not work correctly + const onChange = useCallback(({ nodes, edges }) => { + setSelectedNodes(nodes.map((node) => node.id)); + setSelectedEdges(edges.map((edge) => edge.id)); + }, []); + + useOnSelectionChange({ + onChange, + }); + + return ( +
+

Selected nodes: {selectedNodes.join(', ')}

+

Selected edges: {selectedEdges.join(', ')}

+
+ ); +} const render = createRender(() => { const model = useModel(); @@ -50,12 +72,16 @@ const render = createRender(() => { const [nodes, setNodes] = useState(initialNodes); const [edges, setEdges] = useState(initialEdges); + const selectedNodes = []; + const selectedEdges = []; const nodeTypes = { textUpdater: TextUpdaterNode, customNode: CustomNode, }; + const [macroName, setMacroName] = useState('custom_macro'); + const updateData = (nodeLabel, handleIndex, newValue) => { setNodes(prevNodes => @@ -103,9 +129,31 @@ const render = createRender(() => { const onNodesChange = useCallback( (changes) => { setNodes((nds) => { - const new_nodes = applyNodeChanges(changes, nds); - console.log('onNodesChange: ', changes, new_nodes) + const new_nodes = applyNodeChanges(changes, nds); + for (const i in changes) { + if (Object.hasOwn(changes[i], 'selected')) { + if (changes[i].selected){ + for (const k in new_nodes){ + if (new_nodes[k].id == changes[i].id) { + selectedNodes.push(new_nodes[k]); + } + + } + } + else{ + for (const j in selectedNodes){ + if (selectedNodes[j].id == changes[i].id) { + //const index = selectedNodes[j].indexOf(changes[i].id); + selectedNodes.splice(j, 1); + } + } + } + } + } + console.log('selectedNodes:', selectedNodes); + console.log('nodes:', nodes); model.set("nodes", JSON.stringify(new_nodes)); + model.set("selected_nodes", JSON.stringify(selectedNodes)); model.save_changes(); return new_nodes; }); @@ -115,11 +163,38 @@ const render = createRender(() => { const onEdgesChange = useCallback( (changes) => { - setEdges((eds) => { - const new_edges = applyEdgeChanges(changes, eds); - model.set("edges", JSON.stringify(new_edges)); - model.save_changes(); - return new_edges; + setEdges((eds) => { + const new_edges = applyEdgeChanges(changes, eds); + for (const i in changes) { + if (Object.hasOwn(changes[i], 'selected')) { + if (changes[i].selected){ + for (const k in new_edges){ + if (new_edges[k].id == changes[i].id) { + selectedEdges.push(new_edges[k]); + } + } + } + else{ + for (const j in selectedEdges){ + if (selectedEdges[j].id == changes[i].id) { + selectedEdges.splice(j, 1); + } + } + } + } + } + for (const n in selectedEdges){ + var filterResult = new_edges.filter((edge) => edge.id === selectedEdges[n].id); + if (filterResult == []){ + selectedEdges.splice(n, 1); + } + } + console.log('selectedEdges:', selectedEdges); + console.log('edges:', new_edges); + model.set("edges", JSON.stringify(new_edges)); + model.set("selected_edges", JSON.stringify(selectedEdges)); + model.save_changes(); + return new_edges; }); }, [setEdges], @@ -173,8 +248,17 @@ const render = createRender(() => { data: { ...node.data, forceToolbarVisible: enabled }, })), ), - ); - + ); + + const macroFunction = (userInput) => { + console.log('macro: ', userInput); + if (model) { + model.set("commands", `macro: ${userInput}`); + model.save_changes(); + } else { + console.error('model is undefined'); + } + } return (
@@ -188,10 +272,25 @@ const render = createRender(() => { onNodesDelete={onNodesDelete} nodeTypes={nodeTypes} fitView - style={rfStyle}> - + style={rfStyle} + /*debugMode={true}*/ + > +
+ + setMacroName(evt.target.value)} + /> +
+ +
diff --git a/pyironflow/reactflow.py b/pyironflow/reactflow.py index 91c9e5ae..d05335e9 100644 --- a/pyironflow/reactflow.py +++ b/pyironflow/reactflow.py @@ -1,6 +1,7 @@ from pyiron_workflow import Workflow from pyiron_workflow.channels import NotData from pyironflow.themes import get_color +from pyironflow.create_macro import custom import anywidget import pathlib @@ -28,6 +29,8 @@ class ReactFlowWidget(anywidget.AnyWidget): _css = path / "widget.css" nodes = traitlets.Unicode('[]').tag(sync=True) edges = traitlets.Unicode('[]').tag(sync=True) + selected_nodes = traitlets.Unicode('[]').tag(sync=True) + selected_edges = traitlets.Unicode('[]').tag(sync=True) commands = traitlets.Unicode('[]').tag(sync=True) @@ -113,7 +116,7 @@ def get_node_types(node_io): return node_io_types -def get_node_position(node, id_num, node_width=200, y0=100, x_spacing=30): +def get_node_position(node, id_num, node_width=240, y0=100, x_spacing=20): if 'position' in dir(node): x, y = node.position # if isinstance(x, str): @@ -126,7 +129,7 @@ def get_node_position(node, id_num, node_width=200, y0=100, x_spacing=30): def get_node_dict(node, id_num, key=None): - node_width = 200 + node_width = 240 label = node.label if (node.label != key) and (key is not None): label = f'{node.label}: {key}' @@ -222,39 +225,44 @@ def on_value_change(self, change): command, node_name = change['new'].split(':') node_name = node_name.split('-')[0].strip() # print (f'node {node_name} not in wf {self.wf._children.keys()}: ', node_name not in self.wf._children) - if node_name not in self.wf._children: - return - node = self.wf._children[node_name] - # print(change['new'], command, node.label) - if self.accordion_widget is not None: - self.accordion_widget.selected_index = 1 - if command == 'source': - import inspect - from pygments import highlight - from pygments.lexers import Python2Lexer - from pygments.formatters import TerminalFormatter - - if hasattr(node, 'node_function'): - code = inspect.getsource(node.node_function) - elif hasattr(node, 'graph_creator'): - code = inspect.getsource(node.graph_creator) - elif hasattr(node, 'dataclass'): - code = inspect.getsource(node.dataclass) - else: - code = 'Function to extract code not implemented!' - - print(highlight(code, Python2Lexer(), TerminalFormatter())) - - elif command == 'run': - self.out_widget.clear_output() - out = node.pull() - - display(out) - # elif command == 'output': - # keys = list(node.outputs.channel_dict.keys()) - # display(node.outputs.channel_dict[keys[0]].value) - elif command == 'delete_node': - self.wf.remove_child(node_name) + if command != 'macro': + node_name = node_name.split('-')[0].strip() + if node_name not in self.wf._children: + return + node = self.wf._children[node_name] + # print(change['new'], command, node.label) + if self.accordion_widget is not None: + self.accordion_widget.selected_index = 1 + if command == 'source': + import inspect + from pygments import highlight + from pygments.lexers import Python2Lexer + from pygments.formatters import TerminalFormatter + + if hasattr(node, 'node_function'): + code = inspect.getsource(node.node_function) + elif hasattr(node, 'graph_creator'): + code = inspect.getsource(node.graph_creator) + elif hasattr(node, 'dataclass'): + code = inspect.getsource(node.dataclass) + else: + code = 'Function to extract code not implemented!' + + print(highlight(code, Python2Lexer(), TerminalFormatter())) + + elif command == 'run': + self.out_widget.clear_output() + out = node.pull() + + display(out) + # elif command == 'output': + # keys = list(node.outputs.channel_dict.keys()) + # display(node.outputs.channel_dict[keys[0]].value) + elif command == 'delete_node': + self.wf.remove_child(node_name) + + elif command == 'macro': + custom(self.get_selected_workflow(), node_name) def update(self): nodes = get_nodes(self.wf) @@ -294,3 +302,22 @@ def get_workflow(self): dict_to_edge(dict_edge, nodes) return wf + + def get_selected_workflow(self): + workflow_label = self.wf.label + + wf = Workflow(workflow_label) + dict_nodes = json.loads(self.gui.selected_nodes) + print(dict_nodes) + for dict_node in dict_nodes: + node = dict_to_node(dict_node) + wf.add_child(node) + # wf.add_child(node(label=node.label)) + + nodes = wf._children + dict_edges = json.loads(self.gui.selected_edges) + print(dict_edges) + for dict_edge in dict_edges: + dict_to_edge(dict_edge, nodes) + + return wf From 2fd02209e3f4f9a46b598759592a2bcf25bbdfbb Mon Sep 17 00:00:00 2001 From: tlakshmi Date: Thu, 21 Nov 2024 08:20:45 +0100 Subject: [PATCH 3/7] modify selected workflow --- package.json | 2 +- pyironflow/reactflow.py | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 3f25e9b4..ed11666d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ }, "dependencies": { "@anywidget/react": "^0.0.7", - "@xyflow/react": "^12.0.4", + "@xyflow/react": "^12.3.5", "elkjs": "^0.9.3", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/pyironflow/reactflow.py b/pyironflow/reactflow.py index d05335e9..dfe43e8c 100644 --- a/pyironflow/reactflow.py +++ b/pyironflow/reactflow.py @@ -308,16 +308,31 @@ def get_selected_workflow(self): wf = Workflow(workflow_label) dict_nodes = json.loads(self.gui.selected_nodes) - print(dict_nodes) + node_labels = [] for dict_node in dict_nodes: node = dict_to_node(dict_node) wf.add_child(node) + node_labels.append(dict_node["data"]["label"]) # wf.add_child(node(label=node.label)) + print("Nodes:") + print(node_labels) + print("\n") nodes = wf._children dict_edges = json.loads(self.gui.selected_edges) - print(dict_edges) - for dict_edge in dict_edges: + subset_dict_edges = [] + edge_labels = [] + for edge in dict_edges: + if edge["source"] in node_labels and edge["target"] in node_labels: + subset_dict_edges.append(edge) + edge_labels.append(edge["id"]) + print("Edges:") + print(edge_labels) + print("\n") + + for dict_edge in subset_dict_edges: dict_to_edge(dict_edge, nodes) + print("Sub-workflow:") + print(wf) return wf From deb11a257d65cd1bbb8b9e4843459ea74bfca150 Mon Sep 17 00:00:00 2001 From: tlakshmi Date: Thu, 21 Nov 2024 10:21:26 +0100 Subject: [PATCH 4/7] store created macro in root_path --- pyironflow/create_macro.py | 7 ++++--- pyironflow/pyironflow.py | 2 +- pyironflow/reactflow.py | 13 +++++-------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/pyironflow/create_macro.py b/pyironflow/create_macro.py index 062673ae..3e2d5bd4 100644 --- a/pyironflow/create_macro.py +++ b/pyironflow/create_macro.py @@ -28,12 +28,12 @@ def get_input_types_from_hint(node_input: dict): return new_type -def custom(wf = dict, name = str): +def custom(wf = dict, name = str, root_path='../pyiron_nodes/pyiron_nodes'): imports = list("") var_def = "" - file = open('../pyiron_nodes/' + name + '.py', 'w') + file = open(root_path + '/' + name + '.py', 'w') for i, (k, v) in enumerate(wf.children.items()): rest, n = get_import_path(v).rsplit('.', 1) @@ -50,6 +50,7 @@ def custom(wf = dict, name = str): else: value = str(j.value) var_def = var_def + v.label + "_" + j.label + ": " + get_input_types_from_hint(j)+ " = " + value + ", " + print(var_def) var_def = var_def[:-2] @@ -94,7 +95,7 @@ def ''' + name + '''(wf, ''' + var_def + '''): rest, n = list(wf.outputs.channel_dict.keys())[0].rsplit('__', 1) file.write(" return wf." + rest) - print(wf.children.items()) + print("\nSuccessfully created macro: " + root_path + '/' + name + '.py') file.close() return diff --git a/pyironflow/pyironflow.py b/pyironflow/pyironflow.py index 07d27b5a..22808468 100644 --- a/pyironflow/pyironflow.py +++ b/pyironflow/pyironflow.py @@ -28,7 +28,7 @@ def __init__(self, wf_list=None, root_path='../pyiron_nodes/pyiron_nodes'): self.out_log = widgets.Output(layout={'border': '1px solid black', 'width': '800px'}) self.out_widget = widgets.Output(layout={'border': '1px solid black', 'min_width': '400px'}) - self.wf_widgets = [PyironFlowWidget(wf, log=self.out_log, out_widget=self.out_widget) + self.wf_widgets = [PyironFlowWidget(wf=wf, root_path=root_path, log=self.out_log, out_widget=self.out_widget) for wf in self.workflows] self.view_flows = self.view_flows() self.tree_view = TreeView(root_path=root_path, flow_widget=self.wf_widgets[0], log=self.out_log) diff --git a/pyironflow/reactflow.py b/pyironflow/reactflow.py index dfe43e8c..3f16ddc9 100644 --- a/pyironflow/reactflow.py +++ b/pyironflow/reactflow.py @@ -197,12 +197,13 @@ def get_edges(wf): class PyironFlowWidget: - def __init__(self, wf: Workflow = Workflow(label='workflow'), log=None, out_widget=None): + def __init__(self, root_path='../pyiron_nodes/pyiron_nodes', wf: Workflow = Workflow(label='workflow'), log=None, out_widget=None): self.log = log self.out_widget = out_widget self.accordion_widget = None self.gui = ReactFlowWidget() self.wf = wf + self.root_path = root_path self.gui.observe(self.on_value_change, names='commands') @@ -262,7 +263,7 @@ def on_value_change(self, change): self.wf.remove_child(node_name) elif command == 'macro': - custom(self.get_selected_workflow(), node_name) + custom(self.get_selected_workflow(), node_name, self.root_path) def update(self): nodes = get_nodes(self.wf) @@ -314,9 +315,8 @@ def get_selected_workflow(self): wf.add_child(node) node_labels.append(dict_node["data"]["label"]) # wf.add_child(node(label=node.label)) - print("Nodes:") + print("\nSelected nodes:") print(node_labels) - print("\n") nodes = wf._children dict_edges = json.loads(self.gui.selected_edges) @@ -326,13 +326,10 @@ def get_selected_workflow(self): if edge["source"] in node_labels and edge["target"] in node_labels: subset_dict_edges.append(edge) edge_labels.append(edge["id"]) - print("Edges:") + print("\nSelected edges:") print(edge_labels) - print("\n") for dict_edge in subset_dict_edges: dict_to_edge(dict_edge, nodes) - print("Sub-workflow:") - print(wf) return wf From 6b237e58ed63fbc5cf0b26caacab1e1e93c3096b Mon Sep 17 00:00:00 2001 From: tlakshmi Date: Thu, 21 Nov 2024 11:29:19 +0100 Subject: [PATCH 5/7] fix type hinting --- pyironflow/create_macro.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pyironflow/create_macro.py b/pyironflow/create_macro.py index 3e2d5bd4..469088b8 100644 --- a/pyironflow/create_macro.py +++ b/pyironflow/create_macro.py @@ -17,14 +17,19 @@ def get_input_types_from_hint(node_input: dict): new_type = "" for listed_type in list(type_hint_to_tuple(node_input.type_hint)): + if listed_type == None: + listed_type = type(None) if listed_type.__name__ != "NoneType": new_type = new_type + listed_type.__name__ + "|" new_type = new_type[:-1] for listed_type in list(type_hint_to_tuple(node_input.type_hint)): + if listed_type == None: + listed_type = type(None) if listed_type.__name__ == "NoneType": - new_type = "Optional[" + new_type + "]" + if new_type != "": + new_type = ": Optional[" + new_type + "]" return new_type @@ -49,8 +54,7 @@ def custom(wf = dict, name = str, root_path='../pyiron_nodes/pyiron_nodes'): value = "'" + j.value + "'" else: value = str(j.value) - var_def = var_def + v.label + "_" + j.label + ": " + get_input_types_from_hint(j)+ " = " + value + ", " - print(var_def) + var_def = var_def + v.label + "_" + j.label + get_input_types_from_hint(j)+ " = " + value + ", " var_def = var_def[:-2] From 023ef4b4d82dd9a018a7182e830a4e576e886faf Mon Sep 17 00:00:00 2001 From: tlakshmi Date: Thu, 21 Nov 2024 13:19:27 +0100 Subject: [PATCH 6/7] snap to output --- pyironflow/reactflow.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyironflow/reactflow.py b/pyironflow/reactflow.py index 3f16ddc9..23f249f2 100644 --- a/pyironflow/reactflow.py +++ b/pyironflow/reactflow.py @@ -263,6 +263,8 @@ def on_value_change(self, change): self.wf.remove_child(node_name) elif command == 'macro': + if self.accordion_widget is not None: + self.accordion_widget.selected_index = 1 custom(self.get_selected_workflow(), node_name, self.root_path) def update(self): @@ -305,9 +307,8 @@ def get_workflow(self): return wf def get_selected_workflow(self): - workflow_label = self.wf.label - wf = Workflow(workflow_label) + wf = Workflow("temp_workflow") dict_nodes = json.loads(self.gui.selected_nodes) node_labels = [] for dict_node in dict_nodes: From 3307933ae86edc6e0f7cd07681e68554a3029659 Mon Sep 17 00:00:00 2001 From: tlakshmi Date: Thu, 21 Nov 2024 13:34:43 +0100 Subject: [PATCH 7/7] minor self fix --- pyironflow/create_macro.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyironflow/create_macro.py b/pyironflow/create_macro.py index 469088b8..adaaef34 100644 --- a/pyironflow/create_macro.py +++ b/pyironflow/create_macro.py @@ -71,14 +71,14 @@ def custom(wf = dict, name = str, root_path='../pyiron_nodes/pyiron_nodes'): from typing import Optional @as_macro_node() -def ''' + name + '''(wf, ''' + var_def + '''): +def ''' + name + '''(self, ''' + var_def + '''): ''') for j in imports: file.write(j + "\n") for i, (k, v) in enumerate(wf.children.items()): rest, n = get_import_path(v).rsplit('.', 1) - file.write(" wf." + v.label + " = " + n + "()\n") + file.write(" self." + v.label + " = " + n + "()\n") for i, (k, v) in enumerate(wf.children.items()): rest, n = get_import_path(v).rsplit('.', 1) @@ -92,13 +92,13 @@ def ''' + name + '''(wf, ''' + var_def + '''): for p in new_list: if v.label == p[1]: - node_def = node_def + p[2] + " = wf."+ p[0] + ", " + node_def = node_def + p[2] + " = self."+ p[0] + ", " node_def = node_def[:-2] - file.write(" wf." + v.label + ".set_input_values" + "(" + node_def + ")\n") + file.write(" self." + v.label + ".set_input_values" + "(" + node_def + ")\n") rest, n = list(wf.outputs.channel_dict.keys())[0].rsplit('__', 1) - file.write(" return wf." + rest) + file.write(" return self." + rest) print("\nSuccessfully created macro: " + root_path + '/' + name + '.py') file.close()