예제 #1
0
def test_get_nodes():
    in_node = EONode(InputTask())
    inc_node0 = EONode(IncTask(), inputs=[in_node])
    inc_node1 = EONode(IncTask(), inputs=[inc_node0])
    inc_node2 = EONode(IncTask(), inputs=[inc_node1])
    output_node = EONode(OutputTask(name="out"), inputs=[inc_node2])

    eow = EOWorkflow([in_node, inc_node0, inc_node1, inc_node2, output_node])

    returned_nodes = eow.get_nodes()

    assert [
        in_node,
        inc_node0,
        inc_node1,
        inc_node2,
        output_node,
    ] == returned_nodes, "Returned nodes differ from original nodes"

    arguments_dict = {in_node: {"val": 2}, inc_node0: {"d": 2}}
    workflow_res = eow.execute(arguments_dict)

    manual_res = []
    for _, node in enumerate(returned_nodes):
        manual_res = [
            node.task.execute(*manual_res, **arguments_dict.get(node, {}))
        ]

    assert workflow_res.outputs["out"] == manual_res[
        0], "Manually running returned nodes produces different results."
예제 #2
0
def test_exception_handling():
    input_node = EONode(InputTask(), name="xyz")
    exception_node = EONode(ExceptionTask(), inputs=[input_node])
    increase_node = EONode(IncTask(), inputs=[exception_node])
    workflow = EOWorkflow([input_node, exception_node, increase_node])

    with pytest.raises(CustomException):
        workflow.execute()

    results = workflow.execute(raise_errors=False)

    assert results.outputs == {}
    assert results.error_node_uid == exception_node.uid
    assert len(results.stats) == 2

    for node in [input_node, exception_node]:
        node_stats = results.stats[node.uid]

        assert node_stats.node_uid == node.uid
        assert node_stats.node_name == node.name

        if node is exception_node:
            assert isinstance(node_stats.exception, CustomException)
            assert node_stats.exception_traceback.startswith("Traceback")
        else:
            assert node_stats.exception is None
            assert node_stats.exception_traceback is None
예제 #3
0
def test_workflow_arguments():
    input_node1 = EONode(InputTask())
    input_node2 = EONode(InputTask(), name="some name")
    divide_node = EONode(DivideTask(),
                         inputs=(input_node1, input_node2),
                         name="some name")
    output_node = EONode(OutputTask(name="output"), inputs=[divide_node])

    workflow = EOWorkflow([input_node1, input_node2, divide_node, output_node])

    with concurrent.futures.ProcessPoolExecutor(max_workers=5) as executor:
        k2future = {
            k: executor.submit(workflow.execute, {
                input_node1: {
                    "val": k**3
                },
                input_node2: {
                    "val": k**2
                }
            })
            for k in range(2, 100)
        }
        executor.shutdown()
        for k in range(2, 100):
            assert k2future[k].result().outputs["output"] == k

    result1 = workflow.execute({
        input_node1: {
            "val": 15
        },
        input_node2: {
            "val": 3
        }
    })
    assert result1.outputs["output"] == 5

    result2 = workflow.execute({
        input_node1: {
            "val": 6
        },
        input_node2: {
            "val": 3
        }
    })
    assert result2.outputs["output"] == 2

    result3 = workflow.execute({
        input_node1: {
            "val": 6
        },
        input_node2: {
            "val": 3
        },
        divide_node: {
            "z": 1
        }
    })
    assert result3.outputs[output_node.task.name] == 3
def test_output_task_in_workflow(test_eopatch_path, test_eopatch):
    load = EONode(LoadTask(test_eopatch_path))
    output = EONode(OutputTask(name="result-name"), inputs=[load])

    workflow = EOWorkflow([load, output, EONode(DummyTask(), inputs=[load])])

    results = workflow.execute()

    assert len(results.outputs) == 1
    assert results.outputs["result-name"] == test_eopatch
