Repository: facebookresearch/hydra

Issue:
Changes in package header in Hydra 1.1
- [ ] Deprecate the use cases requiring changes in 1.1
- [ ] Create an upgrade page in the website based on this content.



Discussion:

Patch:
diff --git a/hydra/core/default_element.py b/hydra/core/default_element.py
--- a/hydra/core/default_element.py
+++ b/hydra/core/default_element.py
@@ -112,12 +112,25 @@ def is_deleted(self) -> bool:
 
     def set_package_header(self, package_header: Optional[str]) -> None:
         assert self.__dict__["package_header"] is None
-        if (
-            package_header is None
-            or package_header == "_group_"
-            or self.get_default_package() == package_header
-        ):
+
+        if package_header is None:
+            return
+
+        if "_group_" in package_header or "_name_" in package_header:
+            path = self.get_config_path()
+            url = "https://hydra.cc/docs/next/upgrades/1.0_to_1.1/changes_to_package_header"
+            warnings.warn(
+                category=UserWarning,
+                message=dedent(
+                    f"""\
+                    In '{path}': Usage of deprecated keyword in package header '# @package {package_header}'.
+                    See {url} for more information"""
+                ),
+            )
+
+        if package_header == "_group_":
             return
+
         # package header is always interpreted as absolute.
         # if it does not have a _global_ prefix, add it.
         if package_header != "_global_" and not package_header.startswith("_global_."):
@@ -125,6 +138,7 @@ def set_package_header(self, package_header: Optional[str]) -> None:
                 package_header = "_global_"
             else:
                 package_header = f"_global_.{package_header}"
+
         package_header = package_header.replace("_group_", self.get_default_package())
         self.__dict__["package_header"] = package_header
 


Test patch:
diff --git a/plugins/hydra_ax_sweeper/tests/config/quadratic/basic.yaml b/plugins/hydra_ax_sweeper/tests/config/quadratic/basic.yaml
--- a/plugins/hydra_ax_sweeper/tests/config/quadratic/basic.yaml
+++ b/plugins/hydra_ax_sweeper/tests/config/quadratic/basic.yaml
@@ -1,3 +1,2 @@
-# @package _group_
 x: ???
 y: ???
diff --git a/tests/defaults_list/data/deprecated_headers/group.yaml b/tests/defaults_list/data/deprecated_headers/group.yaml
new file mode 100644
--- /dev/null
+++ b/tests/defaults_list/data/deprecated_headers/group.yaml
@@ -0,0 +1 @@
+# @package _group_
diff --git a/tests/defaults_list/data/deprecated_headers/group_foo.yaml b/tests/defaults_list/data/deprecated_headers/group_foo.yaml
new file mode 100644
--- /dev/null
+++ b/tests/defaults_list/data/deprecated_headers/group_foo.yaml
@@ -0,0 +1 @@
+# @package _group_.foo
diff --git a/tests/defaults_list/data/deprecated_headers/group_name.yaml b/tests/defaults_list/data/deprecated_headers/group_name.yaml
new file mode 100644
--- /dev/null
+++ b/tests/defaults_list/data/deprecated_headers/group_name.yaml
@@ -0,0 +1 @@
+# @package _group_._name_
diff --git a/tests/defaults_list/data/deprecated_headers/name.yaml b/tests/defaults_list/data/deprecated_headers/name.yaml
new file mode 100644
--- /dev/null
+++ b/tests/defaults_list/data/deprecated_headers/name.yaml
@@ -0,0 +1 @@
+# @package _name_
diff --git a/tests/defaults_list/test_defaults_list.py b/tests/defaults_list/test_defaults_list.py
--- a/tests/defaults_list/test_defaults_list.py
+++ b/tests/defaults_list/test_defaults_list.py
@@ -1503,7 +1503,7 @@ def test_duplicate_items(
     ],
 )
 def test_load_group_header(
-    config_name: str, overrides: List[str], expected: List[ResultDefault]
+    config_name: str, overrides: List[str], expected: List[ResultDefault], recwarn: Any
 ) -> None:
     _test_defaults_list_impl(
         config_name=config_name,
@@ -1740,7 +1740,7 @@ def test_with_missing_config(
     ],
 )
 def test_set_package_header_no_parent_pkg(
-    default: InputDefault, package_header: str, expected: str
+    default: InputDefault, package_header: str, expected: str, recwarn: Any
 ) -> None:
     default.update_parent(parent_base_dir="", parent_package="")
     default.set_package_header(package_header)
