示例#1
0
def test_aliased_solids():
    @lambda_solid()
    def first():
        return ["first"]

    @lambda_solid(input_defs=[InputDefinition(name="prev")])
    def not_first(prev):
        return prev + ["not_first"]

    pipeline = PipelineDefinition(
        solid_defs=[first, not_first],
        name="test",
        dependencies={
            "not_first": {
                "prev": DependencyDefinition("first")
            },
            NodeInvocation("not_first", alias="second"): {
                "prev": DependencyDefinition("not_first")
            },
            NodeInvocation("not_first", alias="third"): {
                "prev": DependencyDefinition("second")
            },
        },
    )

    result = execute_pipeline(pipeline)
    assert result.success
    solid_result = result.result_for_solid("third")
    assert solid_result.output_value() == [
        "first", "not_first", "not_first", "not_first"
    ]
示例#2
0
def test_failure_hook_event():
    @failure_hook
    def a_hook(_):
        pass

    @solid
    def a_solid(_):
        pass

    @solid
    def failed_solid(_):
        raise SomeUserException()

    a_pipeline = PipelineDefinition(
        solid_defs=[a_solid, failed_solid],
        name="test",
        dependencies={
            NodeInvocation("a_solid", hook_defs={a_hook}): {},
            NodeInvocation("failed_solid", hook_defs={a_hook}): {},
        },
    )

    result = execute_pipeline(a_pipeline, raise_on_error=False)
    assert not result.success

    hook_events = list(filter(lambda event: event.is_hook_event, result.event_list))
    # when a hook is not triggered, we fire hook skipped event instead of completed
    assert len(hook_events) == 2
    for event in hook_events:
        if event.event_type == DagsterEventType.HOOK_COMPLETED:
            assert event.solid_name == "failed_solid"
        if event.event_type == DagsterEventType.HOOK_SKIPPED:
            assert event.solid_name == "a_solid"
示例#3
0
def test_required_inputs():
    @lambda_solid(input_defs=[InputDefinition("num", Int)],
                  output_def=OutputDefinition(Int))
    def add_one(num):
        return num + 1

    pipeline_def = PipelineDefinition(
        name="required_int_input",
        solid_defs=[add_one],
        dependencies={
            NodeInvocation("add_one", "first_add"): {},
            NodeInvocation("add_one", "second_add"): {
                "num": DependencyDefinition("first_add")
            },
        },
    )

    env_type = create_run_config_schema_type(pipeline_def)

    solids_type = env_type.fields["solids"].config_type

    first_add_fields = solids_type.fields["first_add"].config_type.fields

    assert "inputs" in first_add_fields

    inputs_field = first_add_fields["inputs"]

    assert inputs_field.is_required

    assert inputs_field.config_type.fields["num"].is_required

    # second_add has a dependency so the input is not available
    assert "inputs" not in solids_type.fields["second_add"].config_type.fields
示例#4
0
def test_success_hook():

    called_hook_to_solids = defaultdict(list)

    @success_hook
    def a_success_hook(context):
        called_hook_to_solids[context.hook_def.name].append(context.solid.name)

    @success_hook(name="a_named_success_hook")
    def named_success_hook(context):
        called_hook_to_solids[context.hook_def.name].append(context.solid.name)

    @success_hook(required_resource_keys={"resource_a"})
    def success_hook_resource(context):
        called_hook_to_solids[context.hook_def.name].append(context.solid.name)
        assert context.resources.resource_a == 1

    @solid
    def succeeded_solid(_):
        pass

    @solid
    def failed_solid(_):
        # this solid shouldn't trigger success hooks
        raise SomeUserException()

    a_pipeline = PipelineDefinition(
        solid_defs=[succeeded_solid, failed_solid],
        name="test",
        dependencies={
            NodeInvocation(
                "succeeded_solid",
                "succeeded_solid_with_hook",
                hook_defs={
                    a_success_hook, named_success_hook, success_hook_resource
                },
            ): {},
            NodeInvocation(
                "failed_solid",
                "failed_solid_with_hook",
                hook_defs={a_success_hook, named_success_hook},
            ): {},
        },
        mode_defs=[ModeDefinition(resource_defs={"resource_a": resource_a})],
    )

    result = execute_pipeline(a_pipeline, raise_on_error=False)
    assert not result.success

    # test if hooks are run for the given solids
    assert "succeeded_solid_with_hook" in called_hook_to_solids[
        "a_success_hook"]
    assert "succeeded_solid_with_hook" in called_hook_to_solids[
        "a_named_success_hook"]
    assert "succeeded_solid_with_hook" in called_hook_to_solids[
        "success_hook_resource"]
    assert "failed_solid_with_hook" not in called_hook_to_solids[
        "a_success_hook"]
    assert "failed_solid_with_hook" not in called_hook_to_solids[
        "a_named_success_hook"]