예제 #5
0
def test_multiedge_workflow():
    in_node = EONode(InputTask())
    inc_node = EONode(IncTask(), inputs=[in_node])
    div_node = EONode(DivideTask(), inputs=[inc_node, inc_node])
    output_node = EONode(OutputTask(name="out"), inputs=[div_node])

    workflow = EOWorkflow([in_node, output_node, inc_node, div_node])
    arguments_dict = {in_node: {"val": 2}}
    workflow_res = workflow.execute(arguments_dict)

    assert workflow_res.outputs["out"] == 1
예제 #6
0
def test_get_node_with_uid():
    in_node = EONode(InputTask())
    inc_node = EONode(IncTask(), inputs=[in_node])
    output_node = EONode(OutputTask(name="out"), inputs=[inc_node])

    eow = EOWorkflow([in_node, inc_node, output_node])

    assert all(node == eow.get_node_with_uid(node.uid)
               for node in (in_node, inc_node, output_node))
    assert eow.get_node_with_uid("nonexsitant") is None
    with pytest.raises(KeyError):
        eow.get_node_with_uid("nonexsitant", fail_if_missing=True)
예제 #7
0
def test_workflows_reusing_nodes():

    in_node = EONode(InputTask())
    node1 = EONode(IncTask(), inputs=[in_node])
    node2 = EONode(IncTask(), inputs=[node1])
    out_node = EONode(OutputTask(name="out"), inputs=[node2])
    input_args = {in_node: {"val": 2}, node2: {"d": 2}}

    original = EOWorkflow([in_node, node1, node2, out_node])
    node_reuse = EOWorkflow([in_node, node1, node2, out_node])

    assert original.execute(input_args).outputs["out"] == node_reuse.execute(
        input_args).outputs["out"]
예제 #8
0
def test_run_after_interrupt(workflow, execution_kwargs, simple_cluster):
    foo_node = EONode(FooTask())
    exception_node = EONode(KeyboardExceptionTask(), inputs=[foo_node])
    exception_workflow = EOWorkflow([foo_node, exception_node])
    exception_executor = RayExecutor(exception_workflow, [{}])
    executor = RayExecutor(workflow,
                           execution_kwargs[:-1])  # removes args for exception

    result_preexception = executor.run()
    with pytest.raises(
        (ray.exceptions.TaskCancelledError, ray.exceptions.RayTaskError)):
        exception_executor.run()
    result_postexception = executor.run()

    assert [res.outputs for res in result_preexception
            ] == [res.outputs for res in result_postexception]
예제 #9
0
def test_nodes_different_uids():
    uids = set()
    for _ in range(5000):
        node = EONode(Inc())
        uids.add(node.uid)

    assert len(uids) == 5000, "Different nodes should have different uids."
예제 #10
0
def test_workflow_from_endnodes():
    input_node1 = EONode(InputTask())
    input_node2 = EONode(InputTask(), name="some name")
    divide_node = EONode(DivideTask(),
                         inputs=(input_node1, input_node2),
                         name="some name")
    output_node = EONode(OutputTask(name="out"), inputs=[divide_node])

    regular_workflow = EOWorkflow(
        [input_node1, input_node2, divide_node, output_node])
    endnode_workflow = EOWorkflow.from_endnodes(output_node)

    assert isinstance(endnode_workflow, EOWorkflow)
    assert set(endnode_workflow.get_nodes()) == set(
        regular_workflow.get_nodes()), "Nodes are different"

    with concurrent.futures.ProcessPoolExecutor(max_workers=5) as executor:
        regular_results = [
            executor.submit(regular_workflow.execute, {
                input_node1: {
                    "val": k**3
                },
                input_node2: {
                    "val": k**2
                }
            }) for k in range(2, 100)
        ]
        endnode_results = [
            executor.submit(endnode_workflow.execute, {
                input_node1: {
                    "val": k**3
                },
                input_node2: {
                    "val": k**2
                }
            }) for k in range(2, 100)
        ]
        executor.shutdown()
        assert all(x.result().outputs["out"] == y.result().outputs["out"]
                   for x, y in zip(regular_results, endnode_results))

    endnode_duplicates = EOWorkflow.from_endnodes(output_node, output_node,
                                                  divide_node)
    assert set(endnode_duplicates.get_nodes()) == set(
        regular_workflow.get_nodes()), "Fails if endnodes are repeated"
