Example #1
0
def test_nested_graph_config_mapping():
    @op(config_schema=str)
    def my_op(context):
        return context.op_config

    def _nested_config_fn(outer):
        return {"my_op": {"config": outer}}

    @graph(config=ConfigMapping(config_fn=_nested_config_fn,
                                config_schema=str))
    def my_nested_graph():
        my_op()

    def _config_fn(outer):
        return {"my_nested_graph": {"config": outer}}

    @graph(config=ConfigMapping(config_fn=_config_fn, config_schema=str))
    def my_graph():
        my_nested_graph()

    result = my_graph.to_job().execute_in_process(
        run_config={"ops": {
            "config": "foo"
        }})

    assert result.success
    assert result.output_for_node("my_nested_graph.my_op") == "foo"
Example #2
0
def test_graph_configured_error_in_fn():
    @op(config_schema=str)
    def my_op(context):
        return context.op_config

    def _config_fn(outer):
        return {"my_op": {"config": outer}}

    @graph(config=ConfigMapping(config_fn=_config_fn, config_schema=str))
    def my_graph():
        my_op()

    def _bad_config_fn(_):
        raise Exception("Uh oh")

    configured_graph = my_graph.configured(name="blah",
                                           config_or_config_fn=_bad_config_fn)

    with pytest.raises(
            DagsterConfigMappingFunctionError,
            match=
            "The config mapping function on a `configured` GraphDefinition has thrown an "
            "unexpected error during its execution.",
    ):
        configured_graph.execute_in_process()
Example #3
0
def test_op_selection_with_config_mapping():
    def my_config_fn(val):
        config_val = {"config": {"foo": val["foo"]}}
        return {
            "ops": {
                "my_op": config_val,
                "my_other_op": config_val,
            }
        }

    @op
    def my_op(context):
        return context.op_config["foo"]

    @graph
    def my_graph():
        my_op()
        my_op.alias("my_other_op")()

    my_job = my_graph.to_job(config=ConfigMapping(my_config_fn))
    result = my_job.execute_in_process(run_config={"foo": "bar"})
    assert result.success
    assert result.output_for_node("my_op") == "bar"
    assert result.output_for_node("my_other_op") == "bar"

    subset_result = my_job.execute_in_process(run_config={"foo": "bar"},
                                              op_selection=["my_other_op"])
    assert subset_result.success
    assert subset_result.output_for_node("my_other_op") == "bar"
Example #4
0
def test_graph_with_configured():
    @op(config_schema=str)
    def my_op(context):
        return context.op_config

    def _config_fn(outer):
        return {"my_op": {"config": outer}}

    @graph(config=ConfigMapping(config_fn=_config_fn, config_schema=str))
    def my_graph():
        my_op()

    result = my_graph.configured(
        name="my_graph", config_or_config_fn="foo").execute_in_process()
    assert result.success
    assert result.output_for_node("my_op") == "foo"

    def _configured_use_fn(outer):
        return outer

    result = (my_graph.configured(
        name="my_graph",
        config_or_config_fn=_configured_use_fn,
        config_schema=str).to_job().execute_in_process(
            run_config={"ops": {
                "config": "foo"
            }}))

    assert result.success
    assert result.output_for_node("my_op") == "foo"
Example #5
0
def test_config_mapping_fn():
    @resource(config_schema=str)
    def date(context) -> str:
        return context.resource_config

    @op(
        required_resource_keys={"date"},
        config_schema={"msg": str},
    )
    def do_stuff(context):
        return f"{context.op_config['msg'] } on {context.resources.date}"

    @graph
    def needs_config():
        do_stuff()

    def _mapped(val):
        return {
            "ops": {"do_stuff": {"config": {"msg": "i am here"}}},
            "resources": {"date": {"config": val["date"]}},
        }

    job = needs_config.to_job(
        resource_defs={"date": date},
        config=ConfigMapping(
            config_schema={"date": str},  # top level has to be dict
            config_fn=_mapped,
        ),
    )

    result = job.execute_in_process(run_config={"date": "6/4"})
    assert result.success
    assert result.output_for_node("do_stuff") == "i am here on 6/4"
