Skip to content

Commit e759b8f

Browse files
authored
Merge pull request #151 from cesioarg/master
Incorporate evaluation logics to BaseNode class + Fix example
2 parents 2a2b10c + d53b726 commit e759b8f

File tree

6 files changed

+277
-217
lines changed

6 files changed

+277
-217
lines changed

NodeGraphQt/base/node.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ def output_ports(self):
669669
list[NodeGraphQt.Port]: node output ports.
670670
"""
671671
return self._outputs
672-
672+
673673
def input(self, index):
674674
"""
675675
Return the input port with the matching index.
@@ -775,6 +775,38 @@ def on_input_disconnected(self, in_port, out_port):
775775
"""
776776
return
777777

778+
def update_streams(self, *args):
779+
"""
780+
Update all nodes joined by pipes to this.
781+
"""
782+
nodes = []
783+
trash = []
784+
785+
for port, nodeList in self.connected_output_nodes().items():
786+
nodes.extend(nodeList)
787+
788+
while nodes:
789+
node = nodes.pop()
790+
if node.disabled():
791+
continue
792+
if node not in trash:
793+
trash.append(node)
794+
795+
for port, nodeList in node.connected_output_nodes().items():
796+
nodes.extend(nodeList)
797+
798+
if not nodes:
799+
try:
800+
node.run()
801+
except Exception as error:
802+
print("Error Update Streams: %s" % str(error))
803+
804+
def run(self):
805+
"""
806+
Node evaluation logics.
807+
"""
808+
return
809+
778810

779811
class BackdropNode(NodeObject):
780812
"""

example_math_nodes.py

Lines changed: 12 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -1,188 +1,12 @@
11
#!/usr/bin/python
22
# -*- coding: utf-8 -*-
3-
import inspect
4-
import math
5-
from functools import partial
6-
7-
# add basic math functions to math library
8-
math.add = lambda x, y: x + y
9-
math.sub = lambda x, y: x - y
10-
math.mul = lambda x, y: x * y
11-
math.div = lambda x, y: x / y
12-
13-
# Transform float to functions
14-
for constant in ['pi', 'e', 'tau', 'inf', 'nan']:
15-
setattr(math, constant, partial(lambda x: x, getattr(math, constant)))
16-
17-
3+
from example_nodes import Nodes
184
from NodeGraphQt import (NodeGraph,
195
BaseNode,
206
setup_context_menu)
217
from NodeGraphQt import QtWidgets, QtCore, PropertiesBinWidget, NodeTreeWidget
228

239

