Esempio n. 1
0
def test_resolve_resolves_dict_keys():
    d = {"dct": {"foo": "foobar", "persist": True}}

    context = Context(d)
    assert context.resolve({"${dct.foo}": {"persist": "${dct.persist}"}}) == {
        "foobar": {"persist": True}
    }
Esempio n. 2
0
def test_load_from_raises_if_file_is_directory(tmp_dir, dvc):
    (tmp_dir / "data").mkdir()

    with pytest.raises(ParamsLoadError) as exc_info:
        Context.load_from(dvc.fs, "data")

    assert str(exc_info.value) == "'data' is a directory"
Esempio n. 3
0
def test_track_from_multiple_files(tmp_dir):
    d1 = {"Train": {"us": {"lr": 10}}}
    d2 = {"Train": {"us": {"layers": 100}}}

    fs = LocalFileSystem()
    path1 = tmp_dir / "params.yaml"
    path2 = tmp_dir / "params2.yaml"
    path1.dump(d1, fs=fs)
    path2.dump(d2, fs=fs)

    context = Context.load_from(fs, path1)
    c = Context.load_from(fs, path2)
    context.merge_update(c)

    def key_tracked(d, path, key):
        return key in d[relpath(path)]

    with context.track() as tracked:
        context.select("Train")
        assert not (
            key_tracked(tracked, path1, "Train")
            or key_tracked(tracked, path2, "Train")
        )

        context.select("Train.us")
        assert not (
            key_tracked(tracked, path1, "Train.us")
            or key_tracked(tracked, path2, "Train.us")
        )

        context.select("Train.us.lr")
        assert key_tracked(tracked, path1, "Train.us.lr") and not key_tracked(
            tracked, path2, "Train.us.lr"
        )
        context.select("Train.us.layers")
        assert not key_tracked(
            tracked, path1, "Train.us.layers"
        ) and key_tracked(tracked, path2, "Train.us.layers")

    context = Context.clone(context)
    assert not context._tracked_data

    # let's see with an alias
    context["us"] = context["Train"]["us"]
    with context.track() as tracked:
        context.select("us")
        assert not (
            key_tracked(tracked, path1, "Train.us")
            or key_tracked(tracked, path2, "Train.us")
        )

        context.select("us.lr")
        assert key_tracked(tracked, path1, "Train.us.lr") and not key_tracked(
            tracked, path2, "Train.us.lr"
        )
        context.select("Train.us.layers")
        assert not key_tracked(
            tracked, path1, "Train.us.layers"
        ) and key_tracked(tracked, path2, "Train.us.layers")
Esempio n. 4
0
def test_track_from_multiple_files(tmp_dir):
    d1 = {"Train": {"us": {"lr": 10}}}
    d2 = {"Train": {"us": {"layers": 100}}}

    tree = LocalTree(None, config={})
    path1 = tmp_dir / "params.yaml"
    path2 = tmp_dir / "params2.yaml"
    dump_yaml(path1, d1, tree)
    dump_yaml(path2, d2, tree)

    context = Context.load_from(tree, path1)
    c = Context.load_from(tree, path2)
    context.merge_update(c)

    def key_tracked(d, path, key):
        return key in d[relpath(path)]

    with context.track() as tracked:
        context.select("Train")
        assert not (
            key_tracked(tracked, path1, "Train")
            or key_tracked(tracked, path2, "Train")
        )

        context.select("Train.us")
        assert not (
            key_tracked(tracked, path1, "Train.us")
            or key_tracked(tracked, path2, "Train.us")
        )

        context.select("Train.us.lr")
        assert key_tracked(tracked, path1, "Train.us.lr") and not key_tracked(
            tracked, path2, "Train.us.lr"
        )
        context.select("Train.us.layers")
        assert not key_tracked(
            tracked, path1, "Train.us.layers"
        ) and key_tracked(tracked, path2, "Train.us.layers")

    context = Context.clone(context)
    assert not context._tracked_data

    # let's see with an alias
    context["us"] = context["Train"]["us"]
    with context.track() as tracked:
        context.select("us")
        assert not (
            key_tracked(tracked, path1, "Train.us")
            or key_tracked(tracked, path2, "Train.us")
        )

        context.select("us.lr")
        assert key_tracked(tracked, path1, "Train.us.lr") and not key_tracked(
            tracked, path2, "Train.us.lr"
        )
        context.select("Train.us.layers")
        assert not key_tracked(
            tracked, path1, "Train.us.layers"
        ) and key_tracked(tracked, path2, "Train.us.layers")
