Repository: facebookresearch/hydra

Issue:
[Feature Request] Allow Initialize to take a module
# 🚀 Feature Request

Allow hydra.experimental.initialize to take a calling module

Comments:

Patch:
diff --git a/examples/advanced/ad_hoc_composition/hydra_compose_example.py b/examples/advanced/ad_hoc_composition/hydra_compose_example.py
index e113bfcd36..c44c47a54d 100644
--- a/examples/advanced/ad_hoc_composition/hydra_compose_example.py
+++ b/examples/advanced/ad_hoc_composition/hydra_compose_example.py
@@ -4,7 +4,7 @@ from hydra.experimental import compose, initialize
 if __name__ == "__main__":
     # initialize the Hydra subsystem.
     # This is needed for apps that cannot have a standard @hydra.main() entry point
-    initialize(config_dir="conf", strict=True)
+    initialize(config_path="conf", strict=True)
 
     cfg = compose("config.yaml", overrides=["db=mysql", "db.user=${env:USER}"])
     print(cfg.pretty(resolve=True))
diff --git a/examples/notebook/hydra_notebook_example.ipynb b/examples/notebook/hydra_notebook_example.ipynb
index 2e33ed631f..5798ba4513 100644
--- a/examples/notebook/hydra_notebook_example.ipynb
+++ b/examples/notebook/hydra_notebook_example.ipynb
@@ -45,7 +45,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "initialize(config_dir=\"../../hydra/test_utils/configs/cloud_infra_example\")"
+    "initialize(config_path=\"../../hydra/test_utils/configs/cloud_infra_example\")"
    ]
   },
   {
@@ -209,17 +209,8 @@
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
    "version": "3.8.2"
-  },
-  "pycharm": {
-   "stem_cell": {
-    "cell_type": "raw",
-    "metadata": {
-     "collapsed": false
-    },
-    "source": []
-   }
   }
  },
  "nbformat": 4,
  "nbformat_minor": 2
-}
+}
\ No newline at end of file
diff --git a/hydra/experimental/compose.py b/hydra/experimental/compose.py
index 5d787f81a0..e7aa643dbd 100644
--- a/hydra/experimental/compose.py
+++ b/hydra/experimental/compose.py
@@ -9,31 +9,58 @@ from hydra.core.global_hydra import GlobalHydra
 
 
 def initialize(
-    config_dir: Optional[str] = None,
+    config_path: Optional[str] = None,
     strict: Optional[bool] = None,
     caller_stack_depth: int = 1,
 ) -> None:
     """
-    :param config_dir: config directory relative to the calling script
-    :param strict:
-    :param caller_stack_depth:
-    :return:
+    Initialize automatically detect the calling file or module.
+    config_path is relative to the detected calling for or module.
+
+    :param config_path: A directory relative to the declaring python file or module
+    :param strict: (Deprecated), will be removed in the next major version
+    :param caller_stack_depth: stack depth of module the config_path is relative to
     """
     calling_file, calling_module = detect_calling_file_or_module_from_stack_frame(
         caller_stack_depth + 1
     )
     Hydra.create_main_hydra_file_or_module(
-        calling_file, calling_module, config_dir, strict
+        calling_file, calling_module, config_path, strict
     )
 
 
+def initialize_with_file(
+    calling_file: Optional[str], config_path: Optional[str] = None
+) -> None:
+    """
+    Initialize Hydra and add the config_path to the search path.
+    The config path is relative to the calling_file.
+    :param calling_file : The file to make the config_path relative to
+    :param config_path : The config path
+    """
+    Hydra.create_main_hydra_file_or_module(calling_file, None, config_path, None)
+
+
+def initialize_with_module(
+    calling_module: Optional[str], config_path: Optional[str] = None
+) -> None:
+    """
+    Initialize Hydra and add the config_path to the search path.
+    The config path is relative to the calling_module.
+    :param calling_module : The module to make the config_path relative to
+    :param config_path : The config path
+    """
+
+    Hydra.create_main_hydra_file_or_module(None, calling_module, config_path, None)
+
+
 def compose(
     config_name: Optional[str] = None,
     overrides: List[str] = [],
     strict: Optional[bool] = None,
 ) -> DictConfig:
     """
-    :param config_name: optional config name to load
+    :param config_name: the name of the config (usually the file name without the .yaml extension)
     :param overrides: list of overrides for config file
     :param strict: optionally override the default strict mode
     :return: the composed config
diff --git a/news/574.feature b/news/574.feature
new file mode 100644
index 0000000000..ce06c5eff8
--- /dev/null
+++ b/news/574.feature
@@ -0,0 +1,1 @@
+Add hydra.experimental.{initialize_with_file, initialize_with_module}
diff --git a/website/docs/experimental/hydra_compose.md b/website/docs/experimental/hydra_compose.md
index 803e918c72..c5c821430b 100644
--- a/website/docs/experimental/hydra_compose.md
+++ b/website/docs/experimental/hydra_compose.md
@@ -4,8 +4,8 @@ title: Compose API
 sidebar_label: Compose API
 ---
 
-Hydra 0.11.0 introduces a new experimental API for composing configuration via the `hydra.experimental.compose()` function.
-Prior to calling compose(), you have to initialize Hydra: This can be done by using the standard `@hydra.main()` or by calling `hydra.experimental.initialize()`.
+The compose API can compose a configuration similar to `@hydra.main()` anywhere in the code.  
+Prior to calling compose(), you have to initialize Hydra: This can be done by using the standard `@hydra.main()` or by calling one of the initialization methods listed below.
 
 Here is an [example Jupyter notebook utilizing this API](https://github.com/facebookresearch/hydra/tree/master/examples/notebook).
 
@@ -15,7 +15,7 @@ from hydra.experimental import compose, initialize
 
 
 if __name__ == "__main__":
-    initialize(config_dir="conf")
+    initialize(config_path="conf")
 
     cfg = compose("config.yaml", overrides=["db=mysql", "db.user=me"])
     print(cfg.pretty())
@@ -28,15 +28,42 @@ def compose(config_file=None, overrides=[]):
     :param overrides: list of overrides for config file
     :return: the composed config
     """
