mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-02 07:18:25 +01:00
The code are wrapped due to us using line-length=79 before, but now some of the code can easily fit in 88 chars. The formatter did not change this automatically when we changed line-length, because of magic trailing commas that gets added when they turn into multiple lines. Black/ruff wrapping them in parens and splitting them into multiple lines was making it difficult to read.
186 lines
5.9 KiB
Python
186 lines
5.9 KiB
Python
from copy import deepcopy
|
|
|
|
import pytest
|
|
|
|
from dvc.parsing import DEFAULT_PARAMS_FILE, DataResolver, ResolveError
|
|
from dvc.parsing.context import Context
|
|
from dvc.utils.serialize import dumps_yaml
|
|
|
|
from . import CONTEXT_DATA, RESOLVED_DVC_YAML_DATA, TEMPLATED_DVC_YAML_DATA
|
|
|
|
DATA = {"models": {"bar": "bar", "foo": "foo"}}
|
|
|
|
|
|
def test_resolver(tmp_dir, dvc):
|
|
resolver = DataResolver(dvc, tmp_dir.fs_path, TEMPLATED_DVC_YAML_DATA)
|
|
resolver.context.merge_update(Context(CONTEXT_DATA))
|
|
assert resolver.resolve() == RESOLVED_DVC_YAML_DATA
|
|
|
|
|
|
def test_default_params_file_not_exist(tmp_dir, dvc):
|
|
d = {"vars": [DATA["models"]]}
|
|
resolver = DataResolver(dvc, tmp_dir.fs_path, d)
|
|
assert resolver.context == d["vars"][0]
|
|
|
|
|
|
def test_no_params_yaml_and_vars(tmp_dir, dvc):
|
|
resolver = DataResolver(dvc, tmp_dir.fs_path, {})
|
|
assert not resolver.context
|
|
|
|
|
|
def test_local_vars(tmp_dir, dvc):
|
|
resolver = DataResolver(
|
|
dvc, tmp_dir.fs_path, {"vars": [{"foo": "bar", "bar": "foo"}]}
|
|
)
|
|
assert resolver.context == {"foo": "bar", "bar": "foo"}
|
|
|
|
|
|
@pytest.mark.parametrize("vars_", ["${file}_params.yaml", {"foo": "${foo}"}])
|
|
def test_vars_interpolation_errors(tmp_dir, dvc, vars_):
|
|
with pytest.raises(ResolveError) as exc_info:
|
|
DataResolver(dvc, tmp_dir.fs_path, {"vars": [vars_, {"bar": "foo"}]})
|
|
assert (
|
|
str(exc_info.value)
|
|
== "failed to parse 'vars' in 'dvc.yaml': interpolating is not allowed"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("vars_", [{}, {"vars": []}, {"vars": [DEFAULT_PARAMS_FILE]}])
|
|
def test_default_params_file(tmp_dir, dvc, vars_):
|
|
(tmp_dir / DEFAULT_PARAMS_FILE).dump(DATA)
|
|
resolver = DataResolver(dvc, tmp_dir.fs_path, vars_)
|
|
assert resolver.context == DATA
|
|
|
|
|
|
def test_load_vars_from_file(tmp_dir, dvc):
|
|
(tmp_dir / DEFAULT_PARAMS_FILE).dump(DATA)
|
|
|
|
datasets = {"datasets": ["foo", "bar"]}
|
|
(tmp_dir / "params.json").dump(datasets)
|
|
d = {"vars": [DEFAULT_PARAMS_FILE, "params.json"]}
|
|
resolver = DataResolver(dvc, tmp_dir.fs_path, d)
|
|
|
|
expected = deepcopy(DATA)
|
|
expected.update(datasets)
|
|
assert resolver.context == expected
|
|
|
|
|
|
def test_load_vars_with_relpath(tmp_dir, scm, dvc):
|
|
tmp_dir.scm_gen(DEFAULT_PARAMS_FILE, dumps_yaml(DATA), commit="add params")
|
|
|
|
revisions = ["HEAD", "workspace"]
|
|
for rev in dvc.brancher(revs=["HEAD"]):
|
|
assert rev == revisions.pop()
|
|
d = {"vars": [f"../{DEFAULT_PARAMS_FILE}"]}
|
|
resolver = DataResolver(dvc, "subdir", d)
|
|
assert resolver.context == deepcopy(DATA)
|
|
|
|
|
|
def test_partial_vars_doesnot_exist(tmp_dir, dvc):
|
|
(tmp_dir / "test_params.yaml").dump({"sub1": "sub1"})
|
|
|
|
with pytest.raises(ResolveError) as exc_info:
|
|
DataResolver(dvc, tmp_dir.fs_path, {"vars": ["test_params.yaml:sub2"]})
|
|
|
|
assert (
|
|
str(exc_info.value) == "failed to parse 'vars' in 'dvc.yaml': "
|
|
"could not find 'sub2' in 'test_params.yaml'"
|
|
)
|
|
|
|
|
|
def test_global_overwrite_error_on_imports(tmp_dir, dvc):
|
|
(tmp_dir / DEFAULT_PARAMS_FILE).dump(DATA)
|
|
(tmp_dir / "params.json").dump(DATA)
|
|
|
|
d = {"vars": [DEFAULT_PARAMS_FILE, "params.json"]}
|
|
with pytest.raises(ResolveError) as exc_info:
|
|
DataResolver(dvc, tmp_dir.fs_path, d)
|
|
|
|
assert (
|
|
str(exc_info.value) == "failed to parse 'vars' in 'dvc.yaml':\n"
|
|
"cannot redefine 'models.bar' from 'params.json' "
|
|
"as it already exists in 'params.yaml'"
|
|
)
|
|
|
|
|
|
def test_global_overwrite_vars(tmp_dir, dvc):
|
|
(tmp_dir / DEFAULT_PARAMS_FILE).dump(DATA)
|
|
d = {"vars": [DATA]}
|
|
|
|
with pytest.raises(ResolveError) as exc_info:
|
|
DataResolver(dvc, tmp_dir.fs_path, d)
|
|
|
|
assert (
|
|
str(exc_info.value) == "failed to parse 'vars' in 'dvc.yaml':\n"
|
|
"cannot redefine 'models.bar' from 'vars[0]' "
|
|
"as it already exists in 'params.yaml'"
|
|
)
|
|
|
|
|
|
def test_local_declared_vars_overwrite(tmp_dir, dvc):
|
|
(tmp_dir / DEFAULT_PARAMS_FILE).dump(DATA)
|
|
|
|
d = {"vars": [DATA["models"], DATA["models"]]}
|
|
with pytest.raises(ResolveError) as exc_info:
|
|
DataResolver(dvc, tmp_dir.fs_path, d)
|
|
|
|
assert (
|
|
str(exc_info.value) == "failed to parse 'vars' in 'dvc.yaml':\n"
|
|
"cannot redefine 'bar' from 'vars[1]' "
|
|
"as it already exists in 'vars[0]'"
|
|
)
|
|
|
|
|
|
def test_specified_params_file_not_exist(tmp_dir, dvc):
|
|
d = {"vars": ["not_existing_params.yaml"]}
|
|
with pytest.raises(ResolveError) as exc_info:
|
|
DataResolver(dvc, tmp_dir.fs_path, d)
|
|
|
|
assert (
|
|
str(exc_info.value) == "failed to parse 'vars' in 'dvc.yaml': "
|
|
"'not_existing_params.yaml' does not exist"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("local", [True, False])
|
|
@pytest.mark.parametrize(
|
|
"vars_",
|
|
[
|
|
["test_params.yaml", "test_params.yaml:sub1"],
|
|
["test_params.yaml:sub1", "test_params.yaml"],
|
|
["test_params.yaml:sub1", "test_params.yaml:sub1,sub2"],
|
|
],
|
|
)
|
|
def test_vars_already_loaded_message(tmp_dir, dvc, local, vars_):
|
|
d = {"stages": {"build": {"cmd": "echo ${sub1} ${sub2}"}}}
|
|
(tmp_dir / "test_params.yaml").dump({"sub1": "sub1", "sub2": "sub2"})
|
|
if not local:
|
|
d["vars"] = vars_
|
|
else:
|
|
d["stages"]["build"]["vars"] = vars_
|
|
|
|
with pytest.raises(ResolveError) as exc_info: # noqa: PT012
|
|
resolver = DataResolver(dvc, tmp_dir.fs_path, d)
|
|
resolver.resolve()
|
|
assert "partially" in str(exc_info.value)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"vars_, loc", [(DATA, "build.vars[0]"), ("params.json", "params.json")]
|
|
)
|
|
def test_local_overwrite_error(tmp_dir, dvc, vars_, loc):
|
|
(tmp_dir / DEFAULT_PARAMS_FILE).dump(DATA)
|
|
(tmp_dir / "params.json").dump(DATA)
|
|
|
|
d = {"stages": {"build": {"cmd": "echo ${models.foo}", "vars": [vars_]}}}
|
|
|
|
resolver = DataResolver(dvc, tmp_dir.fs_path, d)
|
|
with pytest.raises(ResolveError) as exc_info:
|
|
resolver.resolve()
|
|
|
|
assert (
|
|
str(exc_info.value) == "failed to parse stage 'build' in 'dvc.yaml':\n"
|
|
f"cannot redefine 'models.bar' from '{loc}' "
|
|
"as it already exists in 'params.yaml'"
|
|
)
|