Repository: facebookresearch/hydra

Issue:
Option to access hydra configs from interpolation
The hydra config node is removed from the tree before the program stats, which makes it impossible to rely on it at runtime.
The reason it's removed is that otherwise the user config would be very large even for a simple program.
That config however is still available at runtime through the HydraConfig singleston.

The idea here is to simply register a resolver function by the name of hydra, which would provide access to hydra config.

User usage would look like:
```yaml
gpu_id: ${hydra:job.num}
```

This can be useful for accessing everything inside the hydra config, including parameters only available at runtime.

In addition, provide an option to call to_absolute_dir from interpolations.


Discussion:

Patch:
diff --git a/hydra/core/hydra_config.py b/hydra/core/hydra_config.py
--- a/hydra/core/hydra_config.py
+++ b/hydra/core/hydra_config.py
@@ -15,7 +15,7 @@ def set_config(self, cfg: DictConfig) -> None:
         assert cfg is not None
         OmegaConf.set_readonly(cfg.hydra, True)
         assert OmegaConf.get_type(cfg, "hydra") == HydraConf
-        self.cfg = cfg  # type: ignore
+        self.cfg = OmegaConf.masked_copy(cfg, "hydra")  # type: ignore
 
     @staticmethod
     def get() -> HydraConf:
diff --git a/hydra/core/utils.py b/hydra/core/utils.py
--- a/hydra/core/utils.py
+++ b/hydra/core/utils.py
@@ -10,7 +10,7 @@
 from os.path import basename, dirname, splitext
 from pathlib import Path
 from time import localtime, strftime
-from typing import Any, Dict, Optional, Sequence, Tuple, Union
+from typing import Any, Dict, Optional, Sequence, Tuple, Union, cast
 
 from omegaconf import DictConfig, OmegaConf, open_dict
 
@@ -126,13 +126,18 @@ def get_valid_filename(s: str) -> str:
 
 
 def setup_globals() -> None:
-    try:
-        OmegaConf.register_resolver(
-            "now", lambda pattern: strftime(pattern, localtime())
-        )
-    except AssertionError:
-        # calling it again in no_workers mode will throw. safe to ignore.
-        pass
+    def register(name: str, f: Any) -> None:
+        try:
+            OmegaConf.register_resolver(name, f)
+        except AssertionError:
+            # calling it again in no_workers mode will throw. safe to ignore.
+            pass
+
+    register("now", lambda pattern: strftime(pattern, localtime()))
+    register(
+        "hydra",
+        lambda path: OmegaConf.select(cast(DictConfig, HydraConfig.get()), path),
+    )
 
 
 @dataclass


Test patch:
diff --git a/hydra/test_utils/configs/accessing_hydra_config.yaml b/hydra/test_utils/configs/accessing_hydra_config.yaml
new file mode 100644
--- /dev/null
+++ b/hydra/test_utils/configs/accessing_hydra_config.yaml
@@ -0,0 +1,3 @@
+cwd: ${hydra:runtime.cwd}
+job_name: ${hydra:job.name}
+config_name: ${hydra:job.config_name}
\ No newline at end of file
diff --git a/tests/test_core_utils.py b/tests/test_core_utils.py
new file mode 100644
--- /dev/null
+++ b/tests/test_core_utils.py
@@ -0,0 +1,25 @@
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
+from typing import Any
+
+from omegaconf import open_dict
+
+from hydra._internal.config_loader_impl import ConfigLoaderImpl
+from hydra._internal.utils import create_config_search_path
+from hydra.core import utils
+from hydra.core.hydra_config import HydraConfig
+
+
+def test_foo(restore_singletons: Any) -> Any:
+    utils.setup_globals()
+
+    config_loader = ConfigLoaderImpl(
+        config_search_path=create_config_search_path("pkg://hydra.test_utils.configs")
+    )
+    cfg = config_loader.load_configuration(
+        config_name="accessing_hydra_config", overrides=[]
+    )
+    HydraConfig.instance().set_config(cfg)
+    with open_dict(cfg):
+        del cfg["hydra"]
+    assert cfg.job_name == "UNKNOWN_NAME"
+    assert cfg.config_name == "accessing_hydra_config"