24-
def update_streams(node, *args):
25-
"""
26-
Update all nodes joined by pipes
27-
"""
28-
nodes = []
29-
trash = []
30-
31-
for port, nodeList in node.connected_output_nodes().items():
32-
nodes.extend(nodeList)
33-
34-
while nodes:
35-
node = nodes.pop()
36-
if node not in trash:
37-
trash.append(node)
38-
39-
for port, nodeList in node.connected_output_nodes().items():
40-
nodes.extend(nodeList)
41-
42-
if not nodes:
43-
try:
44-
node.run()
45-
except Exception as error:
46-
print("Error Update Streams: %s" % str(error))
47-
48-
49-
class DataInputNode(BaseNode):
50-
"""
51-
Input node data.
52-
"""
53-
54-
__identifier__ = 'com.chantasticvfx'
55-
NODE_NAME = 'Input Numbers'
56-
57-
def __init__(self):
58-
super(DataInputNode, self).__init__()
59-
self.output = self.add_output('out')
60-
self.add_text_input('out', 'Data Input', text='0.4', tab='widgets')
61-
self.view.widgets['out'].value_changed.connect(partial(update_streams, self))
62-
63-
def run(self):
64-
return
65-
66-
67-
class MathFunctionsNode(BaseNode):
68-
"""
69-
Math functions node.
70-
"""
71-
72-
# set a unique node identifier.
73-
__identifier__ = 'com.chantasticvfx'
74-
75-
# set the initial default node name.
76-
NODE_NAME = 'Functions node'
77-
78-
mathFuncs = [func for func in dir(math) if not func.startswith('_')]
79-
80-
def __init__(self):
81-
super(MathFunctionsNode, self).__init__()
82-
self.set_color(25, 58, 51)
83-
self.add_combo_menu('functions', 'Functions', items=self.mathFuncs,
84-
tab='widgets')
85-
86-
# switch math function type
87-
self.view.widgets['functions'].value_changed.connect(self.addFunction)
88-
update = partial(update_streams, self)
89-
self.view.widgets['functions'].value_changed.connect(update)
90-
self.output = self.add_output('output')
91-
self.create_property(self.output.name(), None)
92-
self.trigger_type = 'no_inPorts'
93-
94-
self.view.widgets['functions'].widget.setCurrentIndex(2)
95-
96-
def addFunction(self, prop, func):
97-
"""
98-
Create inputs based on math functions arguments.
99-
"""
100-
self.func = getattr(math, func)
101-
dataFunc = inspect.getfullargspec(self.func)
102-
103-
for arg in dataFunc.args:
104-
if not self.has_property(arg):
105-
inPort = self.add_input(arg)
106-
inPort.trigger = True
107-
self.create_property(arg, None)
108-
109-
for inPort in self._inputs:
110-
if inPort.name() in dataFunc.args:
111-
if not inPort.visible():
112-
inPort.set_visible(True)
113-
else:
114-
inPort.set_visible(False)
115-
116-
def run(self):
117-
"""
118-
Evaluate all entries, pass them as arguments of the
119-
chosen mathematical function.
120-
"""
121-
for to_port in self.input_ports():
122-
if to_port.visible() == False:
123-
continue
124-
from_ports = to_port.connected_ports()
125-
if not from_ports:
126-
raise Exception('Port %s not connected!' % to_port.name(),
127-
to_port)
128-
129-
for from_port in from_ports:
130-
from_port.node().run()
131-
data = from_port.node().get_property(from_port.name())
132-
self.set_property(to_port.name(), float(data))
133-
134-
try:
135-
# Execute math function with arguments.
136-
output = self.func(*[self.get_property(inport.name()) for inport in self._inputs if inport.visible()])
137-
138-
self.set_property('output', output)
139-
except KeyError as error:
140-
print("An input is missing! %s" % str(error))
141-
except TypeError as error:
142-
print("Error evaluating function: %s" % str(error))
143-
144-
def on_input_connected(self, to_port, from_port):
145-
"""Override node callback method."""
146-
self.set_property(to_port.name(), from_port.node().run())
147-
update_streams(self)
148-
149-
def on_input_disconnected(self, to_port, from_port):
150-
"""Override node callback method."""
151-
self.set_property('output', None)
152-
update_streams(self)
153-
154-
155-
class DataViewerNode(BaseNode):
156-
__identifier__ = 'com.chantasticvfx'
157-
NODE_NAME = 'Result View'
158-
159-
def __init__(self):
160-
super(DataViewerNode, self).__init__()
161-
self.input = self.add_input('in data')
162-
self.add_text_input('data', 'Data Viewer', tab='widgets')
163-
164-
def run(self):
165-
"""Evaluate input to show it."""
166-
for source in self.input.connected_ports():
167-
from_node = source.node()
168-
try:
169-
from_node.run()
170-
except Exception as error:
171-
print("%s no inputs connected: %s" % (from_node.name(), str(error)))
172-
self.set_property('data', None)
173-
return
174-
value = from_node.get_property(source.name())
175-
self.set_property('data', str(value))
176-
177-
def on_input_connected(self, to_port, from_port):
178-
"""Override node callback method"""
179-
self.run()
180-
181-
def on_input_disconnected(self, to_port, from_port):
182-
"""Override node callback method"""
183-
self.set_property('data', None)
184-
185-
18610
if __name__ == '__main__':
18711
app = QtWidgets.QApplication([])
18812

@@ -216,38 +40,36 @@ def show_nodes_list(node):
21640
graph.node_double_clicked.connect(show_nodes_list)
21741