Esempio n. 5
0
def test_resolve_collection():
    from tests.func.parsing import (
        CONTEXT_DATA,
        RESOLVED_DVC_YAML_DATA,
        TEMPLATED_DVC_YAML_DATA,
    )

    context = Context(CONTEXT_DATA)
    resolved = context.resolve(TEMPLATED_DVC_YAML_DATA)
    assert resolved == RESOLVED_DVC_YAML_DATA
    assert recurse_not_a_node(resolved)
Esempio n. 6
0
def test_loop_context():
    context = Context({"foo": "foo", "bar": "bar", "lst": [1, 2, 3]})

    assert list(context) == ["foo", "bar", "lst"]
    assert len(context) == 3

    assert list(context["lst"]) == [Value(i) for i in [1, 2, 3]]
    assert len(context["lst"]) == 3

    assert list(context.items()) == [
        ("foo", Value("foo")),
        ("bar", Value("bar")),
        ("lst", CtxList([1, 2, 3])),
    ]
Esempio n. 7
0
def test_set_multiple_interpolations(value):
    context = Context(CONTEXT_DATA)
    with pytest.raises(
            ValueError,
            match=r"Cannot set 'item', joining string with interpolated string",
    ):
        DataResolver.set_context_from(context, {"thresh": 10, "item": value})
Esempio n. 8
0
def test_context():
    context = Context({"foo": "bar"})
    assert context["foo"] == Value("bar")

    context = Context(foo="bar")
    assert context["foo"] == Value("bar")

    context["foobar"] = "foobar"
    assert context["foobar"] == Value("foobar")

    del context["foobar"]
    assert "foobar" not in context
    assert "foo" in context

    with pytest.raises(KeyError):
        _ = context["foobar"]
Esempio n. 9
0
def test_item_key_in_generated_stage_vars(tmp_dir, dvc, redefine, from_file):
    context = Context(foo="bar")
    vars_ = [redefine]
    if from_file:
        (tmp_dir / "test_params.yaml").dump(redefine)
        vars_ = ["test_params.yaml"]

    definition = make_foreach_def(
        tmp_dir,
        "build",
        {"model1": {"thresh": "10"}, "model2": {"thresh": 5}},
        {"vars": vars_, "cmd": "${item}"},
        context,
    )

    with pytest.raises(ResolveError) as exc_info:
        definition.resolve_all()

    message = str(exc_info.value)
    assert (
        "failed to parse stage 'build@model1' in 'dvc.yaml': "
        "attempted to modify reserved"
    ) in message

    key_or_keys = "keys" if len(redefine) > 1 else "key"
    assert f"{key_or_keys} {join(redefine)}" in message
    if from_file:
        assert "in 'test_params.yaml'" in message
    assert context == {"foo": "bar"}
Esempio n. 10
0
def test_set_already_exists():
    context = Context({"item": "foo"})
    with pytest.raises(ValueError,
                       match="Cannot set 'item', key already exists"):
        DataResolver.set_context_from(context, {"item": "bar"})

    assert context["item"] == Value("foo")
Esempio n. 11
0
def test_node_value():
    d = {"dct": {"foo": "bar"}, "lst": [1, 2, 3], "foo": "foo"}
    context = Context(d)
    assert isinstance(context, (Context, CtxDict))
    assert isinstance(context["dct"], CtxDict)
    assert isinstance(context["lst"], CtxList)
    assert isinstance(context["foo"], Value)
    assert isinstance(context["dct"]["foo"], Value)
    assert isinstance(context["lst"][0], Value)

    assert context.value == d
    assert recurse_not_a_node(context.value)
    assert isinstance(context.value["dct"], dict)
    assert isinstance(context.value["lst"], list)
    assert isinstance(context.value["foo"], str)
    assert isinstance(context.value["dct"]["foo"], str)
    assert isinstance(context.value["lst"][0], int)

    assert isinstance(context["dct"].value, dict)
    assert context["dct"]["foo"].value == "bar"

    assert isinstance(context["lst"].value, list)
    assert context["lst"][1].value == 2

    assert context["foo"].value == "foo"
Esempio n. 12
0
def make_entry_definition(wdir, name, data, context=None) -> EntryDefinition:
    return EntryDefinition(
        DataResolver(wdir.dvc, wdir.fs_path, {}),
        context or Context(),
        name,
        data,
    )