Example #6
0
def test_top_level_config_mapping_graph():
    @op(config_schema=str)
    def my_op(context):
        return context.op_config

    def _config_fn(_):
        return {"my_op": {"config": "foo"}}

    @graph(config=ConfigMapping(config_fn=_config_fn))
    def my_graph():
        my_op()

    result = my_graph.execute_in_process()

    assert result.success
    assert result.output_for_node("my_op") == "foo"
Example #7
0
def test_top_level_graph_outer_config_failure():
    @op(config_schema=str)
    def my_op(context):
        return context.op_config

    def _config_fn(outer):
        return {"my_op": {"config": outer}}

    @graph(config=ConfigMapping(config_fn=_config_fn, config_schema=str))
    def my_graph():
        my_op()

    with pytest.raises(DagsterInvalidConfigError, match="Invalid scalar at path root:ops:config"):
        my_graph.to_job().execute_in_process(run_config={"ops": {"config": {"bad_type": "foo"}}})

    with pytest.raises(DagsterInvalidConfigError, match="Invalid scalar at path root:config"):
        my_graph.to_job(config={"ops": {"config": {"bad_type": "foo"}}})
Example #8
0
def test_top_level_graph_config_mapping_failure():
    @op(config_schema=str)
    def my_op(context):
        return context.op_config

    def _nested_config_fn(_):
        return "foo"

    @graph(config=ConfigMapping(config_fn=_nested_config_fn))
    def my_nested_graph():
        my_op()

    with pytest.raises(
        DagsterInvalidConfigError,
        match="In pipeline 'my_nested_graph', top level graph 'my_nested_graph' has a configuration error.",
    ):
        my_nested_graph.execute_in_process()
Example #9
0
def test_job_config_mapping():
    @op(config_schema=str)
    def my_op(context):
        return context.op_config

    def _config_fn(outer):
        return {"ops": {"my_op": {"config": outer["foo_schema"]}}}

    config_mapping = ConfigMapping(config_fn=_config_fn,
                                   config_schema={"foo_schema": str})

    @job(config=config_mapping)
    def my_job():
        my_op()

    result = my_job.execute_in_process(run_config={"foo_schema": "foo"})
    assert result.success
    assert result.output_for_node("my_op") == "foo"
Example #10
0
def test_graph_configured_error_in_config():
    @op(config_schema=str)
    def my_op(context):
        return context.op_config

    def _config_fn(outer):
        return {"my_op": {"config": outer}}

    @graph(config=ConfigMapping(config_fn=_config_fn, config_schema=str))
    def my_graph():
        my_op()

    def _bad_config_fn(_):
        return 2

    configured_graph = my_graph.configured(name="blah", config_or_config_fn=_bad_config_fn)

    with pytest.raises(DagsterInvalidConfigError, match="Error in config for graph blah"):
        configured_graph.execute_in_process()
Example #11
0
def test_enum_config_mapping():
    @op(
        config_schema={
            "my_enum":
            Field(Enum.from_python_enum(TestEnum),
                  is_required=False,
                  default_value="ONE")
        })
    def my_op(context):
        return context.op_config["my_enum"]

    @graph
    def my_graph():
        my_op()

    def _use_defaults_mapping(_):
        return {}

    use_defaults = my_graph.to_job(config=ConfigMapping(
        config_fn=_use_defaults_mapping))
    result = use_defaults.execute_in_process()
    assert result.success
    assert result.output_for_node("my_op") == TestEnum.ONE

    def _override_defaults_mapping(_):
        return {"ops": {"my_op": {"config": {"my_enum": "TWO"}}}}

    override_defaults = my_graph.to_job(config=ConfigMapping(
        config_fn=_override_defaults_mapping))
    result = override_defaults.execute_in_process()
    assert result.success
    assert result.output_for_node("my_op") == TestEnum.TWO

    def _ingest_config_mapping(x):
        return {"ops": {"my_op": {"config": {"my_enum": x["my_field"]}}}}

    default_config_mapping = ConfigMapping(
        config_fn=_ingest_config_mapping,
        config_schema=Shape({
            "my_field":
            Field(Enum.from_python_enum(TestEnum),
                  is_required=False,
                  default_value="TWO")
        }),
        receive_processed_config_values=False,
    )
    ingest_mapping = my_graph.to_job(config=default_config_mapping)
    result = ingest_mapping.execute_in_process()
    assert result.success
    assert result.output_for_node("my_op") == TestEnum.TWO

    no_default_config_mapping = ConfigMapping(
        config_fn=_ingest_config_mapping,
        config_schema=Shape({
            "my_field":
            Field(Enum.from_python_enum(TestEnum), is_required=True)
        }),
        receive_processed_config_values=False,
    )
    ingest_mapping_no_default = my_graph.to_job(
        config=no_default_config_mapping)
    result = ingest_mapping_no_default.execute_in_process(
        run_config={"my_field": "TWO"})
    assert result.success
    assert result.output_for_node("my_op") == TestEnum.TWO

    def _ingest_post_processed_config(x):
        assert x["my_field"] == TestEnum.TWO
        return {"ops": {"my_op": {"config": {"my_enum": "TWO"}}}}

    config_mapping_with_preprocessing = ConfigMapping(
        config_fn=_ingest_post_processed_config,
        config_schema=Shape({
            "my_field":
            Field(Enum.from_python_enum(TestEnum), is_required=True)
        }),
    )
    ingest_preprocessing = my_graph.to_job(
        config=config_mapping_with_preprocessing)
    result = ingest_preprocessing.execute_in_process(
        run_config={"my_field": "TWO"})
    assert result.success
    assert result.output_for_node("my_op") == TestEnum.TWO
