def test_compound_output_plugs_inform_parent_on_value_set(clear_default_graph): """ +--------------------+ +----------------------+ | Generate | | MyPrint | |--------------------| |----------------------| | out %--------->o value<{"1": 1, "> | | out.0 o +----------------------+ | out.1 o | out.2 o +--------------------+ """ @Node(outputs=['out']) def Generate(): return {'out.{0}'.format(i): i for i in range(3)} @Node(outputs=['out']) def TestNode(value): return {'out': value} graph = Graph() generate = Generate(graph=graph) test = TestNode(graph=graph) generate.outputs['out'] >> test.inputs['value'] graph.evaluate() assert test.outputs['out'].value == {'0': 0, '1': 1, '2': 2}
def test_rshift_into_input_plug_group(clear_default_graph): """Test the node rshift operator with an INode as target. Note that OutputPlug >> INode is tested in the plug tests.""" g = Graph() g2 = Graph() @Node(outputs=["marker"]) def Node1(): return {"marker": None} @Node(outputs=[]) def Node2(marker): return {} @Node(outputs=[]) def Node3(different_marker): return {} n1 = Node1(graph=g) n2 = Node2(graph=g2) n3 = Node3(graph=g2) ig = InputPlugGroup( name="marker", graph=g2, plugs=[n2.inputs["marker"], n3.inputs["different_marker"]], ) n1 >> ig assert n2.inputs["marker"] in n1.outputs["marker"].connections
def test_string_representations(): """Print the Graph.""" graph = Graph() start = NodeForTesting(name='Start', graph=graph) n1 = NodeForTesting(name='Node1', graph=graph) n2 = NodeForTesting(name='Node2', graph=graph) end = NodeForTesting(name='End', graph=graph) start.outputs['out'] >> n1.inputs['in1'] start.outputs['out'] >> n2.inputs['in1']['0'] n1.outputs['out'] >> end.inputs['in1']['1'] n2.outputs['out']['0'] >> end.inputs['in1']['2'] n2.outputs['out']['0'] >> end.inputs['in2'] assert str(graph) == '\ +------------+ +------------+ +--------------------+\n\ | Start | | Node1 | | End |\n\ |------------| |------------| |--------------------|\n\ o in1<> | +--->o in1<> | % in1 |\n\ o in2<> | | o in2<> | +------->o in1.1<> |\n\ | out o-----+ | out o---------+ +--->o in1.2<> |\n\ | out2 o | | out2 o |--->o in2<> |\n\ +------------+ | +------------+ | | out o\n\ | +--------------------+ | | out2 o\n\ | | Node2 | | +--------------------+\n\ | |--------------------| | \n\ | % in1 | | \n\ +--->o in1.0<> | | \n\ o in2<> | | \n\ | out % | \n\ | out.0 o-----+ \n\ | out2 o \n\ +--------------------+ ' assert graph.list_repr() == '''\
def test_evaluation_matrix(): """The nodes as a 2D grid.""" start = NodeForTesting('start') n11 = NodeForTesting('11') n12 = NodeForTesting('12') n21 = NodeForTesting('21') n31 = NodeForTesting('31') n32 = NodeForTesting('32') n33 = NodeForTesting('33') end = NodeForTesting('end') # Connect them start.outputs['out'] >> n11.inputs['in1'] start.outputs['out'] >> n21.inputs['in1'] start.outputs['out'] >> n31.inputs['in1'] n31.outputs['out'] >> n32.inputs['in1'] n32.outputs['out'] >> n33.inputs['in1'] n11.outputs['out'] >> n12.inputs['in1'] n33.outputs['out'] >> n12.inputs['in2'] n12.outputs['out'] >> end.inputs['in1'] n21.outputs['out'] >> end.inputs['in2'] nodes = [start, n11, n12, n21, n31, n32, n33, end] graph = Graph(nodes=nodes) order = [[start], [n11, n21, n31], [n32], [n33], [n12], [end]] for i, row in enumerate(graph.evaluation_matrix): for node in row: assert node in order[i] graph.evaluate()
def test_compound_output_plugs_inform_parent_on_value_set(clear_default_graph): """ +--------------------+ +----------------------+ | Generate | | MyPrint | |--------------------| |----------------------| | out %--------->o value<{"1": 1, "> | | out.0 o +----------------------+ | out.1 o | out.2 o +--------------------+ """ @Node(outputs=["out"]) def Generate(): return {"out.{0}".format(i): i for i in range(3)} @Node(outputs=["out"]) def TestNode(value): return {"out": value} graph = Graph() generate = Generate(graph=graph) test = TestNode(graph=graph) generate.outputs["out"] >> test.inputs["value"] graph.evaluate() assert test.outputs["out"].value == {"0": 0, "1": 1, "2": 2}
def test_nodes_are_only_added_once(): graph = Graph() node = NodeForTesting() for i in range(10): graph.add_node(node) assert len(graph.nodes) == 1
def test_serialize_graph_to_pickle(clear_default_graph): """ +------------+ +------------+ +--------------------+ | Start | | Node2 | | End | |------------| |------------| |--------------------| o in1<0> | +--->o in1<> | % in1 | o in2<0> | | o in2<0> | +--->o in1.1<> | | out o-----+ | out o-----|--->o in1.2<> | | out2 o | | out2 o | o in2<0> | +------------+ | +------------+ | | out o | +------------+ | | out2 o | | Node1 | | +--------------------+ | |------------| | +--->o in1<> | | o in2<0> | | | out o-----+ | out2 o +------------+ """ graph = Graph() start = NodeForTesting(name='Start', graph=graph) n1 = NodeForTesting(name='Node1', graph=graph) n2 = NodeForTesting(name='Node2', graph=graph) end = NodeForTesting(name='End', graph=graph) start.outputs['out'] >> n1.inputs['in1'] start.outputs['out'] >> n2.inputs['in1'] n1.outputs['out'] >> end.inputs['in1']['1'] n2.outputs['out'] >> end.inputs['in1']['2'] serialized = graph.to_pickle() deserialized = Graph.from_pickle(serialized).to_pickle() assert serialized == deserialized
def test_access_nodes_in_graph_by_identifier(): """Access nodes by their identifier in a Graph.""" node = NodeForTesting() graph = Graph(nodes=[node]) assert node == graph.node_by_id(node.identifier) with pytest.raises(Exception): graph.node_by_id("DoesNotExist")
def test_access_nodes_in_graph_by_name(): """Access nodes by their name in a Graph.""" node = NodeForTesting() graph = Graph(nodes=[node]) assert node == graph.node(node.name)[0] with pytest.raises(Exception): graph.node("DoesNotExist")
def test_string_representations(): """Print the Graph.""" start = NodeForTesting('start') end = NodeForTesting('end') start.outputs['out'] >> end.inputs['in1'] graph = Graph(nodes=[start, end]) print(graph) print(graph.list_repr())
def test_nodes_in_graph_can_have_same_name(): graph = Graph() nodes = [] for i in range(100): node = NodeForTesting("SameName") graph.add_node(node) nodes.append(node) print(graph.node("SameName"))
def test_nested_graphs_expand_sub_graphs(clear_default_graph): """Nested Graphs expand all nodes of their sub graphs on evaluation. +----G1-----+ +----G2-----+ +----G3-----+ +----G3-----+ +----G2-----+ +----G1-----+ | N1 | | N3 | | N4 | | N5 | | N6 | | N7 | |-----------| |-----------| |-----------| |-----------| |-----------| |-----------| o in_<> | o in_<> | o in_<> | o in_<> | o in_<> | o in_<> | o in_1<> | +--->o in_1<> | +--->o in_1<> | +--->o in_1<> | +--->o in_1<> | +--->o in_1<> | o in_2<> | | o in_2<>----|-----|--->o in_2<> | +----o-in_2<>----|----------o-in_2<>----|--------->o in_2<> | | out o-----+----|-------out-o----------|-------out-o-----+ | out o-----+ | out o-----+ | out o +-----------+ +-----------+ +-----------+ +-----------+ +-----------+ +-----------+ +----G2-----+ | | N2 | | |-----------| | o in_<> | | o in_1<> | | o in_2<> | | | out o-----------------+ +-----------+ """ # G 3 # G3 = Graph(name="G3") N5 = FunctionNodeForTesting(name="N5", graph=G3) N4 = FunctionNodeForTesting(name="N4", graph=G3) N4.inputs["in_1"].promote_to_graph() N4.inputs["in_2"].promote_to_graph() N5.outputs["out"].promote_to_graph() N4.outputs["out"] >> N5.inputs["in_1"] # G 2 # G2 = Graph(name="G2") N3 = FunctionNodeForTesting(name="N3", graph=G2) N2 = FunctionNodeForTesting(name="N2", graph=G2) N6 = FunctionNodeForTesting(name="N6", graph=G2) N3.inputs["in_1"].promote_to_graph() N6.outputs["out"].promote_to_graph() N3.outputs["out"] >> G3.inputs["in_1"] N2.outputs["out"] >> G3.inputs["in_2"] G3.outputs["out"] >> N6.inputs["in_1"] # G 1 # G1 = Graph(name="G1") N1 = FunctionNodeForTesting(name="N1", graph=G1) N7 = FunctionNodeForTesting(name="N7", graph=G1) N1.outputs["out"] >> G2.inputs["in_1"] G2.outputs["out"] >> N7.inputs["in_1"] N1.outputs["out"] >> N7.inputs["in_2"] order = [['N1', 'N2'], ['N3'], ['N4'], ['N5'], ['N6'], ['N7']] for i, nodes in enumerate(G1.evaluation_matrix): assert sorted([n.name for n in nodes]) == sorted(order[i])
def test_nodes_can_be_accessed_via_name_through_indexing(): graph = Graph() test_name = "TestName" node = NodeForTesting(name=test_name) graph.add_node(node) assert graph[test_name] == node with pytest.raises(Exception): graph["Does not exist"]
def test_if_on_node_is_dirty_the_entire_graph_is_dirty(): start = NodeForTesting('start') end = NodeForTesting('end') start.outputs['out'] >> end.inputs['in1'] graph = Graph(nodes=[start, end]) graph.evaluate() assert not graph.is_dirty start.inputs["in1"].is_dirty = True assert graph.is_dirty
def test_serialize_graph(): """Serialize the graph to a json-serializable dictionary.""" start = NodeForTesting('start') n11 = NodeForTesting('11') n12 = NodeForTesting('12') n21 = NodeForTesting('21') n31 = NodeForTesting('31') n32 = NodeForTesting('32') n33 = NodeForTesting('33') end = NodeForTesting('end') # Connect them start.outputs['out'] >> n11.inputs['in1'] start.outputs['out'] >> n21.inputs['in1'] start.outputs['out'] >> n31.inputs['in1'] n31.outputs['out'] >> n32.inputs['in1'] n32.outputs['out'] >> n33.inputs['in1'] n11.outputs['out'] >> n12.inputs['in1'] n33.outputs['out'] >> n12.inputs['in2'] n12.outputs['out'] >> end.inputs['in1'] n21.outputs['out'] >> end.inputs['in2'] nodes = [start, n11, n12, n21, n31, n32, n33, end] graph = Graph(nodes=nodes) serialized = graph.serialize() deserialized = graph.deserialize(serialized) assert len(deserialized.nodes) == len(graph.nodes) assert graph.identifier == deserialized.identifier assert graph.name == deserialized.name # Connections need to be deserialized as well for i in range(len(graph.nodes)): assert graph.nodes[i].identifier == deserialized.nodes[i].identifier # inputs for name, plug in graph.nodes[i].inputs.items(): ds_plug = deserialized.nodes[i].inputs[name] for j in range(len(plug.connections)): connection = plug.connections[j] ds_connection = ds_plug.connections[j] assert ds_connection.name == connection.name assert ds_connection.node.identifier == connection.node.identifier # outputs for name, plug in graph.nodes[i].outputs.items(): ds_plug = deserialized.nodes[i].outputs[name] for j in range(len(plug.connections)): connection = plug.connections[j] ds_connection = ds_plug.connections[j] assert ds_connection.name == connection.name assert ds_connection.node.name == connection.node.name
def test_string_representations_with_subgraphs(clear_default_graph): """For nested graphs, graph names are shown in header of nodes.""" main = Graph(name="main") sub1 = Graph(name="sub1") sub2 = Graph(name="sub2") start = NodeForTesting(name='Start', graph=main) n1 = NodeForTesting(name='Node1', graph=sub1) n2 = NodeForTesting(name='Node2', graph=sub1) end = NodeForTesting(name='End', graph=sub2) start.outputs['out'] >> n1.inputs['in1'] start.outputs['out'] >> n2.inputs['in1']['0'] n1.outputs['out'] >> end.inputs['in1']['1'] n2.outputs['out']['0'] >> end.inputs['in1']['2'] n2.outputs['out']['0'] >> end.inputs['in2'] assert str(main) == '\
def branching_graph(): """ +------------+ +------------+ +--------------------+ | Start | | Node2 | | End | |------------| |------------| |--------------------| o in1<0> | +--->o in1<> | % in1 | o in2<0> | | o in2<0> | +--->o in1.1<> | | out o-----+ | out o-----|--->o in1.2<> | | out2 o | | out2 o | o in2<0> | +------------+ | +------------+ | | out o | +------------+ | | out2 o | | Node1 | | +--------------------+ | |------------| | +--->o in1<> | | o in2<0> | | | out o-----+ | out2 o +------------+ """ graph = Graph(name="TestGraph") start = NodeForTesting(name="Start", graph=graph) n1 = NodeForTesting(name="Node1", graph=graph) n2 = NodeForTesting(name="Node2", graph=graph) end = NodeForTesting(name="End", graph=graph) start.outputs["out"] >> n1.inputs["in1"] start.outputs["out"] >> n2.inputs["in1"] n1.outputs["out"] >> end.inputs["in1"]["1"] n2.outputs["out"] >> end.inputs["in1"]["2"] yield graph
def complex_cg_render(frames, batch_size): graph = Graph(name='Rendering') slapcomp = CreateSlapComp(graph=graph, template='nuke_template.nk') update_database = UpdateDatabase(graph=graph, id_=123456) for i in range(0, frames, batch_size): maya_render = MayaRender(name='MayaRender{0}-{1}'.format( i, i + batch_size), graph=graph, frames=range(i, i + batch_size), scene_file='/scene/for/rendering.ma') check_images = CheckImages(name='CheckImages{0}-{1}'.format( i, i + batch_size), graph=graph) maya_render.outputs['renderings'].connect( check_images.inputs['images']) check_images.outputs['images'].connect( slapcomp.inputs['images'][str(i)]) check_images.outputs['images'].connect( update_database.inputs['images'][str(i)]) quicktime = Quicktime() for i in range(0, frames, batch_size): nuke_render = NukeRender(name='NukeRender{0}-{1}'.format( i, i + batch_size), graph=graph, frames=range(i, i + batch_size)) slapcomp.outputs['slapcomp'].connect(nuke_render.inputs['scene_file']) nuke_render.outputs['renderings'].connect( quicktime.inputs['images'][str(i)]) print(graph)
def branching_graph(): """ +------------+ +------------+ +--------------------+ | Start | | Node2 | | End | |------------| |------------| |--------------------| o in1<0> | +--->o in1<> | % in1 | o in2<0> | | o in2<0> | +--->o in1.1<> | | out o-----+ | out o-----|--->o in1.2<> | | out2 o | | out2 o | o in2<0> | +------------+ | +------------+ | | out o | +------------+ | | out2 o | | Node1 | | +--------------------+ | |------------| | +--->o in1<> | | o in2<0> | | | out o-----+ | out2 o +------------+ """ graph = Graph(name="TestGraph") start = NodeForTesting(name='Start', graph=graph) n1 = NodeForTesting(name='Node1', graph=graph) n2 = NodeForTesting(name='Node2', graph=graph) end = NodeForTesting(name='End', graph=graph) start.outputs['out'] >> n1.inputs['in1'] start.outputs['out'] >> n2.inputs['in1'] n1.outputs['out'] >> end.inputs['in1']['1'] n2.outputs['out'] >> end.inputs['in1']['2'] yield graph
def test_exception_event(clear_default_graph): """Test the proper handling of exceptions in nodes.""" g = Graph() def has_been_executed(n): n.event_happened = True @Node() def ErrorNode(): raise Exception en = ErrorNode(graph=g) en.EVENTS["evaluation-exception"].register(has_been_executed) with pytest.raises(Exception): g.evaluate() assert en.event_happened
def test_node_names_on_graph_have_to_be_unique(clear_default_graph): graph = Graph() same_name = "Same Name" node_1 = NodeForTesting(name=same_name, graph=None) graph.add_node(node_1) node_2 = NodeForTesting(name=same_name, graph=None) with pytest.raises(ValueError): graph.add_node(node_2)
def test_set_default_graph(clear_default_graph): new_default = Graph(name='new default') set_default_graph(new_default) direct = flowpipe.graph.default_graph assert direct is new_default new_default = "foo" with pytest.raises(TypeError): set_default_graph(new_default)
def test_nodes_can_be_accessed_via_name_through_indexing(clear_default_graph): graph = Graph() test_name = "TestName" node = NodeForTesting(name=test_name) graph.add_node(node) assert graph[test_name] == node with pytest.raises(KeyError): graph["Does not exist"]
def test_nodes_can_add_to_graph_on_init(clear_default_graph): graph = Graph() node = NodeForTesting(graph=graph) assert graph["NodeForTesting"] == node @Node() def function(): pass node = function(graph=graph) assert graph["function"] == node
def open(self): json_file = QtWidgets.QFileDialog.getOpenFileName( self, "Open JSON graph file", "", "JSON Files (*.json)")[0] if not json_file: return json_data = None with open(json_file, "r") as f: json_data = json.load(f) graph = Graph.deserialize(json_data) w.load_graph(graph)
def implicit_batching(frames, batch_size): """Batches are created during the farm conversion.""" graph = Graph(name='Rendering') render = MayaRender(graph=graph, frames=range(frames), scene_file='/scene/for/rendering.ma', metadata={'batch_size': batch_size}) update = UpdateDatabase(graph=graph, id_=123456) render.outputs['renderings'].connect(update.inputs['images']) print(graph) print(json.dumps(convert_graph_to_job(graph), indent=2))
def test_string_representations_with_subgraphs(clear_default_graph): """For nested graphs, graph names are shown in header of nodes.""" main = Graph(name="main") sub1 = Graph(name="sub1") sub2 = Graph(name="sub2") start = NodeForTesting(name="Start", graph=main) n1 = NodeForTesting(name="Node1", graph=sub1) n2 = NodeForTesting(name="Node2", graph=sub1) end = NodeForTesting(name="End", graph=sub2) start.outputs["out"] >> n1.inputs["in1"] start.outputs["out"] >> n2.inputs["in1"]["0"] n1.outputs["out"] >> end.inputs["in1"]["1"] n2.outputs["out"]["0"] >> end.inputs["in1"]["2"] n2.outputs["out"]["0"] >> end.inputs["in2"] assert (str(main) == "\ +--------------------------------------------------------------------------------+\n\ | main |\n\ |--------------------------------------------------------------------------------|\n\ | +----main----+ +----sub1----+ +--------sub2--------+ |\n\ | | Start | | Node1 | | End | |\n\ | |------------| |------------| |--------------------| |\n\ | o in1<> | +--->o in1<> | % in1<> | |\n\ | o in2<> | | o in2<> | +------->o in1.1<> | |\n\ | | out<> o-----+ | out<> o---------+ +--->o in1.2<> | |\n\ | | out2<> o | | out2<> o |--->o in2<> | |\n\ | +------------+ | +------------+ | | out<> o |\n\ | | +--------sub1--------+ | | out2<> o |\n\ | | | Node2 | | +--------------------+ |\n\ | | |--------------------| | |\n\ | | % in1<> | | |\n\ | +--->o in1.0<> | | |\n\ | o in2<> | | |\n\ | | out<> % | |\n\ | | out.0<> o-----+ |\n\ | | out2<> o |\n\ | +--------------------+ |\n\ +--------------------------------------------------------------------------------+\n\ " )
def test_cycle_error_when_node_connects_out_to_own_upstream_across_subgraphs(): """Cycle Error: +---graph1----+ +---graph2----+ +---graph3----+ | N1 | | N2 | | N3 | |-------------| |-------------| |-------------| +-->o in_<> | +--->o in_<> | +--->o in_<> | | | out o-----+ | out o-----+ | out o--+ | +-------------+ +-------------+ +-------------+ | | | +----------------------------------------------------------------------+ """ graph1 = Graph(name="graph1") graph2 = Graph(name="graph2") graph3 = Graph(name="graph3") N1 = FunctionNodeForTesting(name="N1", graph=graph1) N2 = FunctionNodeForTesting(name="N2", graph=graph2) N3 = FunctionNodeForTesting(name="N3", graph=graph3) N1.outputs["out"] >> N2.inputs["in_"] N2.outputs["out"] >> N3.inputs["in_"] with pytest.raises(CycleError): N3.outputs["out"] >> N1.inputs["in_"] with pytest.raises(CycleError): N1.inputs["in_"] >> N3.outputs["out"] with pytest.raises(CycleError): N3.outputs["out"]["a"] >> N1.inputs["in_"] with pytest.raises(CycleError): N1.inputs["in_"]["a"] >> N3.outputs["out"] with pytest.raises(CycleError): N3.outputs["out"]["a"] >> N1.inputs["in_"]["a"] with pytest.raises(CycleError): N1.inputs["in_"]["a"] >> N3.outputs["out"]["a"]
def test_multiprocessed_evaluation_is_faster(): """Test by having sleeper nodes sleep in parallel and check total grah timing. +---------------+ +---------------+ | Sleeper1 | | Sleeper2 | |---------------| |---------------| o in1<> | +--->o in1<> | | out o-----+ | out o +---------------+ | +---------------+ | +---------------+ | | Sleeper3 | | |---------------| +--->o in1<> | | | out o | +---------------+ | +---------------+ | | Sleeper4 | | |---------------| +--->o in1<> | | out o +---------------+ """ delay = .05 graph = Graph(name='threaded') s1 = Sleeper(name='Sleeper1', graph=graph) s2 = Sleeper(name='Sleeper2', graph=graph) s3 = Sleeper(name='Sleeper3', graph=graph) s4 = Sleeper(name='Sleeper4', graph=graph) s1.outputs['out'] >> s2.inputs['in1'] s1.outputs['out'] >> s3.inputs['in1'] s1.outputs['out'] >> s4.inputs['in1'] start = time.time() graph.evaluate(mode="multiprocessing") end = time.time() runtime = end - start assert runtime < len(graph.nodes) * SLEEP_TIME + len(graph.nodes) * delay
def test_linar_evaluation_sequence(): """A linear graph.""" n1 = NodeForTesting('n1') n2 = NodeForTesting('n2') n3 = NodeForTesting('n3') n1.outputs['out'] >> n2.inputs['in1'] n2.outputs['out'] >> n3.inputs['in1'] nodes = [n2, n1, n3] graph = Graph(nodes=nodes) seq = [s.name for s in graph.evaluation_sequence] assert ['n1', 'n2', 'n3'] == seq