21842
# registered nodes.
219-
reg_nodes = [DataInputNode, DataViewerNode, MathFunctionsNode]
220-
221-
for n in reg_nodes:
43+
for n in Nodes:
22244
graph.register_node(n)
22345

224-
mathNodeA = graph.create_node('com.chantasticvfx.MathFunctionsNode',
46+
mathNodeA = graph.create_node('Math.MathFunctionsNode',
22547
name='Math Functions A',
22648
color='#0a1e20',
22749
text_color='#feab20',
22850
pos=[-250, 70])
22951

230-
mathNodeB = graph.create_node('com.chantasticvfx.MathFunctionsNode',
52+
mathNodeB = graph.create_node('Math.MathFunctionsNode',
23153
name='Math Functions B',
23254
color='#0a1e20',
23355
text_color='#feab20',
23456
pos=[-250, -70])
23557

236-
mathNodeC = graph.create_node('com.chantasticvfx.MathFunctionsNode',
237-
name='Math Functions C',
238-
color='#0a1e20',
239-
text_color='#feab20',
240-
pos=[0, 0])
58+
mathNodeC = graph.create_node('Math.MathFunctionsNode',
59+
name='Math Functions C',
60+
color='#0a1e20',
61+
text_color='#feab20',
62+
pos=[0, 0])
24163

242-
inputANode = graph.create_node('com.chantasticvfx.DataInputNode',
64+
inputANode = graph.create_node('Inputs.DataInputNode',
24365
name='Input A',
24466
pos=[-500, -50])
24567

246-
inputBNode = graph.create_node('com.chantasticvfx.DataInputNode',
68+
inputBNode = graph.create_node('Inputs.DataInputNode',
24769
name='Input B',
24870
pos=[-500, 50])
24971

250-
outputNode = graph.create_node('com.chantasticvfx.DataViewerNode',
72+
outputNode = graph.create_node('Viewers.DataViewerNode',
25173
name='Output',
25274
pos=[250, 0])
25375

example_nodes/__init__.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
#!/usr/bin/python
2-
# import os
3-
# import sys
4-
#
5-
# this_path = os.path.dirname(os.path.abspath(__file__))
6-
# directory = os.listdir(this_path)
7-
# modules = {}
8-
# for pkg_file in directory:
9-
# pkg, ext = os.path.splitext(pkg_file)
10-
# if pkg == '__init__':
11-
# continue
12-
# if ext in ('.py', '.pyc'):
13-
# modules[pkg] = ('from . import {}'.format(pkg))
14-
# elif os.path.isdir(os.path.join(directory, pkg_file)):
15-
# modules[pkg] = 'from . import {}'.format(pkg)
16-
#
17-
# for pkg, pkg_imp in modules.items():
18-
# try:
19-
# exec pkg_imp
20-
# except Exception as e:
21-
# import traceback
22-
# sys.stderr.write('Can\'t import module: {}'.format(pkg))
23-
# info = sys.exc_info()
24-
# type = info[0]
25-
# param = info[1]
26-
# tb = info[2]
27-
# traceback.print_exception(type, param, tb, file=sys.stderr)
2+
import os
3+
import sys
4+
import inspect
5+
import importlib
6+
7+
8+
def getNodesRecursively(path=__file__):
9+
Nodes = []
10+
basedir, filename = os.path.split(path)
11+
for root, dirs, files in os.walk(basedir, topdown=False):
12+
if root not in sys.path:
13+
sys.path.append(root)
14+
15+
for name in files:
16+
if name.endswith('.py') and not name.startswith('_'):
17+
module_name = name[:-3]
18+
module = importlib.import_module(module_name)
19+
for name, obj in inspect.getmembers(module):
20+
if inspect.isclass(obj) and not obj.__name__ == 'BaseNode':
21+
for clsObj in inspect.getmro(obj):
22+
if clsObj.__name__ == 'BaseNode':
23+
Nodes.append(obj)
24+
break
25+
return Nodes
26+
27+
28+
Nodes = getNodesRecursively()

0 commit comments

Comments
 (0)