Example #12
0
def test_nested_op_selection_with_config_mapping():
    @op(config_schema=str)
    def concat(context, x: str):
        return x + context.op_config

    @op(config_schema=str)
    def my_op(context):
        return context.op_config

    def _nested_config_fn(outer):
        return {"my_op": {"config": outer}, "concat": {"config": outer}}

    @graph(config=ConfigMapping(config_fn=_nested_config_fn, config_schema=str))
    def my_nested_graph():
        concat(my_op())

    def _config_fn(outer):
        return {"my_nested_graph": {"config": outer}}

    @graph(config=ConfigMapping(config_fn=_config_fn, config_schema=str))
    def my_graph():
        my_nested_graph()

    result = my_graph.to_job().execute_in_process(run_config={"ops": {"config": "foo"}})
    assert result.success
    assert result.output_for_node("my_nested_graph.concat") == "foofoo"

    result_sub_1 = my_graph.to_job().execute_in_process(
        op_selection=["my_nested_graph.my_op", "my_nested_graph.concat"],
        run_config={"ops": {"config": "hello"}},
    )
    assert result_sub_1.success
    assert result_sub_1.output_for_node("my_nested_graph.concat") == "hellohello"

    # when config mapping generates values for unselected nodes, the excess values are ignored
    result_sub_2 = my_graph.to_job().execute_in_process(
        op_selection=["my_nested_graph.my_op"],
        run_config={"ops": {"config": "hello"}},
    )
    assert result_sub_2.success
    assert result_sub_2.output_for_node("my_nested_graph.my_op") == "hello"

    # sub sub graph
    @graph
    def my_super_graph():
        my_graph()

    my_subselected_super_job = my_super_graph.to_job(
        op_selection=["my_graph.my_nested_graph.my_op"]
    )
    result_sub_3_1 = my_subselected_super_job.execute_in_process(
        run_config={"ops": {"my_graph": {"config": "hello"}}},
    )
    assert result_sub_3_1.success
    assert set(_success_step_keys(result_sub_3_1)) == {"my_graph.my_nested_graph.my_op"}
    assert result_sub_3_1.output_for_node("my_graph.my_nested_graph.my_op") == "hello"

    # execute a subselected job with op_selection
    result_sub_3_2 = my_subselected_super_job.execute_in_process(
        op_selection=["*"],
        run_config={"ops": {"my_graph": {"config": "hello"}}},
    )
    assert result_sub_3_2.success
    assert set(_success_step_keys(result_sub_3_2)) == {"my_graph.my_nested_graph.my_op"}
    assert result_sub_3_2.output_for_node("my_graph.my_nested_graph.my_op") == "hello"
Example #13
0
@op(config_schema={"param": str})
def do_something(_):
    ...


@graph
def do_it_all():
    do_something()


# start
do_it_all_job = do_it_all.to_job(config=ConfigMapping(
    config_fn=lambda conf:
    {"solids": {
        "do_something": {
            "config": {
                "param": conf["arg"]
            }
        }
    }},
    config_schema={"arg": str},
))
# end


def execute_do_it_all():
    # start_execute
    do_it_all_job.execute_in_process(run_config={"arg": "some_value"})
    # end_execute