Esempio n. 13
0
def test_context_dict_ignores_keys_except_str():
    c = Context({"one": 1, 3: 3})
    assert "one" in c
    assert 3 not in c

    c[3] = 3
    assert 3 not in c
Esempio n. 14
0
def make_foreach_def(
    wdir, name, foreach_data, do_data=None, context=None
) -> ForeachDefinition:
    return ForeachDefinition(
        DataResolver(wdir.dvc, wdir, {}),
        context or Context(),
        name,
        {"foreach": foreach_data, "do": do_data or {}},
    )
Esempio n. 15
0
def test_set_multiple_interpolations(value):
    context = Context(CONTEXT_DATA)
    with pytest.raises(ResolveError,) as exc_info:
        DataResolver.set_context_from(context, {"thresh": 10, "item": value})

    assert str(exc_info.value) == (
        "Failed to set 'item': Cannot set 'item', "
        "joining string with interpolated string is not supported"
    )
Esempio n. 16
0
def test_set():
    context = Context(CONTEXT_DATA)
    to_set = {
        "foo": "foo",
        "bar": "bar",
        "pi": pi,
        "true": True,
        "false": False,
        "none": "None",
        "int": 1,
        "lst2": [1, 2, 3],
        "dct2": {"foo": "bar", "foobar": "foobar"},
    }
    DataResolver.set_context_from(context, to_set)

    for key, value in to_set.items():
        # FIXME: using for convenience, figure out better way to do it
        assert context[key] == context._convert(key, value)
Esempio n. 17
0
def test_set_nested_coll(coll):
    context = Context(CONTEXT_DATA)
    with pytest.raises(ResolveError) as exc_info:
        DataResolver.set_context_from(context, {"thresh": 10, "item": coll})

    assert (
        str(exc_info.value) == "Failed to set 'item': Cannot set 'item', "
        "has nested dict/list"
    )
Esempio n. 18
0
def test_foreach_do_syntax_is_checked_once(tmp_dir, dvc, mocker):
    do_def = {"cmd": "python script.py --epochs ${item}"}
    data = {"foreach": [0, 1, 2, 3, 4], "do": do_def}
    definition = ForeachDefinition(DataResolver(dvc, tmp_dir.fs_path, {}),
                                   Context(), "build", data)
    mock = mocker.patch("dvc.parsing.check_syntax_errors", return_value=True)
    definition.resolve_all()

    mock.assert_called_once_with(do_def, "build", "dvc.yaml")
Esempio n. 19
0
def test_set_collection_interpolation(coll):
    context = Context(CONTEXT_DATA)
    with pytest.raises(ResolveError) as exc_info:
        DataResolver.set_context_from(context, {"thresh": 10, "item": coll})

    assert (
        str(exc_info.value) == "Failed to set 'item': Cannot set 'item', "
        f"having interpolation inside '{type(coll).__name__}' "
        "is not supported."
    )
Esempio n. 20
0
def test_foreach_data_is_only_resolved_once(tmp_dir, dvc, mocker):
    context = Context(models=["foo", "bar", "baz"])
    data = {"foreach": "${models}", "do": {}}
    definition = ForeachDefinition(DataResolver(dvc, tmp_dir.fs_path, {}),
                                   context, "build", data)
    mock = mocker.spy(definition, "_resolve_foreach_data")

    definition.resolve_all()

    mock.assert_called_once_with()
Esempio n. 21
0
def test_set_already_exists():
    context = Context({"item": "foo"})
    with pytest.raises(ResolveError) as exc_info:
        DataResolver.set_context_from(context, {"item": "bar"})

    assert (
        str(exc_info.value) == "Failed to set 'item': Cannot set 'item', "
        "key already exists"
    )
    assert context["item"] == Value("foo")
Esempio n. 22
0
def test_merge_list():
    c1 = Context(lst=[1, 2, 3])
    with pytest.raises(ValueError):
        # cannot overwrite by default
        c1.merge_update({"lst": [10, 11, 12]})

    # lists are never merged
    c1.merge_update({"lst": [10, 11, 12]}, overwrite=True)
    assert c1.select("lst") == [10, 11, 12]