+    ...
 
+def initialize(
+    config_path: Optional[str] = None,
+    strict: Optional[bool] = None,
+    caller_stack_depth: int = 1,
+) -> None:
+    """
+    Initialize automatically detect the calling file or module.
+    config_path is relative to the detected calling for or module.
 
-def initialize(config_dir=None, caller_stack_depth=1):
+    :param config_path: A directory relative to the declaring python file or module
+    :param strict: (Deprecated), will be removed in the next major version
+    :param caller_stack_depth: stack depth of module the config_path is relative to
     """
-    Initializes the Hydra sub system
 
-    :param config_dir: config directory relative to the calling script
-    :param caller_stack_depth:
-    :return:
+def initialize_with_file(
+    calling_file: Optional[str], config_path: Optional[str] = None
+):
+    """
+    Initialize Hydra and add the config_path to the search path.
+    The config path is relative to the calling_file.
+    :param calling_file : The file to make the config_path relative to
+    :param config_path : The config path
+    """
+    ...
+
+def initialize_with_module(
+    calling_module: Optional[str], config_path: Optional[str] = None
+):
+    """
+    Initialize Hydra and add the config_path to the search path.
+    The config path is relative to the calling_module.
+    :param calling_module : The module to make the config_path relative to
+    :param config_path : The config path
     """
+    ...
 ```
 
diff --git a/website/versioned_docs/version-0.11/advanced/hydra_compose.md b/website/versioned_docs/version-0.11/advanced/hydra_compose.md
index cb9a655b96..f79ee77c75 100644
--- a/website/versioned_docs/version-0.11/advanced/hydra_compose.md
+++ b/website/versioned_docs/version-0.11/advanced/hydra_compose.md
@@ -16,7 +16,7 @@ from hydra.experimental import compose, initialize
 
 if __name__ == "__main__":
     initialize(
-        config_dir="conf", strict=True,
+        config_path="conf", strict=True,
     )
 
     cfg = compose("config.yaml", overrides=["db=mysql", "db.user=me"])


Test patch:
diff --git a/hydra/test_utils/test_utils.py b/hydra/test_utils/test_utils.py
index 2a7fdaa6b5..11f80bd1ac 100644
--- a/hydra/test_utils/test_utils.py
+++ b/hydra/test_utils/test_utils.py
@@ -42,7 +42,7 @@ class GlobalHydraContext:
 
     def __enter__(self) -> "GlobalHydraContext":
         hydra.experimental.initialize(
-            config_dir=self.config_dir, strict=self.strict, caller_stack_depth=2
+            config_path=self.config_dir, strict=self.strict, caller_stack_depth=2
         )
         return self
 
diff --git a/tests/test_compose.py b/tests/test_compose.py
index 6fd3e7c830..a5626cfdbe 100644
--- a/tests/test_compose.py
+++ b/tests/test_compose.py
@@ -9,6 +9,7 @@ from hydra.core.config_search_path import SearchPathQuery
 from hydra.core.global_hydra import GlobalHydra
 from hydra.errors import HydraException
 from hydra.experimental import compose, initialize
+from hydra.experimental.compose import initialize_with_file, initialize_with_module
 from hydra.test_utils.test_utils import (
     TGlobalHydraContext,
     chdir_hydra_root,
@@ -20,13 +21,13 @@ chdir_hydra_root()
 
 def test_initialize(restore_singletons: Any) -> None:
     assert not GlobalHydra().is_initialized()
-    initialize(config_dir=None)
+    initialize(config_path=None)
     assert GlobalHydra().is_initialized()
 
 
 def test_initialize_with_config_dir(restore_singletons: Any) -> None:
     assert not GlobalHydra().is_initialized()
-    initialize(config_dir="../hydra/test_utils/configs")
+    initialize(config_path="../hydra/test_utils/configs")
     assert GlobalHydra().is_initialized()
 
     gh = GlobalHydra.instance()
@@ -130,7 +131,7 @@ def test_strict_deprecation_warning(restore_singletons: Any) -> None:
         "\nSee https://hydra.cc/next/upgrades/0.11_to_1.0/strict_mode_flag_deprecated"
     )
     with pytest.warns(expected_warning=UserWarning, match=re.escape(msg)):
-        initialize(config_dir=None, strict=True)
+        initialize(config_path=None, strict=True)
 
 
 @pytest.mark.usefixtures("restore_singletons")
@@ -231,3 +232,21 @@ def test_missing_init_py_error(hydra_global_context: TGlobalHydraContext) -> Non
             config_dir="../hydra/test_utils/configs/missing_init_py"
         ):
             ...
+
+
+def test_initialize_with_file(restore_singletons: Any) -> None:
+    initialize_with_file(
+        calling_file="tests/test_apps/app_with_cfg_groups/my_app.py", config_path="conf"
+    )
+    assert compose(config_name="config") == {
+        "optimizer": {"type": "nesterov", "lr": 0.001}
+    }
+
+
+def test_initialize_with_module(restore_singletons: Any) -> None:
+    initialize_with_module(
+        calling_module="tests.test_apps.app_with_cfg_groups.my_app", config_path="conf"
+    )
+    assert compose(config_name="config") == {
+        "optimizer": {"type": "nesterov", "lr": 0.001}
+    }