def test_subnet_with_substreams(graph, discard): # tracing = True gen = graph.add_component("Generate", GenSS, COUNT=15) passnet = graph.add_component("Subnet", PassthruNet) dis = graph.add_component("Discard", discard) graph.connect("Generate.OUT", "Subnet.IN") graph.connect("Subnet.OUT", "Discard.IN") # graph.reset() # graph._build_runners() # graph._open_ports() # assert isinstance(passnet.ports['OUT'].component, Passthru) # assert isinstance(passnet.ports['OUT'].sender, ComponentRunner) # assert isinstance(passnet.ports['IN'].component, Passthru) # assert isinstance(passnet.ports['IN'].receiver, ComponentRunner) # FIXME: need a separate test for the NULL port behavior # graph.connect("Subnet.*SUBEND", "WTC.IN") run_graph(graph) assert dis.values == [ '', '000015', '000014', '000013', '000012', '000011', '', '', '000010', '000009', '000008', '000007', '000006', '', '', '000005', '000004', '000003', '000002', '000001', '' ]
def test_make_subgraph(): sub = Graph() sub.add_component('Head', Passthru) sub.add_component('Tail', Passthru) sub.connect('Head.OUT', 'Tail.IN') sub.export('Head.IN', 'IN') sub.export('Tail.OUT', 'OUT') PassNet = make_subgraph(sub, name='PassNet') assert len(PassNet.inport_definitions) == 2 assert len(PassNet.outport_definitions) == 2 graph = Graph() capture = graph.add_component('Capture', Capture) graph.add_component('Pass', PassNet) graph.initialize(5, 'Pass.IN') graph.connect('Pass.OUT', 'Capture.IN') run_graph(graph) assert capture.value == 5
def test_inport_default(): graph = Graph() graph.add_component("Generate", GenerateTestData) dis = graph.add_component("Discard", Discard) graph.connect("Generate.OUT", "Discard.IN") run_graph(graph) assert dis.values == ['000001']
def test_null_ports2(graph, tmpdir, discard): """null ports ensure proper ordering of components""" # in this case, we give Read an input that it can consume, but the null # port should prevent it from happening until Write is done graph.add_component("Data", GenerateTestData, COUNT=2) graph.add_component("FileNames", GenerateTestData, COUNT=2) graph.add_component("Prefix", Prefix, PRE=str(tmpdir.join('file.'))) graph.add_component("Replicate", Replicate) write = graph.add_component("Write", Write) read = graph.add_component("Read", ReadLines) dis = graph.add_component("Discard", discard) graph.connect("Data.OUT", "Write.IN") graph.connect("FileNames.OUT", "Prefix.IN") graph.connect("Prefix.OUT", "Replicate.IN") graph.connect("Replicate.OUT[0]", "Write.FILEPATH") graph.connect("Replicate.OUT[1]", "Read.FILEPATH") # Note that it's probably more correct to use Write.OUT which sends after # each file written, instead of Write.NULL which sends after all files are # written, but we use the latter because it reveals an interesting deadlock # issue with Replicate (see notes in that component for more info) graph.connect(write.port(OUT_NULL), read.port(IN_NULL)) graph.connect("Read.OUT", "Discard.IN") run_graph(graph) assert dis.values == ['000002', '000001']
def test_synced_receive3(graph, discard): # contains the call to synced: graph.add_component("Merge", Group) dis = graph.add_component("Discard", discard) graph.connect("Merge.OUT", "Discard.IN") run_graph(graph) assert dis.values == []
def test_first(graph, discard): graph.add_component("Generate", GenerateTestData, COUNT=4) graph.add_component("First", First) dis = graph.add_component("Discard", discard) graph.connect("Generate.OUT", "First.IN") graph.connect("First.OUT", "Discard.IN") run_graph(graph) assert dis.values == ['000004']
def test_fixed_size_array(graph, discard): graph.add_component("Generate", GenerateFixedSizeArray) dis1 = graph.add_component("Discard1", discard) dis2 = graph.add_component("Discard2", discard) graph.connect("Generate.OUT[0]", "Discard1.IN") graph.connect("Generate.OUT[1]", "Discard2.IN") graph.initialize(5, "Generate.COUNT") run_graph(graph) assert dis1.values == ['000005', '000004', '000003', '000002', '000001'] assert dis2.values == ['000005', '000004', '000003', '000002', '000001']
def test_unconnected_output_array_element(graph, discard): """if an array port does not specify fixed_size, some elements may remain unconnected """ graph.add_component("generate", GenerateTestData) graph.add_component("replicate", Replicate) graph.add_component("discard", discard) graph.connect("generate.OUT", "replicate.IN") graph.connect("replicate.OUT[2]", "discard.IN") graph.initialize(10, "generate.COUNT") run_graph(graph)
def test_inport_closed_propagation(graph, discard): """If a downstream inport is closed, the upstream component should shut down""" graph.add_component("Generate", GenerateTestDataDumb, COUNT=5) graph.add_component("First", First) # receives one packet then closes IN dis = graph.add_component("Discard", discard) graph.connect("Generate.OUT", "First.IN") graph.connect("First.OUT", "Discard.IN") run_graph(graph) assert dis.values == ['000005']
def test_readme_example(graph, discard): graph.add_component("LineToWords", LineToWords, IN="HeLLo GoodbYe WOrld") graph.add_component("StartsWith", StartsWith, TEST='G') graph.add_component("LowerCase", LowerCase) graph.add_component("WordsToLine", WordsToLine) dis = graph.add_component("Discard", discard) graph.connect("LineToWords.OUT", "StartsWith.IN") graph.connect("StartsWith.REJ", "LowerCase.IN") graph.connect("LowerCase.OUT", "WordsToLine.IN") graph.connect("WordsToLine.OUT", "Discard.IN") run_graph(graph) assert dis.values == ['hello world']
def test_null_ports(graph, tmpdir, discard): """null ports ensure proper ordering of components""" tempfile = str(tmpdir.join('data.txt')) graph.add_component("Generate", GenerateTestData, COUNT=5) write = graph.add_component("Write", WriteLines, FILEPATH=tempfile) read = graph.add_component("Read", ReadLines, FILEPATH=tempfile) dis = graph.add_component("Discard", discard) graph.connect("Generate.OUT", "Write.IN") graph.connect(write.port(OUT_NULL), read.port(IN_NULL)) graph.connect("Read.OUT", "Discard.IN") run_graph(graph) assert dis.values == ['000005', '000004', '000003', '000002', '000001']
def test_optional_fixed_size_array(graph, discard): """if an array port specifies fixed_size, some elements may remain unconnected if the array port is not required""" # fixed_size of 4 graph.add_component("Generate", GenerateOptionalFixedArray) dis1 = graph.add_component("Discard1", discard) dis2 = graph.add_component("Discard2", discard) # only two connected graph.connect("Generate.OUT", "Discard1.IN") graph.connect("Generate.OUT[2]", "Discard2.IN") graph.initialize(5, "Generate.COUNT") run_graph(graph) assert dis1.values == ['000005', '000004', '000003', '000002', '000001'] assert dis2.values == ['000005', '000004', '000003', '000002', '000001']
def test_merge_sort_drop(graph, discard): graph.add_component("_Generate", GenerateTestData, COUNT=4) graph.add_component("_Generate2", GenerateTestData, COUNT=4) graph.add_component("_Sort", Sort) dis = graph.add_component("_Discard", discard) graph.add_component("Passthru", Passthru) graph.add_component("Passthru2", Passthru) graph.connect("_Generate2.OUT", "Passthru2.IN") graph.connect("_Generate.OUT", "Passthru.IN") graph.connect("Passthru2.OUT", "Passthru.IN") graph.connect("Passthru.OUT", "_Sort.IN") graph.connect("_Sort.OUT", "_Discard.IN") run_graph(graph) assert dis.values == [ '000001', '000001', '000002', '000002', '000003', '000003', '000004', '000004' ]
def test_synced_receive1(graph, discard): """ components using `fn.synced` (Group) close all synced inports on the first exhausted inport. """ graph.add_component("Generate5", GenerateTestData, COUNT=5) graph.add_component("Generate3", GenerateTestData, COUNT=3) # contains the call to synced: graph.add_component("Merge", Group) dis = graph.add_component("Discard", discard) graph.connect("Generate5.OUT", "Merge.IN[0]") graph.connect("Generate3.OUT", "Merge.IN[1]") graph.initialize('initial', "Merge.IN[2]") graph.connect("Merge.OUT", "Discard.IN") run_graph(graph) assert dis.values == [ ('000005', '000003', 'initial'), ('000004', '000002', 'initial'), ('000003', '000001', 'initial'), ]
def test_initialize_subnet(): @outport("OUT") @inport("IN") @subnet def PassNet(sub): sub.add_component('Head', Passthru) sub.add_component('Tail', Passthru) sub.connect('Head.OUT', 'Tail.IN') sub.export('Head.IN', 'IN') sub.export('Tail.OUT', 'OUT') graph = Graph() capture = graph.add_component('Capture', Capture) graph.add_component('Pass', PassNet) graph.initialize(5, 'Pass.IN') graph.connect('Pass.OUT', 'Capture.IN') run_graph(graph) assert capture.value == 5
def test_synced_receive2(graph, discard): """ components using `fn.synced` (Group) close all synced inports on the first exhausted inport. """ graph.add_component("Generate5", GenerateTestData, COUNT=5) graph.add_component("Generate3", GenerateTestData, COUNT=3) # repeat infinitely: graph.add_component("Repeat", Repeat, IN='initial') # FIXME: this fails when COUNT=1 # contains the call to synced: graph.add_component("Merge", Group) dis = graph.add_component("Discard", discard) graph.connect("Generate5.OUT", "Merge.IN[0]") graph.connect("Generate3.OUT", "Merge.IN[1]") graph.connect('Repeat.OUT', "Merge.IN[2]") graph.connect("Merge.OUT", "Discard.IN") run_graph(graph) assert dis.values == [('000005', '000003', 'initial'), ('000004', '000002', 'initial'), ('000003', '000001', 'initial')]
def test_subnet_decorator(): @outport("OUT") @inport("IN", description='an input') @subnet def DecoratedPassNet(sub): sub.add_component('Head', SlowPass, DELAY=0.01) sub.add_component('Tail', SlowPass, DELAY=0.01) sub.connect('Head.OUT', 'Tail.IN') sub.export('Head.IN', 'IN') sub.export('Tail.OUT', 'OUT') assert issubclass(DecoratedPassNet, SubGraph) assert DecoratedPassNet._inport_definitions[0].description == 'an input' assert DecoratedPassNet.inport_definitions['IN'].description == 'an input' graph = Graph() gen = graph.add_component("Generate", GenSS, COUNT=5) passnet = graph.add_component("Subnet", DecoratedPassNet) dis = graph.add_component("Discard", Discard) graph.connect("Generate.OUT", "Subnet.IN") graph.connect("Subnet.OUT", "Discard.IN") run_graph(graph) assert dis.values == [ '', '000005', '000004', '000003', '000002', '000001', '', ]
def test_fib(graph): """ Make fibonacci sequence from completely reusable parts. """ graph.add_component("Add", Add) # oscillates between its two inputs: graph.add_component("Split", RoundRobinSplit) # kicks off the initial values: graph.add_component("Zero", Inject, CONST=0) graph.add_component("One", Inject, CONST=1) # doubles up the streams because they are consumed in pairs by Add: # Split.OUT[0]: 0 1 1 3 3 8 8 # Split.OUT[1]: 1 1 2 2 5 5 13 graph.add_component("Repeat1", Repeat, COUNT=2) graph.add_component("Repeat2", Repeat, COUNT=2) # set a max value to the sequence graph.add_component("Cap", Cap, MAX=30) pthru = graph.add_component("Passthru", Passthru) # need to use inject because you can't mix static value and connection graph.connect("Zero.OUT", "Add.IN1") graph.connect("Repeat1.OUT", "Add.IN1") graph.connect("Split.OUT[0]", "Repeat1.IN") # need to use inject because you can't mix static value and connection graph.connect("One.OUT", "Repeat2.IN") graph.connect("Split.OUT[1]", "Repeat2.IN") graph.connect("Repeat2.OUT", "Add.IN2") graph.connect("Add.OUT", "Cap.IN") graph.connect("Cap.OUT", "Passthru.IN") # complete the loop: graph.connect("Passthru.OUT", "Split.IN") run_graph(graph) # FIXME: where's the 0? assert pthru.values == [1, 2, 3, 5, 8, 13, 21]
def test_network_apply_with_outputs(): graph = Graph() graph.add_component('Add1', Add) graph.add_component('Add2', Add) graph.add_component('Kick', Kick) graph.connect('Add1.OUT', 'Add2.IN1') graph.export('Add1.IN1', 'IN1') graph.export('Add1.IN2', 'IN2') graph.export('Add2.IN2', 'IN3') graph.export('Add2.OUT', 'OUT') graph.export('Kick.OUT', 'Kick_OUT') outputs = run_graph(graph, {'IN1': 1, 'IN2': 3, 'IN3': 6}, ['OUT']) assert outputs == {'OUT': 10}
def test_network_apply(): graph = Graph() graph.add_component('Add1', Add) graph.add_component('Add2', Add) graph.connect('Add1.OUT', 'Add2.IN1') graph.export('Add1.IN1', 'IN1') graph.export('Add1.IN2', 'IN2') graph.export('Add2.IN2', 'IN3') graph.export('Add2.OUT', 'OUT') outputs = run_graph(graph, { 'IN1': 1, 'IN2': 3, 'IN3': 6 }, capture_results=True) assert outputs['OUT'] == 10