예제 #11
0
def test_keyboard_interrupt(simple_cluster):
    exception_node = EONode(KeyboardExceptionTask())
    workflow = EOWorkflow([exception_node])
    execution_kwargs = []
    for _ in range(10):
        execution_kwargs.append({exception_node: {"arg1": 1}})

    with pytest.raises(
        (ray.exceptions.TaskCancelledError, ray.exceptions.RayTaskError)):
        RayExecutor(workflow, execution_kwargs).run()
예제 #12
0
def test_keyboard_interrupt():
    exception_node = EONode(KeyboardExceptionTask())
    workflow = EOWorkflow([exception_node])
    execution_kwargs = []
    for _ in range(10):
        execution_kwargs.append({exception_node: {"arg1": 1}})

    run_kwargs = [{"workers": 1}, {"workers": 3, "multiprocess": True}, {"workers": 3, "multiprocess": False}]
    for kwarg in run_kwargs:
        with pytest.raises(KeyboardInterrupt):
            EOExecutor(workflow, execution_kwargs).run(**kwarg)
예제 #13
0
def test_workflow_copying_eopatches():
    feature1 = FeatureType.DATA, "data1"
    feature2 = FeatureType.DATA, "data2"

    create_node = EONode(CreateEOPatchTask())
    init_node = EONode(
        InitializeFeatureTask([feature1, feature2],
                              shape=(2, 4, 4, 3),
                              init_value=1),
        inputs=[create_node],
    )
    remove_node1 = EONode(RemoveFeatureTask([feature1]), inputs=[init_node])
    remove_node2 = EONode(RemoveFeatureTask([feature2]), inputs=[init_node])
    output_node1 = EONode(OutputTask(name="out1"), inputs=[remove_node1])
    output_node2 = EONode(OutputTask(name="out2"), inputs=[remove_node2])

    workflow = EOWorkflow([
        create_node, init_node, remove_node1, remove_node2, output_node1,
        output_node2
    ])
    results = workflow.execute()

    eop1 = results.outputs["out1"]
    eop2 = results.outputs["out2"]

    assert eop1 == EOPatch(
        data={"data2": np.ones((2, 4, 4, 3), dtype=np.uint8)})
    assert eop2 == EOPatch(
        data={"data1": np.ones((2, 4, 4, 3), dtype=np.uint8)})
예제 #14
0
def test_workflow_results():
    input_node = EONode(InputTask())
    output_node = EONode(OutputTask(name="out"), inputs=[input_node])
    workflow = EOWorkflow([input_node, output_node])

    results = workflow.execute({input_node: {"val": 10}})

    assert isinstance(results, WorkflowResults)
    assert results.outputs == {"out": 10}

    results_without_outputs = results.drop_outputs()
    assert results_without_outputs.outputs == {}
    assert id(results_without_outputs) != id(results)

    assert isinstance(results.start_time, dt.datetime)
    assert isinstance(results.end_time, dt.datetime)
    assert results.start_time < results.end_time < dt.datetime.now()

    assert isinstance(results.stats, dict)
    assert len(results.stats) == 2
    for node in [input_node, output_node]:
        stats_uid = node.uid
        assert isinstance(results.stats.get(stats_uid), NodeStats)
