Repository: iterative/dvc (python)

Issue:
Nested Interpolation / Expansions
It would be really nice to have the possibility to nest string interpolations / variables expansions, ex. interpolating in `dvc.yaml` a field of `params.yaml` that is itself an interpolation of another field...

For example: 

In `params.yaml`

```yaml
paths: 
  data: 
    root: path/to/data/dir
    raw: ${paths.data.root}/raw/
  scripts: 
    root: path/to/stages/dir
    load: ${paths.scripts.root}
 ```

and then `dvc.yaml`
 
```yaml
stages:
  load:
    cmd: python ${paths.scripts.load}
    outs: 
      - ${paths.raw}/filename.extension
```

This would really help in avoiding cumbersome & "error prone" hardcoding. 

Many thanks in advance 
Regards 
M

Pull request description:
hydra: resolve OmegaConf interpolations.
Closes #9196

Patch:
diff --git a/dvc/repo/experiments/utils.py b/dvc/repo/experiments/utils.py
index 8a3a17437..afd1a1a5a 100644
--- a/dvc/repo/experiments/utils.py
+++ b/dvc/repo/experiments/utils.py
@@ -286,7 +286,7 @@ def check_ref_format(scm: "Git", ref: ExpRefInfo):
         )
 
 
-def fetch_all_exps(scm: "Git", url: str, progress: Optional[Callable] = None):
+def fetch_all_exps(scm: "Git", url: str, progress: Optional[Callable] = None, **kwargs):
     refspecs = [
         f"{ref}:{ref}"
         for ref in iter_remote_refs(scm, url, base=EXPS_NAMESPACE)
@@ -296,6 +296,7 @@ def fetch_all_exps(scm: "Git", url: str, progress: Optional[Callable] = None):
         url,
         refspecs,
         progress=progress,
+        **kwargs,
     )
 
 
diff --git a/dvc/utils/hydra.py b/dvc/utils/hydra.py
index c83be6f2f..6e12cabdc 100644
--- a/dvc/utils/hydra.py
+++ b/dvc/utils/hydra.py
@@ -36,6 +36,8 @@ def compose_and_dump(
     with initialize_config_dir(config_dir, version_base=None):
         cfg = compose(config_name=config_name, overrides=overrides)
 
+    OmegaConf.resolve(cfg)
+
     suffix = Path(output_file).suffix.lower()
     if suffix not in [".yml", ".yaml"]:
         dumper = DUMPERS[suffix]


Test patch:
diff --git a/tests/func/utils/test_hydra.py b/tests/func/utils/test_hydra.py
index d2f7679c4..cc677a1ac 100644
--- a/tests/func/utils/test_hydra.py
+++ b/tests/func/utils/test_hydra.py
@@ -178,7 +178,7 @@ def test_compose_and_dump(tmp_dir, suffix, overrides, expected):
 
 
 def test_compose_and_dump_yaml_handles_string(tmp_dir):
-    """Regression test for 8583"""
+    """Regression test for https://github.com/iterative/dvc/issues/8583"""
     from dvc.utils.hydra import compose_and_dump
 
     config = tmp_dir / "conf" / "config.yaml"
@@ -189,6 +189,20 @@ def test_compose_and_dump_yaml_handles_string(tmp_dir):
     assert output_file.read_text() == "foo: 'no'\n"
 
 
+def test_compose_and_dump_resolves_interpolation(tmp_dir):
+    """Regression test for https://github.com/iterative/dvc/issues/9196"""
+    from dvc.utils.hydra import compose_and_dump
+
+    config = tmp_dir / "conf" / "config.yaml"
+    config.parent.mkdir()
+    config.dump({"data": {"root": "path/to/root", "raw": "${.root}/raw"}})
+    output_file = tmp_dir / "params.yaml"
+    compose_and_dump(output_file, str(config.parent), "config", [])
+    assert output_file.parse() == {
+        "data": {"root": "path/to/root", "raw": "path/to/root/raw"}
+    }
+
+
 @pytest.mark.parametrize(
     "overrides, expected",
     [