示例#5
0
def test_aliased_configs():
    @solid(input_defs=[], config_schema=Int)
    def load_constant(context):
        return context.solid_config

    pipeline = PipelineDefinition(
        solid_defs=[load_constant],
        name="test",
        dependencies={
            NodeInvocation(load_constant.name, "load_a"): {},
            NodeInvocation(load_constant.name, "load_b"): {},
        },
    )

    result = execute_pipeline(
        pipeline,
        {"solids": {
            "load_a": {
                "config": 2
            },
            "load_b": {
                "config": 3
            }
        }})

    assert result.success
    assert result.result_for_solid("load_a").output_value() == 2
    assert result.result_for_solid("load_b").output_value() == 3
示例#6
0
def test_nothing_inputs():
    @lambda_solid(input_defs=[InputDefinition("never_defined", Nothing)])
    def emit_one():
        return 1

    @lambda_solid
    def emit_two():
        return 2

    @lambda_solid
    def emit_three():
        return 3

    @lambda_solid(output_def=OutputDefinition(Nothing))
    def emit_nothing():
        pass

    @solid(input_defs=[
        InputDefinition("_one", Nothing),
        InputDefinition("one", Int),
        InputDefinition("_two", Nothing),
        InputDefinition("two", Int),
        InputDefinition("_three", Nothing),
        InputDefinition("three", Int),
    ])
    def adder(_context, one, two, three):
        assert one == 1
        assert two == 2
        assert three == 3
        return one + two + three

    pipeline = PipelineDefinition(
        name="input_test",
        solid_defs=[emit_one, emit_two, emit_three, emit_nothing, adder],
        dependencies={
            NodeInvocation("emit_nothing", "_one"): {},
            NodeInvocation("emit_nothing", "_two"): {},
            NodeInvocation("emit_nothing", "_three"): {},
            "adder": {
                "_one": DependencyDefinition("_one"),
                "_two": DependencyDefinition("_two"),
                "_three": DependencyDefinition("_three"),
                "one": DependencyDefinition("emit_one"),
                "two": DependencyDefinition("emit_two"),
                "three": DependencyDefinition("emit_three"),
            },
        },
    )
    result = execute_pipeline(pipeline)
    assert result.success
示例#7
0
def test_fanin_deps():
    called = defaultdict(int)

    @lambda_solid
    def emit_two():
        return 2

    @lambda_solid(output_def=OutputDefinition(Nothing))
    def emit_nothing():
        called["emit_nothing"] += 1

    @solid(input_defs=[
        InputDefinition("ready", Nothing),
        InputDefinition("num_1", Int),
        InputDefinition("num_2", Int),
    ])
    def adder(_context, num_1, num_2):
        assert called["emit_nothing"] == 3
        called["adder"] += 1
        return num_1 + num_2

    pipeline = PipelineDefinition(
        name="input_test",
        solid_defs=[emit_two, emit_nothing, adder],
        dependencies={
            NodeInvocation("emit_two", "emit_1"): {},
            NodeInvocation("emit_two", "emit_2"): {},
            NodeInvocation("emit_nothing", "_one"): {},
            NodeInvocation("emit_nothing", "_two"): {},
            NodeInvocation("emit_nothing", "_three"): {},
            "adder": {
                "ready":
                MultiDependencyDefinition([
                    DependencyDefinition("_one"),
                    DependencyDefinition("_two"),
                    DependencyDefinition("_three"),
                ]),
                "num_1":
                DependencyDefinition("emit_1"),
                "num_2":
                DependencyDefinition("emit_2"),
            },
        },
    )
    result = execute_pipeline(pipeline)
    assert result.success
    assert called["adder"] == 1
    assert called["emit_nothing"] == 3