Esempio n. 23
0
def test_foreach_data_expects_list_or_dict(tmp_dir, dvc, foreach_data):
    context = Context(
        {"foo": "bar", "dct": {"model1": "a-out"}, "lst": ["foo", "bar"]}
    )
    definition = make_foreach_def(tmp_dir, "build", foreach_data, {}, context)
    with pytest.raises(ResolveError) as exc_info:
        definition.resolve_all()
    assert str(exc_info.value) == (
        "failed to resolve 'stages.build.foreach' in 'dvc.yaml': "
        "expected list/dictionary, got str"
    )
Esempio n. 24
0
def test_interpolate_non_string(tmp_dir, dvc):
    definition = make_entry_definition(tmp_dir, "build",
                                       {"cmd": "echo ${models}"},
                                       Context(models={}))
    with pytest.raises(ResolveError) as exc_info:
        definition.resolve()

    assert str(exc_info.value) == (
        "failed to parse 'stages.build.cmd' in 'dvc.yaml':\n"
        "Cannot interpolate data of type 'dict'")
    assert definition.context == {"models": {}}
Esempio n. 25
0
def test_clone():
    d = {
        "dct": {
            "foo0": "foo0",
            "bar0": "bar0",
            "foo1": "foo1",
            "bar1": "bar1",
        },
        "lst": [1, 2, 3],
    }
    c1 = Context(d)
    c2 = Context.clone(c1)

    c2["dct"]["foo0"] = "foo"
    del c2["dct"]["foo1"]

    assert c1 != c2
    assert c1 == Context(d)
    assert c2.select("lst.0") == Value(1)
    with pytest.raises(KeyNotInContext):
        c2.select("lst.1.not_existing_key")
Esempio n. 26
0
def test_merge_list():
    c1 = Context(lst=[1, 2, 3])
    with pytest.raises(MergeError):
        # cannot overwrite by default
        c1.merge_update({"lst": [10, 11, 12]})

    # lists are never merged
    c1.merge_update({"lst": [10, 11, 12]}, overwrite=True)
    node = c1.select("lst")
    assert node == [10, 11, 12]
    assert isinstance(node, CtxList)
    assert node[0] == Value(10)
Esempio n. 27
0
def test_foreach_overwriting_item_in_list(
    tmp_dir, dvc, caplog, global_data, where
):
    context = Context(global_data)
    definition = make_foreach_def(
        tmp_dir, "build", {"model1": 10, "model2": 5}, {}, context
    )
    with caplog.at_level(logging.WARNING, logger="dvc.parsing"):
        definition.resolve_all()

    assert caplog.messages == [
        f"{where} already specified, "
        "will be overwritten for stages generated from 'build'"
    ]
Esempio n. 28
0
def test_with_simple_list_data(tmp_dir, dvc):
    """Testing a simple non-nested list as a foreach data"""
    resolver = DataResolver(dvc, tmp_dir.fs_path, {})

    context = Context()
    data = {"foreach": ["foo", "bar", "baz"], "do": {"cmd": "echo ${item}"}}
    definition = ForeachDefinition(resolver, context, "build", data)

    assert definition.resolve_one("foo") == {"build@foo": {"cmd": "echo foo"}}
    assert definition.resolve_one("bar") == {"build@bar": {"cmd": "echo bar"}}
    # check that `foreach` item-key replacement didnot leave any leftovers.
    assert not context
    assert not resolver.tracked_vars["build@foo"]
    assert not resolver.tracked_vars["build@bar"]
Esempio n. 29
0
def test_wdir_failed_to_interpolate(tmp_dir, dvc, wdir, expected_msg):
    definition = make_entry_definition(
        tmp_dir,
        "build",
        {"wdir": wdir, "cmd": "echo ${models.bar}"},
        Context(models={"bar": "bar"}),
    )
    with pytest.raises(ResolveError) as exc_info:
        definition.resolve()

    assert escape_ansi(str(exc_info.value)) == (
        "failed to parse 'stages.build.wdir' in 'dvc.yaml':" + expected_msg
    )
    assert definition.context == {"models": {"bar": "bar"}}
Esempio n. 30
0
def test_specified_key_does_not_exist(tmp_dir, dvc):
    definition = make_entry_definition(
        tmp_dir,
        "build",
        {"cmd": "echo ${models.foobar}"},
        Context(models={"foo": "foo"}),
    )
    with pytest.raises(ResolveError) as exc_info:
        definition.resolve()

    assert str(exc_info.value) == (
        "failed to parse 'stages.build.cmd' in 'dvc.yaml': "
        "Could not find 'models.foobar'")
    assert definition.context == {"models": {"foo": "foo"}}