def test_quick_wire_to_input_array_with_set_sample(session): canvas = Planner(session) frags = session.Sample.where( {"sample_type_id": session.SampleType.find_by_name("Fragment").id}, opts={"limit": 10}, ) purify1 = canvas.create_operation_by_name("Purify Gel Slice", category="Cloning") purify2 = canvas.create_operation_by_name("Purify Gel Slice", category="Cloning") canvas.set_field_value(purify1.inputs[0], sample=frags[0]) canvas.set_field_value(purify2.inputs[0], sample=frags[1]) assemble = canvas.create_operation_by_name("Assemble Plasmid", category="Cloning") canvas.quick_wire(purify1, assemble) canvas.quick_wire(purify2, assemble) canvas.chain("Purify Gel Slice", assemble, category="Cloning") input_array = assemble.input_array("Fragment") assert len(input_array) == 3, "There should be 3 field values" assert input_array[0].sample == frags[0] assert input_array[1].sample == frags[1] assert input_array[2].sample is None
def test_quick_wire_to_input_array(session): canvas = Planner(session) ops = canvas.chain("Purify Gel Slice", "Assemble Plasmid", category="Cloning") canvas.chain("Purify Gel Slice", ops[-1], category="Cloning") assert len(canvas.plan.operations) == 3 assert len(canvas.plan.wires) == 2
def test_topo_sort_with_independent_subgraphs(self, session): canvas = Planner(session) ops1 = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", category="Cloning", ) ops2 = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", category="Cloning", ) ops3 = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", category="Cloning", ) canvas.layout.topo_sort() print([op.x for op in ops1]) print([op.x for op in ops2]) print([op.x for op in ops3]) assert ops3[0].x + canvas.layout.BOX_DELTA_X == ops2[0].x assert ops2[0].x + canvas.layout.BOX_DELTA_X == ops1[0].x
def test_set_input_array(session): canvas = Planner(session) op = canvas.create_operation_by_name("Assemble Plasmid", category="Cloning") frags = session.Sample.where( {"sample_type_id": session.SampleType.find_by_name("Fragment").id}, opts={"limit": 10}, ) canvas.set_input_field_value_array(op, "Fragment", sample=frags[0]) canvas.set_input_field_value_array(op, "Fragment", sample=frags[1]) input_array = op.input_array("Fragment") assert ( len(op.input_array("Fragment")) == 2 ), "There should be exactly 2 field values in the input array" assert ( input_array[0] != input_array[1] ), "Input array field values should be different" assert len(op.input_array("Fragment")) == 2 assert ( op.input_array("Fragment")[0].sample == frags[0] ), "Input array 0 should have fragment 0" assert ( op.input_array("Fragment")[1].sample == frags[1] ), "Input array 1 should have fragment 1"
def test_collect_matching_afts(session): canvas = Planner(session) op1 = canvas.create_operation_by_name("Check Plate", category="Cloning") op2 = canvas.create_operation_by_name("E Coli Lysate", category="Cloning") afts = canvas._collect_matching_afts(op1, op2) print(afts)
def test_canvas_quick_create_chain(session): canvas = Planner(session) canvas.chain( "Yeast Transformation", "Check Yeast Plate", "Yeast Overnight Suspension" ) assert len(canvas.plan.operations) == 3 assert len(canvas.plan.wires) == 2, "There should be two operations"
def test_raise_exception_if_wiring_two_outputs(session): canvas = Planner(session) assert len(canvas.plan.wires) == 0 op1 = canvas.create_operation_by_name("Check Plate", category="Cloning") op2 = canvas.create_operation_by_name("Check Plate", category="Cloning") with pytest.raises(PlannerException): canvas.add_wire(op1.outputs[0], op2.outputs[0])
def planner_example(session): num_chains = 4 with session.with_cache() as sess: p = Planner(sess) for _ in range(num_chains): p.chain("Make PCR Fragment", "Run Gel", "Extract Gel Slice", "Purify Gel Slice") p.plan.id = 1234 return p
def test_canvas_add_op(session): canvas = Planner(session) canvas.create_operation_by_name("Yeast Transformation") canvas.create_operation_by_name("Yeast Antibiotic Plating") canvas.quick_wire_by_name("Yeast Transformation", "Yeast Antibiotic Plating") canvas.create() p = session.Plan.find(canvas.plan.id) pass
def test_plan_validate_with_no_errors(session): """An easy to pass test. A plan that is complete should always pass the validation method. """ session.set_verbose(True) plan = session.Plan.one(query='status != "planning"') assert plan canvas = Planner(plan) canvas.validate()
def test_layout(self, session): canvas = Planner(session) canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) assert canvas.layout is not None
def test_annotate(session): canvas = Planner(session) a = canvas.annotate("This is my annotation", 10, 20, 110, 100) assert a["x"] == 10 assert a["y"] == 20 anchor = a["anchor"] assert anchor["x"] == 110 assert anchor["y"] == 100
def test_collect_predecessors(self, session): canvas = Planner(session) ops = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) s = canvas.layout.collect_predecessors(["r{}".format(ops[1].rid)]) assert s == ["r{}".format(ops[0].rid)]
def test_inventory_updater(session): ot = session.ObjectType.one(query="rows > 2 AND columns > 2") collection = session.Collection.new(object_type=ot) primer = session.SampleType.find_by_name("Primer") fragment = session.SampleType.find_by_name("Fragment") plasmid = session.SampleType.find_by_name("Plasmid") yeast = session.SampleType.find_by_name("Yeast Strain") frag = fragment.new_sample( str(uuid4()), project="test", description="", properties={ "Forward Primer": primer.new_sample( str(uuid4()), project="test", description="", properties={ "Anneal Sequence": "AGGGATAT", "T Anneal": 50 }, ), "Length": 1000, "Sequence": "", }, ) collection[0, 0] = frag item = session.Item.new( object_type=session.ObjectType.find_by_name("Fragment Stock"), sample=collection.sample_matrix[0, 0], ) print(item.object_type) planner = Planner(session) op = planner.create_operation_by_name("Make PCR Fragment") planner.set_field_value(op.input("Template"), item=item) saved = save_inventory(session, [planner.plan, collection]) # assert frag in saved assert frag.id assert frag.properties["Forward Primer"].id assert item.id assert planner.plan.id assert collection.id save_inventory(session, [planner.plan, collection], merge_samples=True)
def test_layout_edges_and_nodes(session): canvas = Planner(session) canvas.chain( "Yeast Transformation", "Check Yeast Plate", "Yeast Overnight Suspension" ) G = canvas.layout.nxgraph edges = list(G.edges) assert len(edges) == 2, "There should only be 2 edges/wires in the graph/plan" assert ( len(G.nodes) == 3 ), "There should only be 3 nodes/Operations in the graph/plan" assert edges[0][1] == edges[1][0], "Check Yeast Plate should be in both wires"
def test_subgraph(self, session): canvas = Planner(session) ops = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) graph = canvas.layout.ops_to_subgraph(ops[-2:]) assert len(graph) == 2 canvas.layout.topo_sort()
def test_optimize_case1(self, session): """Here, we are trying to optimize two chains of 5 operations. Since Yeast Transformation is missing an input sample and Yeast Overnight Suspension is missing a output sample, these will NOT be merged, and so we expect 7 operations after the merge procedure. """ with session.with_cache() as sess: canvas = Planner(sess) q = self.sql({ "object_type_id": sess.ObjectType.find_by_name("E coli Plate of Plasmid").id, "location": self.Not("deleted"), }) item = sess.Item.one(query=q) assert item chain = [ "Check Plate", "Make Overnight Suspension", "Make Miniprep", "Yeast Transformation", "Yeast Overnight Suspension", ] for i in range(2): ops = canvas.chain(*chain) canvas.set_field_value_and_propogate(ops[0].inputs[0], sample=item.sample) canvas.set_to_available_item(ops[0].inputs[0]) assert len(canvas.plan.operations) == 10 canvas.optimize() # we expect to merge everything except 'Yeast Transformation' and # 'Yeast Overnight' since these have absent sample definition for either # their input or outputs and FieldValues with no samples are never mergable. expected_op_types = [ "Check Plate", "Make Miniprep", "Make Overnight Suspension", "Yeast Overnight Suspension", "Yeast Overnight Suspension", "Yeast Transformation", "Yeast Transformation", ] op_types = sorted( [op.operation_type.name for op in canvas.operations]) assert len(canvas.plan.operations) == 7 assert expected_op_types == op_types
def test_routing_graph(session): canvas = Planner(session) ops = canvas.chain( "Rehydrate Primer", "Make PCR Fragment", "Run Gel", "Extract Gel Slice", "Purify Gel Slice", "Assemble Plasmid", category="Cloning", ) routing_graph = canvas._routing_graph() print(get_subgraphs(routing_graph))
def test_load_plans(session): with session.with_cache() as sess: ops = sess.Operation.last(10, query={"status": "done"}) plans = sess.browser.get("Operation", "plans") for plan in plans: Planner(plan)
def test_optimize_case3_array_inputs(self, session): """Here we test whether operation types with field_value array inputs are mergable despite being in a different order.""" with session.with_cache() as sess: canvas = Planner(sess) q = self.sql({ "object_type_id": sess.ObjectType.find_by_name("Fragment Stock").id, "location": self.Not("deleted"), }) items = sess.Item.last(4, query=q) assert items assemble_op1 = canvas.create_operation_by_name("Assemble Plasmid") assemble_op2 = canvas.create_operation_by_name("Assemble Plasmid") assemble_op3 = canvas.create_operation_by_name("Assemble Plasmid") assemble_op4 = canvas.create_operation_by_name("Assemble Plasmid") assemble_op1.add_to_input_array("Fragment", item=items[0]) assemble_op1.add_to_input_array("Fragment", item=items[1]) assemble_op2.add_to_input_array("Fragment", item=items[0]) assemble_op2.add_to_input_array("Fragment", item=items[1]) assemble_op3.add_to_input_array("Fragment", item=items[1]) assemble_op3.add_to_input_array("Fragment", item=items[0]) assemble_op4.add_to_input_array("Fragment", item=items[1]) assemble_op4.add_to_input_array("Fragment", item=items[2]) sample = sess.Sample.one(query={ "sample_type_id": sess.SampleType.find_by_name("Plasmid").id }) canvas.set_field_value(assemble_op1.outputs[0], sample=sample) canvas.set_field_value(assemble_op2.outputs[0], sample=sample) canvas.set_field_value(assemble_op3.outputs[0], sample=sample) canvas.set_field_value(assemble_op4.outputs[0], sample=sample) assert len(canvas.plan.operations) == 4 canvas.optimize() assert len(canvas.plan.operations) == 2
def test_topo_sort_chain(self, session): canvas = Planner(session) ops = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) ops[-1].x = 300 ops[-2].x = 200 ops[-3].x = 100 assert not len({op.x for op in ops}) == 1 canvas.layout.topo_sort() assert len({op.x for op in ops}) == 1
def test_roots(self, session): canvas = Planner(session) ops = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) canvas.chain( ops[0], "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) assert len(canvas.layout.roots()) == 1
def test_pickle_multiplan(session): p = session.Plan.find(33672) canvas = Planner(p) here = dirname(abspath(__file__)) with open(join(here, "multiplan.pkl"), "wb") as f: dill.dump(canvas, f)
def test_canvas_chaining(session): canvas = Planner(session) canvas.browser.log.set_verbose(True) ops = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) assert len(canvas.plan.wires) == 3 new_ops = [] for i in range(3): new_ops += canvas.chain( ops[-1], ("E Coli Lysate", "Cloning"), "E Coli Colony PCR" )[1:] assert len(canvas.plan.wires) == 2 * 3 + 3
def test_align_x_with_predecessors(self, session): canvas = Planner(session) ops = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) new_ops = canvas.get_op_by_name("E Coli Lysate") print(len(new_ops)) for _ in range(3): print("created") canvas.chain(ops[-1], "E Coli Lysate", category="Cloning") new_ops = canvas.get_op_by_name("E Coli Lysate") print(len(new_ops)) new_ops[0].x = 0 new_ops[1].x = 100 new_ops[2].x = 150 ops_layout = canvas.layout.ops_to_subgraph(ops) new_op_layout = canvas.layout.ops_to_subgraph(new_ops) midpoint = new_op_layout.midpoint() assert midpoint[0] == 75, "should be midpoint between 0 and 150" assert midpoint[0] != ops_layout.midpoint()[0] new_op_layout.align_x_midpoints_to(ops_layout) for op in new_op_layout.operations: print(op.rid) print(op.x) print() assert new_op_layout.midpoint()[0] == ops_layout.midpoint()[0]
def test_topo_sort(self, session): canvas = Planner(session) ops = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) ops[-1].x = 500 for _ in range(3): canvas.chain(ops[-1], ("E Coli Lysate", "Cloning"), "E Coli Colony PCR") lysate = canvas.get_op_by_name("E Coli Lysate") pcr = canvas.get_op_by_name("E Coli Colony PCR") canvas.layout.ops_to_subgraph(pcr).translate(100, 100) assert not canvas.layout.ops_to_subgraph(lysate).midpoint()[0] == ops[-1].x assert ( not canvas.layout.ops_to_subgraph(lysate).midpoint()[0] == canvas.layout.ops_to_subgraph(pcr).midpoint()[0] ) canvas.layout.topo_sort() assert canvas.layout.ops_to_subgraph(lysate).midpoint()[0] == ops[-1].x assert ( canvas.layout.ops_to_subgraph(lysate).midpoint()[0] == canvas.layout.ops_to_subgraph(pcr).midpoint()[0] )
def test_combine_plans(planner_example): plans = planner_example.split() combined = Planner.combine(plans) assert len(combined.plan.operations) == len( planner_example.plan.operations ), "number of operations should remain the same" assert len(combined.plan.wires) == len( planner_example.plan.wires), "number of wires should remain the same"
def test_predecessor_layout(self, session): canvas = Planner(session) ops = canvas.chain( "Assemble Plasmid", "Transform Cells", "Plate Transformed Cells", "Check Plate", category="Cloning", ) new_ops = [] for _ in range(3): new_ops += canvas.chain( ops[-1], ("E Coli Lysate", "Cloning"), "E Coli Colony PCR" )[1:] assert len(new_ops) == 6 predecessor_layout = canvas.layout.predecessor_subgraph( canvas.layout.ops_to_subgraph(new_ops) ) assert len(predecessor_layout) == 1
def test_add_wire_sets_sample_from_source(session): session.set_verbose(True) canvas = Planner(session) assert len(canvas.plan.wires) == 0 p = session.Sample.one( query=dict(sample_type_id=session.SampleType.find_by_name("Primer").id) ) destination = canvas.create_operation_by_name( "Make PCR Fragment", category="Cloning" ) source = canvas.create_operation_by_name("Rehydrate Primer", category="Cloning") canvas.set_field_value(source.outputs[0], sample=p) canvas.add_wire(source.outputs[0], destination.input("Forward Primer")) assert destination.input("Forward Primer").sample.id == p.id
def test_quick_chain_to_existing_operation_too_many_times(session): canvas = Planner(session) op = canvas.create_operation_by_name("Yeast Transformation") op1 = canvas.chain(op, "Check Yeast Plate")[-1] with pytest.raises(PlannerException): canvas.chain("Yeast Transformation", op1) assert len(canvas.plan.wires) == 1