@@ -1759,7 +1759,7 @@ def test_set_package_header_no_parent_pkg(
     ],
 )
 def test_set_package_header_with_parent_pkg(
-    default: InputDefault, package_header: str, expected: str
+    default: InputDefault, package_header: str, expected: str, recwarn: Any
 ) -> None:
     default.update_parent(parent_base_dir="", parent_package="parent_pkg")
     default.set_package_header(package_header)
diff --git a/tests/defaults_list/test_defaults_tree.py b/tests/defaults_list/test_defaults_tree.py
--- a/tests/defaults_list/test_defaults_tree.py
+++ b/tests/defaults_list/test_defaults_tree.py
@@ -2274,3 +2274,55 @@ def test_choices(
     )
     assert res is not None
     assert res.overrides.known_choices == expected_choices
+
+
+@mark.parametrize(
+    ("config_name", "overrides", "package_header", "expected"),
+    [
+        param(
+            "deprecated_headers/group",
+            [],
+            "_group_",
+            DefaultsTreeNode(node=ConfigDefault(path="deprecated_headers/group")),
+            id="deprecated_headers/group",
+        ),
+        param(
+            "deprecated_headers/name",
+            [],
+            "_name_",
+            DefaultsTreeNode(node=ConfigDefault(path="deprecated_headers/name")),
+            id="deprecated_headers/name",
+        ),
+        param(
+            "deprecated_headers/group_name",
+            [],
+            "_group_._name_",
+            DefaultsTreeNode(node=ConfigDefault(path="deprecated_headers/group_name")),
+            id="deprecated_headers/group_name",
+        ),
+        param(
+            "deprecated_headers/group_foo",
+            [],
+            "_group_.foo",
+            DefaultsTreeNode(node=ConfigDefault(path="deprecated_headers/group_foo")),
+            id="deprecated_headers/group_foo",
+        ),
+    ],
+)
+def test_deprecated_package_header_keywords(
+    config_name: Optional[str],
+    overrides: List[str],
+    package_header: str,
+    expected: DefaultsTreeNode,
+) -> None:
+    msg = dedent(
+        f"""\
+        In '{config_name}': Usage of deprecated keyword in package header '# @package {package_header}'.
+        See https://hydra.cc/docs/next/upgrades/1.0_to_1.1/changes_to_package_header for more information"""
+    )
+    with warns(UserWarning, match=re.escape(msg)):
+        _test_defaults_tree_impl(
+            config_name=config_name,
+            input_overrides=overrides,
+            expected=expected,
+        )
diff --git a/tests/test_apps/defaults_pkg_with_dot/dataset/imagenet.yaml b/tests/test_apps/defaults_pkg_with_dot/dataset/imagenet.yaml
--- a/tests/test_apps/defaults_pkg_with_dot/dataset/imagenet.yaml
+++ b/tests/test_apps/defaults_pkg_with_dot/dataset/imagenet.yaml
@@ -1,3 +1,2 @@
-# @package _group_
 name: imagenet
 path: /datasets/imagenet
diff --git a/tests/test_apps/schema-overrides-hydra/group/a.yaml b/tests/test_apps/schema-overrides-hydra/group/a.yaml
--- a/tests/test_apps/schema-overrides-hydra/group/a.yaml
+++ b/tests/test_apps/schema-overrides-hydra/group/a.yaml
@@ -1,2 +1 @@
-# @package _group_
 name: a
diff --git a/tests/test_apps/user-config-dir/conf/dataset/imagenet.yaml b/tests/test_apps/user-config-dir/conf/dataset/imagenet.yaml
--- a/tests/test_apps/user-config-dir/conf/dataset/imagenet.yaml
+++ b/tests/test_apps/user-config-dir/conf/dataset/imagenet.yaml
@@ -1,2 +1 @@
-# @package _group_
 name: imagenet
diff --git a/tests/test_apps/user-config-dir/user-dir/dataset/cifar10.yaml b/tests/test_apps/user-config-dir/user-dir/dataset/cifar10.yaml
--- a/tests/test_apps/user-config-dir/user-dir/dataset/cifar10.yaml
+++ b/tests/test_apps/user-config-dir/user-dir/dataset/cifar10.yaml
@@ -1,2 +1 @@
-# @package _group_
 name: cifar10
diff --git a/tests/test_compose.py b/tests/test_compose.py
--- a/tests/test_compose.py
+++ b/tests/test_compose.py
@@ -209,7 +209,6 @@ def test_initialize_config_dir_ctx_with_absolute_dir(
 
     cfg_file = tmpdir / "test_group" / "test.yaml"
     with open(str(cfg_file), "w") as f:
-        f.write("# @package _group_\n")
         OmegaConf.save(cfg, f)
 
     with initialize_config_dir(config_dir=str(tmpdir)):