mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-09 23:10:24 +01:00
We wrap every data to one of the `Node` object. But, since we were passing `self.data` instead of `self`, it was skipping the conversion and instead was just trying to set data as-is, which would have make our latter assumptions incorrect, as other codebases assume it to be a `Node`. I have added asserts in a few places. Also, I noticed that, on a few test assumptions, when `resolving`, we were not converting values back to it's original form (`CtxDict` -> `dict`, `CtxList` -> `list` and `Value` -> _). So, I have added `node.value` property, as it is a complement of the above fix. This caused a ripple effect for the changes in the API as `foreach` now resolved and changed the data to the original form, which prevents us from tracking the data later in the "field". So, `resolve`/`select` got a real `unwrap` option that should reliably work for all kinds of `Node` objects.
104 lines
2.9 KiB
Python
104 lines
2.9 KiB
Python
from math import inf, pi
|
|
|
|
import pytest
|
|
|
|
from dvc.parsing import Context
|
|
from tests.func.test_stage_resolver import recurse_not_a_node
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"template, var",
|
|
[
|
|
("${value}", "value"),
|
|
("${{item}}", "item"),
|
|
("${ item }", "item"),
|
|
("${{ value }}", "value"),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"data", [True, 12, pi, None, False, 0, "0", "123", "Foobar", "", inf, 3e4]
|
|
)
|
|
def test_resolve_primitive_values(data, template, var):
|
|
context = Context({var: data})
|
|
assert context.resolve(template) == data
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"template, expected",
|
|
[
|
|
(r"\${value}", "${value}"),
|
|
(r"\${{value}}", "${{value}}"),
|
|
(r"\${ value }", "${ value }"),
|
|
(r"\${{ value }}", "${{ value }}"),
|
|
(r"\${{ value }} days", "${{ value }} days"),
|
|
(r"\${ value } days", "${ value } days"),
|
|
(r"Month of \${value}", "Month of ${value}"),
|
|
(r"May the \${value} be with you", "May the ${value} be with you"),
|
|
(
|
|
r"Great shot kid, that was \${value} in a ${value}",
|
|
"Great shot kid, that was ${value} in a value",
|
|
),
|
|
],
|
|
)
|
|
def test_escape(template, expected, mocker):
|
|
context = Context({"value": "value"})
|
|
assert context.resolve(template) == expected
|
|
|
|
|
|
def test_resolve_str():
|
|
template = "My name is ${last}, ${first} ${last}"
|
|
expected = "My name is Bond, James Bond"
|
|
context = Context({"first": "James", "last": "Bond"})
|
|
assert context.resolve(template) == expected
|
|
|
|
|
|
def test_resolve_primitives_dict_access():
|
|
data = {
|
|
"dict": {
|
|
"num": 5,
|
|
"string": "foo",
|
|
"nested": {"float": pi, "string": "bar"},
|
|
}
|
|
}
|
|
context = Context(data)
|
|
|
|
assert context.resolve("${dict.num}") == 5
|
|
assert context.resolve("${dict.string}") == "foo"
|
|
assert context.resolve("${dict.nested.float}") == pi
|
|
assert context.resolve("${dict.nested.string}") == "bar"
|
|
|
|
assert context.resolve("Number ${dict.num}") == "Number 5"
|
|
|
|
|
|
def test_resolve_primitives_list_access():
|
|
context = Context(
|
|
{
|
|
"dict": [
|
|
{"f": "f"},
|
|
{"fo": "fo"},
|
|
{"foo": "foo"},
|
|
{"foo": ["f", "o", "o"]},
|
|
]
|
|
}
|
|
)
|
|
|
|
assert context.resolve("${dict.0.f}") == "f"
|
|
assert context.resolve("${dict.1.fo}") == "fo"
|
|
assert context.resolve("${dict.2.foo}") == "foo"
|
|
assert context.resolve("${dict.3.foo.0}") == "f"
|
|
|
|
assert context.resolve("${ dict.1.fo}${dict.3.foo.1}bar") == "foobar"
|
|
|
|
|
|
def test_resolve_collection():
|
|
from .test_stage_resolver 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)
|