Repository: facebookresearch/hydra

Issue:
[Ax-Plugin] Switch back to the usage of "." in place of "_"

> > I abandoned the idea of compact keys in OmegaConf. This is a good chance to switch back to the more intuitive usage of dot and not _ to separate the path element in keys:
> > ```yaml
> >       params:
> >         banana.x:
> >           type: range
> >           bounds: [-5, 5]
> > ```


_Originally posted by @omry in https://github.com/facebookresearch/hydra/pull/912#issuecomment-679236669_


Discussion:
Not blocking Hydra 1.0.

Resolving patch:
diff --git a/plugins/hydra_ax_sweeper/hydra_plugins/hydra_ax_sweeper/_core.py b/plugins/hydra_ax_sweeper/hydra_plugins/hydra_ax_sweeper/_core.py
--- a/plugins/hydra_ax_sweeper/hydra_plugins/hydra_ax_sweeper/_core.py
+++ b/plugins/hydra_ax_sweeper/hydra_plugins/hydra_ax_sweeper/_core.py
@@ -169,10 +169,6 @@ def sweep(self, arguments: List[str]) -> None:
 
             current_parallelism_index += 1
 
-        best_parameters = {
-            normalize_key(key, str_to_replace=".", str_to_replace_with="_"): value
-            for key, value in best_parameters.items()
-        }
         results_to_serialize = {"optimizer": "ax", "ax": best_parameters}
         OmegaConf.save(
             OmegaConf.create(results_to_serialize),
@@ -204,7 +200,6 @@ def setup_ax_client(self, arguments: List[str]) -> AxClient:
         """Method to setup the Ax Client"""
         parameters: List[Dict[str, Any]] = []
         for key, value in self.ax_params.items():
-            key = normalize_key(key, str_to_replace="_", str_to_replace_with=".")
             param = OmegaConf.to_container(value, resolve=True)
             assert isinstance(param, Dict)
             if param["type"] == "range":
@@ -270,20 +265,6 @@ def chunks(batch: List[Any], n: Optional[int]) -> Iterable[List[Any]]:
             yield batch[i : i + n]
 
 
-def normalize_key(key: str, str_to_replace: str, str_to_replace_with: str) -> str:
-    """Process the key by replacing "str_to_replace" with "str_to_replace_with".
-    The "str_to_replace" escaped using r"\\" are not replaced. Finally, the r"\\" is removed.
-    """
-    str_to_escape = "\\" + str_to_replace
-    splits_to_update = key.split(str_to_escape)
-    updated_splits = [
-        current_split.replace(str_to_replace, str_to_replace_with)
-        for current_split in splits_to_update
-    ]
-    new_key = str_to_escape.join(updated_splits).replace("\\", "")
-    return new_key
-
-
 def create_range_param_using_interval_override(override: Override) -> Dict[str, Any]:
     key = override.get_key_element()
     value = override.value()


Test patch:
diff --git a/plugins/hydra_ax_sweeper/tests/apps/polynomial.yaml b/plugins/hydra_ax_sweeper/tests/apps/polynomial.yaml
--- a/plugins/hydra_ax_sweeper/tests/apps/polynomial.yaml
+++ b/plugins/hydra_ax_sweeper/tests/apps/polynomial.yaml
@@ -18,6 +18,6 @@ hydra:
         max_epochs_without_improvement: 2
 
       params:
-        polynomial_x:
+        polynomial.x:
           type: range
           bounds: [-1, 1]
diff --git a/plugins/hydra_ax_sweeper/tests/config/params/basic.yaml b/plugins/hydra_ax_sweeper/tests/config/params/basic.yaml
--- a/plugins/hydra_ax_sweeper/tests/config/params/basic.yaml
+++ b/plugins/hydra_ax_sweeper/tests/config/params/basic.yaml
@@ -1,8 +1,8 @@
 # @package hydra.sweeper.ax_config.params
-quadratic_x:
+quadratic.x:
   type: range
   bounds: [-1, 1]
 
-quadratic_y:
+quadratic.y:
   type: range
   bounds: [-1, 1]
diff --git a/plugins/hydra_ax_sweeper/tests/config/params/nested_with_escape_char.yaml b/plugins/hydra_ax_sweeper/tests/config/params/nested_with_escape_char.yaml
deleted file mode 100644
--- a/plugins/hydra_ax_sweeper/tests/config/params/nested_with_escape_char.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-# @package hydra.sweeper.ax_config.params
-quadratic_x\_arg:
-  type: range
-  bounds: [-1, 1]
-
-quadratic_y\_arg:
-  type: range
-  bounds: [-1, 1]
diff --git a/plugins/hydra_ax_sweeper/tests/config/quadratic/nested_with_escape_char.yaml b/plugins/hydra_ax_sweeper/tests/config/quadratic/nested_with_escape_char.yaml
deleted file mode 100644
--- a/plugins/hydra_ax_sweeper/tests/config/quadratic/nested_with_escape_char.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-# @package _group_
-x_arg: ???
-y_arg: ???
diff --git a/plugins/hydra_ax_sweeper/tests/test_ax_sweeper_plugin.py b/plugins/hydra_ax_sweeper/tests/test_ax_sweeper_plugin.py
--- a/plugins/hydra_ax_sweeper/tests/test_ax_sweeper_plugin.py
+++ b/plugins/hydra_ax_sweeper/tests/test_ax_sweeper_plugin.py
@@ -30,10 +30,6 @@ def quadratic(cfg: DictConfig) -> Any:
     return 100 * (cfg.quadratic.x ** 2) + 1 * cfg.quadratic.y
 
 
-def nested_quadratic_with_escape_char(cfg: DictConfig) -> Any:
-    return 100 * (cfg.quadratic.x_arg ** 2) + 1 * cfg.quadratic.y_arg
-
-
 @pytest.mark.parametrize(  # type: ignore
     "n,expected",
     [
@@ -104,8 +100,8 @@ def test_jobs_configured_via_config(hydra_sweep_runner: TSweepRunner) -> None:
         assert returns["optimizer"] == "ax"
         assert len(returns) == 2
         best_parameters = returns.ax
-        assert math.isclose(best_parameters.quadratic_x, 0.0, abs_tol=1e-4)
-        assert math.isclose(best_parameters.quadratic_y, -1.0, abs_tol=1e-4)
+        assert math.isclose(best_parameters["quadratic.x"], 0.0, abs_tol=1e-4)
+        assert math.isclose(best_parameters["quadratic.y"], -1.0, abs_tol=1e-4)
 
 
 def test_jobs_configured_via_cmd(hydra_sweep_runner: TSweepRunner) -> None:
@@ -129,8 +125,8 @@ def test_jobs_configured_via_cmd(hydra_sweep_runner: TSweepRunner) -> None:
         assert returns["optimizer"] == "ax"
         assert len(returns) == 2
         best_parameters = returns.ax
-        assert math.isclose(best_parameters.quadratic_x, -2.0, abs_tol=1e-4)
-        assert math.isclose(best_parameters.quadratic_y, 2.0, abs_tol=1e-4)
+        assert math.isclose(best_parameters["quadratic.x"], -2.0, abs_tol=1e-4)
+        assert math.isclose(best_parameters["quadratic.y"], 2.0, abs_tol=1e-4)
 
 
 def test_jobs_configured_via_cmd_and_config(hydra_sweep_runner: TSweepRunner) -> None:
@@ -154,8 +150,8 @@ def test_jobs_configured_via_cmd_and_config(hydra_sweep_runner: TSweepRunner) ->
         assert returns["optimizer"] == "ax"
         assert len(returns) == 2
         best_parameters = returns.ax
-        assert math.isclose(best_parameters.quadratic_x, -2.0, abs_tol=1e-4)
-        assert math.isclose(best_parameters.quadratic_y, 1.0, abs_tol=1e-4)
+        assert math.isclose(best_parameters["quadratic.x"], -2.0, abs_tol=1e-4)
+        assert math.isclose(best_parameters["quadratic.y"], 1.0, abs_tol=1e-4)
 
 
 def test_configuration_set_via_cmd_and_default_config(
@@ -185,8 +181,8 @@ def test_configuration_set_via_cmd_and_default_config(
         returns = OmegaConf.load(f"{sweep.temp_dir}/optimization_results.yaml")
         assert isinstance(returns, DictConfig)
         best_parameters = returns.ax
-        assert "quadratic_x" in best_parameters
-        assert "quadratic_y" in best_parameters
+        assert "quadratic.x" in best_parameters
+        assert "quadratic.y" in best_parameters
 
 
 @pytest.mark.parametrize(  # type: ignore
@@ -304,52 +300,3 @@ def test_example_app(tmpdir: Path) -> None:
     result, _ = get_run_output(cmd)
     assert "banana.x: range=[-5, 5]" in result
     assert "banana.y: range=[-5.0, 10.1]" in result
-
-
-@pytest.mark.parametrize(  # type: ignore
-    "overrides",
-    [[], ["quadratic.x_arg=int(interval(-1, 1))"]],
-)
-def test_jobs_configured_via_nested_config(
-    hydra_sweep_runner: TSweepRunner, overrides: List[str]
-) -> None:
-    sweep = hydra_sweep_runner(
-        calling_file="tests/test_ax_sweeper_plugin.py",
-        calling_module=None,
-        task_function=nested_quadratic_with_escape_char,
-        config_path="config",
-        config_name="config.yaml",
-        overrides=[
-            "hydra/launcher=basic",
-            "quadratic=nested_with_escape_char",
-            "params=nested_with_escape_char",
-        ]
-        + overrides,
-    )
-    with sweep:
-        assert sweep.returns is None
-        returns = OmegaConf.load(f"{sweep.temp_dir}/optimization_results.yaml")
-        assert isinstance(returns, DictConfig)
-        assert returns.optimizer == "ax"
-        assert len(returns) == 2
-        best_parameters = returns.ax
-        assert math.isclose(best_parameters.quadratic_x_arg, 0.0, abs_tol=1e-4)
-        assert math.isclose(best_parameters.quadratic_y_arg, -1.0, abs_tol=1e-4)
-
-
-@pytest.mark.parametrize(  # type: ignore
-    "inp, str_to_replace, str_to_replace_with, expected",
-    [
-        ("apple", ".", "_", "apple"),
-        ("a.pple", ".", "_", "a_pple"),
-        ("a.p.ple", ".", "_", "a_p_ple"),
-        (r"a\.pple", ".", "_", "a.pple"),
-        (r"a.p\.pl.e", ".", "_", "a_p.pl_e"),
-    ],
-)
-def test_process_key_method(
-    inp: str, str_to_replace: str, str_to_replace_with: str, expected: str
-) -> None:
-    from hydra_plugins.hydra_ax_sweeper._core import normalize_key
-
-    assert normalize_key(inp, str_to_replace, str_to_replace_with) == expected