예제 #15
0
def test_bad_structure_exceptions():
    in_node = EONode(InputTask())
    inc_node0 = EONode(IncTask(), inputs=[in_node])
    inc_node1 = EONode(IncTask(), inputs=[inc_node0])
    inc_node2 = EONode(IncTask(), inputs=[inc_node1])
    output_node = EONode(OutputTask(name="out"), inputs=[inc_node2])

    # This one must work
    EOWorkflow([in_node, inc_node0, inc_node1, inc_node2, output_node])

    # Duplicated node
    with pytest.raises(ValueError):
        EOWorkflow(
            [in_node, inc_node0, inc_node0, inc_node1, inc_node2, output_node])

    # Missing node
    with pytest.raises(ValueError):
        EOWorkflow([in_node, inc_node0, inc_node2, output_node])

    # Create circle (much more difficult now)
    super(EONode, inc_node0).__setattr__("inputs", (inc_node1, ))
    with pytest.raises(ValueError):
        EOWorkflow([in_node, inc_node0, inc_node1, inc_node2, output_node])
예제 #16
0
def test_get_dependencies():
    input_node1 = EONode(InputTask())
    input_node2 = EONode(InputTask(), name="some name")
    divide_node1 = EONode(DivideTask(),
                          inputs=(input_node1, input_node2),
                          name="some name")
    divide_node2 = EONode(DivideTask(),
                          inputs=(divide_node1, input_node2),
                          name="some name")
    output_node = EONode(OutputTask(name="output"), inputs=[divide_node2])
    all_nodes = {
        input_node1, input_node2, divide_node1, divide_node2, output_node
    }

    assert len(output_node.get_dependencies()) == len(
        all_nodes), "Wrong number of nodes returned"

    assert all_nodes == set(output_node.get_dependencies())
예제 #17
0
def test_nodes_fixture():
    example = EONode(ExampleTask())
    foo = EONode(FooTask(), inputs=[example, example])
    output = EONode(OutputTask("output"), inputs=[foo])
    nodes = {"example": example, "foo": foo, "output": output}
    return nodes
예제 #18
0
    output_node = EONode(OutputTask(name="out"), inputs=[inc_node])

    eow = EOWorkflow([in_node, inc_node, output_node])

    assert all(node == eow.get_node_with_uid(node.uid)
               for node in (in_node, inc_node, output_node))
    assert eow.get_node_with_uid("nonexsitant") is None
    with pytest.raises(KeyError):
        eow.get_node_with_uid("nonexsitant", fail_if_missing=True)


@pytest.mark.parametrize(
    "faulty_parameters",
    [
        [InputTask(), IncTask(), IncTask()],
        EONode(InputTask()),
        [EONode(IncTask()), IncTask()],
        [EONode(IncTask()), (EONode(IncTask()), "name")],
        [EONode(IncTask()), (EONode(IncTask(), inputs=[EONode(IncTask())]))],
        [EONode(IncTask()), (EONode(IncTask()), IncTask())],
    ],
)
def test_input_exceptions(faulty_parameters):
    with pytest.raises(ValueError):
        EOWorkflow(faulty_parameters)


def test_bad_structure_exceptions():
    in_node = EONode(InputTask())
    inc_node0 = EONode(IncTask(), inputs=[in_node])
    inc_node1 = EONode(IncTask(), inputs=[inc_node0])
예제 #19
0
class ExampleTask(EOTask):
    def execute(self, *_, **kwargs):
        my_logger = logging.getLogger(__file__)
        my_logger.info("Info statement of Example task with kwargs: %s",
                       kwargs)
        my_logger.warning("Warning statement of Example task with kwargs: %s",
                          kwargs)
        my_logger.debug("Debug statement of Example task with kwargs: %s",
                        kwargs)

        if "arg1" in kwargs and kwargs["arg1"] is None:
            raise Exception


NODE = EONode(ExampleTask())
WORKFLOW = EOWorkflow([NODE, EONode(task=ExampleTask(), inputs=[NODE, NODE])])
EXECUTION_KWARGS = [{
    NODE: {
        "arg1": 1
    }
}, {}, {
    NODE: {
        "arg1": 3,
        "arg3": 10
    }
}, {
    NODE: {
        "arg1": None
    }
}]
예제 #20
0
def workflow_fixture():
    node1, node2 = EONode(FooTask()), EONode(FooTask())
    node3 = EONode(FooTask(), [node1, node2])

    workflow = EOWorkflow([node1, node2, node3])
    return workflow