示例#8
0
def test_hook_resource_error():
    @event_list_hook(required_resource_keys={"resource_b"})
    def a_hook(context, event_list):  # pylint: disable=unused-argument
        return HookExecutionResult(hook_name="a_hook")

    @solid
    def a_solid(_):
        pass

    with pytest.raises(
            DagsterInvalidDefinitionError,
            match="resource key 'resource_b' is required by hook 'a_hook'",
    ):
        PipelineDefinition(
            solid_defs=[a_solid],
            name="test",
            dependencies={
                NodeInvocation("a_solid",
                               "a_solid_with_hook",
                               hook_defs={a_hook}): {}
            },
            mode_defs=[
                ModeDefinition(resource_defs={"resource_a": resource_a})
            ],
        )
示例#9
0
def test_hook_with_resource():
    called = {}

    @event_list_hook(required_resource_keys={"resource_a"})
    def a_hook(context, _):
        called[context.solid.name] = True
        assert context.resources.resource_a == 1
        return HookExecutionResult(hook_name="a_hook")

    @solid
    def a_solid(_):
        pass

    a_pipeline = PipelineDefinition(
        solid_defs=[a_solid],
        name="test",
        dependencies={
            NodeInvocation("a_solid", "a_solid_with_hook", hook_defs={a_hook}):
            {}
        },
        mode_defs=[ModeDefinition(resource_defs={"resource_a": resource_a})],
    )

    result = execute_pipeline(a_pipeline)
    assert result.success
    assert called.get("a_solid_with_hook")
示例#10
0
def test_hook():
    called = {}

    @event_list_hook
    def a_hook(context, event_list):
        called[context.hook_def.name] = context.solid.name
        called["step_event_list"] = [i for i in event_list]
        return HookExecutionResult(hook_name="a_hook")

    @event_list_hook(name="a_named_hook")
    def named_hook(context, _):
        called[context.hook_def.name] = context.solid.name
        return HookExecutionResult(hook_name="a_hook")

    @solid
    def a_solid(_):
        pass

    a_pipeline = PipelineDefinition(
        solid_defs=[a_solid],
        name="test",
        dependencies={
            NodeInvocation("a_solid", "a_solid_with_hook", hook_defs={a_hook, named_hook}): {}
        },
    )

    result = execute_pipeline(a_pipeline)
    assert result.success
    assert called.get("a_hook") == "a_solid_with_hook"
    assert called.get("a_named_hook") == "a_solid_with_hook"

    assert set([event.event_type_value for event in called["step_event_list"]]) == set(
        [event.event_type_value for event in result.step_event_list]
    )
示例#11
0
def test_hook_user_error():
    @event_list_hook
    def error_hook(context, _):
        raise SomeUserException()

    @solid
    def a_solid(_):
        return 1

    a_pipeline = PipelineDefinition(
        solid_defs=[a_solid],
        name="test",
        dependencies={
            NodeInvocation("a_solid",
                           "a_solid_with_hook",
                           hook_defs={error_hook}): {}
        },
    )

    result = execute_pipeline(a_pipeline)
    assert result.success

    hook_errored_events = list(
        filter(lambda event: event.event_type == DagsterEventType.HOOK_ERRORED,
               result.event_list))
    assert len(hook_errored_events) == 1
    assert hook_errored_events[0].solid_handle.name == "a_solid_with_hook"
示例#12
0
def test_solid_instance_tags():
    called = {}

    @solid(tags={"foo": "bar", "baz": "quux"})
    def metadata_solid(context):
        assert context.solid.tags == {"foo": "oof", "baz": "quux", "bip": "bop"}
        called["yup"] = True

    pipeline = PipelineDefinition(
        name="metadata_pipeline",
        solid_defs=[metadata_solid],
        dependencies={
            NodeInvocation(
                "metadata_solid",
                alias="aliased_metadata_solid",
                tags={"foo": "oof", "bip": "bop"},
            ): {}
        },
    )

    result = execute_pipeline(
        pipeline,
    )

    assert result.success
    assert called["yup"]
示例#13
0
def test_mapper_errors():
    @lambda_solid
    def solid_a():
        return 1

    with pytest.raises(DagsterInvalidDefinitionError) as excinfo_1:
        PipelineDefinition(
            solid_defs=[solid_a],
            name="test",
            dependencies={"solid_b": {"arg_a": DependencyDefinition("solid_a")}},
        )
    assert (
        str(excinfo_1.value)
        == 'Invalid dependencies: node "solid_b" in dependency dictionary not found in node list'
    )

    with pytest.raises(DagsterInvalidDefinitionError) as excinfo_2:
        PipelineDefinition(
            solid_defs=[solid_a],
            name="test",
            dependencies={
                NodeInvocation("solid_b", alias="solid_c"): {
                    "arg_a": DependencyDefinition("solid_a")
                }
            },
        )
    assert (
        str(excinfo_2.value)
        == 'Invalid dependencies: node "solid_b" (aliased by "solid_c" in dependency dictionary) not found in node list'
    )
示例#14
0
def test_string_from_aliased_inputs():
    called = {}

    @solid(input_defs=[InputDefinition("string_input", String)])
    def str_as_input(_context, string_input):
        assert string_input == "foo"
        called["yup"] = True

    pipeline = PipelineDefinition(
        solid_defs=[str_as_input],
        name="test",
        dependencies={NodeInvocation("str_as_input", alias="aliased"): {}},
    )

    result = execute_pipeline(pipeline, {
        "solids": {
            "aliased": {
                "inputs": {
                    "string_input": {
                        "value": "foo"
                    }
                }
            }
        }
    })

    assert result.success
    assert called["yup"]
示例#15
0
def test_cycle_detect():
    @lambda_solid
    def return_one():
        return 1

    @lambda_solid
    def add(a, b):
        return a + b

    with pytest.raises(DagsterInvalidDefinitionError,
                       match="Circular dependencies exist"):
        PipelineDefinition(
            solid_defs=[return_one, add],
            name="test",
            dependencies={
                NodeInvocation("add", alias="first"): {
                    "a": DependencyDefinition("return_one"),
                    "b": DependencyDefinition("second"),
                },
                NodeInvocation("add", alias="second"): {
                    "a": DependencyDefinition("first"),
                    "b": DependencyDefinition("return_one"),
                },
            },
        )

    with pytest.raises(DagsterInvalidDefinitionError,
                       match="Circular dependencies exist"):
        CompositeSolidDefinition(
            name="circletron",
            solid_defs=[return_one, add],
            dependencies={
                NodeInvocation("add", alias="first"): {
                    "a": DependencyDefinition("return_one"),
                    "b": DependencyDefinition("second"),
                },
                NodeInvocation("add", alias="second"): {
                    "a": DependencyDefinition("first"),
                    "b": DependencyDefinition("return_one"),
                },
            },
        )
示例#16
0
def test_aliased_solids_context():
    record = defaultdict(set)

    @solid
    def log_things(context):
        solid_value = context.solid.name
        solid_def_value = context.solid_def.name
        record[solid_def_value].add(solid_value)

    pipeline = PipelineDefinition(
        solid_defs=[log_things],
        name="test",
        dependencies={
            NodeInvocation("log_things", "log_a"): {},
            NodeInvocation("log_things", "log_b"): {},
        },
    )

    result = execute_pipeline(pipeline)
    assert result.success

    assert dict(record) == {"log_things": set(["log_a", "log_b"])}
示例#17
0
def construct_graph_with_yaml(yaml_file, op_defs) -> GraphDefinition:
    yaml_data = load_yaml_from_path(yaml_file)

    deps = {}

    for op_yaml_data in yaml_data["ops"]:
        def_name = op_yaml_data["def"]
        alias = op_yaml_data.get("alias", def_name)
        op_deps_entry = {}
        for input_name, input_data in op_yaml_data.get("deps", {}).items():
            op_deps_entry[input_name] = DependencyDefinition(
                solid=input_data["op"],
                output=input_data.get("output", "result"))
        deps[NodeInvocation(name=def_name, alias=alias)] = op_deps_entry

    return GraphDefinition(
        name=yaml_data["name"],
        description=yaml_data.get("description"),
        node_defs=op_defs,
        dependencies=deps,
    )
示例#18
0
文件: __init__.py 项目: keyz/dagster
def _dep_key_of(solid):
    return NodeInvocation(solid.definition.name, solid.name)