From 2bda47d949816133659bf846cc9e148d9bbe0e31 Mon Sep 17 00:00:00 2001 From: Omry Yadan Date: Fri, 25 Dec 2020 19:04:48 -0800 Subject: [PATCH] Documentation update - Defaults List - Packages - Extending configs - Configuring experiments --- .../conf/config.yaml | 4 + .../conf/db/mysql.yaml | 1 + .../conf/db/sqlite.yaml | 1 + .../conf/server/apache.yaml | 2 + .../conf/server/nginx.yaml | 1 + .../conf/server_db/apache_sqlite.yaml | 2 + .../defaults_list_interpolation/my_app.py | 13 + .../nested_defaults_list/conf/config.yaml | 4 + .../nested_defaults_list/conf/config2.yaml | 5 + .../conf/server/apache.yaml | 4 + .../conf/server/db/mysql.yaml | 1 + .../conf/server/db/sqlite.yaml | 1 + .../advanced/nested_defaults_list/my_app.py | 13 + .../configuring_experiments/conf/config.yaml | 3 + .../conf/db/mysql.yaml | 1 + .../conf/db/sqlite.yaml | 1 + .../conf/experiment/aplite.yaml | 7 + .../conf/experiment/nglite.yaml | 7 + .../conf/server/apache.yaml | 2 + .../conf/server/nginx.yaml | 2 + .../configuring_experiments/my_app.py | 13 + .../extending_configs/conf/config.yaml | 2 + .../extending_configs/conf/db/base_mysql.yaml | 4 + .../mysql_extending_from_another_group.yaml | 7 + .../db/mysql_extending_from_this_group.yaml | 7 + .../conf/db_schema/base_mysql.yaml | 4 + examples/patterns/extending_configs/my_app.py | 13 + hydra/_internal/defaults_list.py | 2 +- hydra/conf/__init__.py | 44 +-- .../tests/test_ray_launcher.py | 2 +- tests/defaults_list/test_defaults_tree.py | 2 +- tests/test_config_loader.py | 60 +-- tests/test_examples/test_patterns.py | 60 ++- website/docs/advanced/defaults_list.md | 349 +++++++++++------- website/docs/advanced/overriding_packages.md | 211 +++++++---- website/docs/configure_hydra/Intro.md | 60 +-- .../docs/patterns/configuring_experiments.md | 183 +++++++++ website/docs/patterns/extending_configs.md | 70 ++++ .../patterns/write_protect_config_node.md | 2 +- website/docs/terminology.md | 12 +- .../changes_to_default_composition_order.md | 97 +++++ .../defaults_list_interpolation_changes.md | 5 +- .../1.0_to_1.1/defaults_list_override.md | 23 ++ website/sidebars.js | 6 +- 44 files changed, 1003 insertions(+), 310 deletions(-) create mode 100644 examples/advanced/defaults_list_interpolation/conf/config.yaml create mode 100644 examples/advanced/defaults_list_interpolation/conf/db/mysql.yaml create mode 100644 examples/advanced/defaults_list_interpolation/conf/db/sqlite.yaml create mode 100644 examples/advanced/defaults_list_interpolation/conf/server/apache.yaml create mode 100644 examples/advanced/defaults_list_interpolation/conf/server/nginx.yaml create mode 100644 examples/advanced/defaults_list_interpolation/conf/server_db/apache_sqlite.yaml create mode 100644 examples/advanced/defaults_list_interpolation/my_app.py create mode 100644 examples/advanced/nested_defaults_list/conf/config.yaml create mode 100644 examples/advanced/nested_defaults_list/conf/config2.yaml create mode 100644 examples/advanced/nested_defaults_list/conf/server/apache.yaml create mode 100644 examples/advanced/nested_defaults_list/conf/server/db/mysql.yaml create mode 100644 examples/advanced/nested_defaults_list/conf/server/db/sqlite.yaml create mode 100644 examples/advanced/nested_defaults_list/my_app.py create mode 100644 examples/patterns/configuring_experiments/conf/config.yaml create mode 100644 examples/patterns/configuring_experiments/conf/db/mysql.yaml create mode 100644 examples/patterns/configuring_experiments/conf/db/sqlite.yaml create mode 100644 examples/patterns/configuring_experiments/conf/experiment/aplite.yaml create mode 100644 examples/patterns/configuring_experiments/conf/experiment/nglite.yaml create mode 100644 examples/patterns/configuring_experiments/conf/server/apache.yaml create mode 100644 examples/patterns/configuring_experiments/conf/server/nginx.yaml create mode 100644 examples/patterns/configuring_experiments/my_app.py create mode 100644 examples/patterns/extending_configs/conf/config.yaml create mode 100644 examples/patterns/extending_configs/conf/db/base_mysql.yaml create mode 100644 examples/patterns/extending_configs/conf/db/mysql_extending_from_another_group.yaml create mode 100644 examples/patterns/extending_configs/conf/db/mysql_extending_from_this_group.yaml create mode 100644 examples/patterns/extending_configs/conf/db_schema/base_mysql.yaml create mode 100644 examples/patterns/extending_configs/my_app.py create mode 100644 website/docs/patterns/configuring_experiments.md create mode 100644 website/docs/patterns/extending_configs.md create mode 100644 website/docs/upgrades/1.0_to_1.1/changes_to_default_composition_order.md create mode 100644 website/docs/upgrades/1.0_to_1.1/defaults_list_override.md diff --git a/examples/advanced/defaults_list_interpolation/conf/config.yaml b/examples/advanced/defaults_list_interpolation/conf/config.yaml new file mode 100644 index 0000000000..c38d7ad303 --- /dev/null +++ b/examples/advanced/defaults_list_interpolation/conf/config.yaml @@ -0,0 +1,4 @@ +defaults: + - db: mysql + - server: apache + - optional server_db: ${server}_${db} diff --git a/examples/advanced/defaults_list_interpolation/conf/db/mysql.yaml b/examples/advanced/defaults_list_interpolation/conf/db/mysql.yaml new file mode 100644 index 0000000000..2fff82707d --- /dev/null +++ b/examples/advanced/defaults_list_interpolation/conf/db/mysql.yaml @@ -0,0 +1 @@ +name: mysql diff --git a/examples/advanced/defaults_list_interpolation/conf/db/sqlite.yaml b/examples/advanced/defaults_list_interpolation/conf/db/sqlite.yaml new file mode 100644 index 0000000000..0e179b7c33 --- /dev/null +++ b/examples/advanced/defaults_list_interpolation/conf/db/sqlite.yaml @@ -0,0 +1 @@ +name: sqlite diff --git a/examples/advanced/defaults_list_interpolation/conf/server/apache.yaml b/examples/advanced/defaults_list_interpolation/conf/server/apache.yaml new file mode 100644 index 0000000000..4b1d7d721c --- /dev/null +++ b/examples/advanced/defaults_list_interpolation/conf/server/apache.yaml @@ -0,0 +1,2 @@ +name: apache +workers: 10 diff --git a/examples/advanced/defaults_list_interpolation/conf/server/nginx.yaml b/examples/advanced/defaults_list_interpolation/conf/server/nginx.yaml new file mode 100644 index 0000000000..8835eeebcb --- /dev/null +++ b/examples/advanced/defaults_list_interpolation/conf/server/nginx.yaml @@ -0,0 +1 @@ +name: nginx diff --git a/examples/advanced/defaults_list_interpolation/conf/server_db/apache_sqlite.yaml b/examples/advanced/defaults_list_interpolation/conf/server_db/apache_sqlite.yaml new file mode 100644 index 0000000000..80ea53d409 --- /dev/null +++ b/examples/advanced/defaults_list_interpolation/conf/server_db/apache_sqlite.yaml @@ -0,0 +1,2 @@ +# @package server +workers: 5 diff --git a/examples/advanced/defaults_list_interpolation/my_app.py b/examples/advanced/defaults_list_interpolation/my_app.py new file mode 100644 index 0000000000..6b1303d511 --- /dev/null +++ b/examples/advanced/defaults_list_interpolation/my_app.py @@ -0,0 +1,13 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +from omegaconf import DictConfig, OmegaConf + +import hydra + + +@hydra.main(config_path="conf", config_name="config") +def my_app(cfg: DictConfig) -> None: + print(OmegaConf.to_yaml(cfg)) + + +if __name__ == "__main__": + my_app() diff --git a/examples/advanced/nested_defaults_list/conf/config.yaml b/examples/advanced/nested_defaults_list/conf/config.yaml new file mode 100644 index 0000000000..eac458c2f2 --- /dev/null +++ b/examples/advanced/nested_defaults_list/conf/config.yaml @@ -0,0 +1,4 @@ +defaults: + - server/apache + +debug: false diff --git a/examples/advanced/nested_defaults_list/conf/config2.yaml b/examples/advanced/nested_defaults_list/conf/config2.yaml new file mode 100644 index 0000000000..679df8d349 --- /dev/null +++ b/examples/advanced/nested_defaults_list/conf/config2.yaml @@ -0,0 +1,5 @@ +defaults: + - server/apache + - override server/db: sqlite + +debug: false diff --git a/examples/advanced/nested_defaults_list/conf/server/apache.yaml b/examples/advanced/nested_defaults_list/conf/server/apache.yaml new file mode 100644 index 0000000000..e3214dd06a --- /dev/null +++ b/examples/advanced/nested_defaults_list/conf/server/apache.yaml @@ -0,0 +1,4 @@ +defaults: + - db: mysql + +name: apache diff --git a/examples/advanced/nested_defaults_list/conf/server/db/mysql.yaml b/examples/advanced/nested_defaults_list/conf/server/db/mysql.yaml new file mode 100644 index 0000000000..2fff82707d --- /dev/null +++ b/examples/advanced/nested_defaults_list/conf/server/db/mysql.yaml @@ -0,0 +1 @@ +name: mysql diff --git a/examples/advanced/nested_defaults_list/conf/server/db/sqlite.yaml b/examples/advanced/nested_defaults_list/conf/server/db/sqlite.yaml new file mode 100644 index 0000000000..0e179b7c33 --- /dev/null +++ b/examples/advanced/nested_defaults_list/conf/server/db/sqlite.yaml @@ -0,0 +1 @@ +name: sqlite diff --git a/examples/advanced/nested_defaults_list/my_app.py b/examples/advanced/nested_defaults_list/my_app.py new file mode 100644 index 0000000000..6b1303d511 --- /dev/null +++ b/examples/advanced/nested_defaults_list/my_app.py @@ -0,0 +1,13 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +from omegaconf import DictConfig, OmegaConf + +import hydra + + +@hydra.main(config_path="conf", config_name="config") +def my_app(cfg: DictConfig) -> None: + print(OmegaConf.to_yaml(cfg)) + + +if __name__ == "__main__": + my_app() diff --git a/examples/patterns/configuring_experiments/conf/config.yaml b/examples/patterns/configuring_experiments/conf/config.yaml new file mode 100644 index 0000000000..9554ce5822 --- /dev/null +++ b/examples/patterns/configuring_experiments/conf/config.yaml @@ -0,0 +1,3 @@ +defaults: + - db: mysql + - server: apache diff --git a/examples/patterns/configuring_experiments/conf/db/mysql.yaml b/examples/patterns/configuring_experiments/conf/db/mysql.yaml new file mode 100644 index 0000000000..2fff82707d --- /dev/null +++ b/examples/patterns/configuring_experiments/conf/db/mysql.yaml @@ -0,0 +1 @@ +name: mysql diff --git a/examples/patterns/configuring_experiments/conf/db/sqlite.yaml b/examples/patterns/configuring_experiments/conf/db/sqlite.yaml new file mode 100644 index 0000000000..0e179b7c33 --- /dev/null +++ b/examples/patterns/configuring_experiments/conf/db/sqlite.yaml @@ -0,0 +1 @@ +name: sqlite diff --git a/examples/patterns/configuring_experiments/conf/experiment/aplite.yaml b/examples/patterns/configuring_experiments/conf/experiment/aplite.yaml new file mode 100644 index 0000000000..b88c77aa61 --- /dev/null +++ b/examples/patterns/configuring_experiments/conf/experiment/aplite.yaml @@ -0,0 +1,7 @@ +# @package _global_ +defaults: + - override /db: sqlite + + +server: + port: 8080 diff --git a/examples/patterns/configuring_experiments/conf/experiment/nglite.yaml b/examples/patterns/configuring_experiments/conf/experiment/nglite.yaml new file mode 100644 index 0000000000..8223b3e50d --- /dev/null +++ b/examples/patterns/configuring_experiments/conf/experiment/nglite.yaml @@ -0,0 +1,7 @@ +# @package _global_ +defaults: + - override /server: nginx + - override /db: sqlite + +server: + port: 8080 diff --git a/examples/patterns/configuring_experiments/conf/server/apache.yaml b/examples/patterns/configuring_experiments/conf/server/apache.yaml new file mode 100644 index 0000000000..b426ebcff7 --- /dev/null +++ b/examples/patterns/configuring_experiments/conf/server/apache.yaml @@ -0,0 +1,2 @@ +name: apache +port: 80 diff --git a/examples/patterns/configuring_experiments/conf/server/nginx.yaml b/examples/patterns/configuring_experiments/conf/server/nginx.yaml new file mode 100644 index 0000000000..eb7a8b4fe1 --- /dev/null +++ b/examples/patterns/configuring_experiments/conf/server/nginx.yaml @@ -0,0 +1,2 @@ +name: nginx +port: 80 diff --git a/examples/patterns/configuring_experiments/my_app.py b/examples/patterns/configuring_experiments/my_app.py new file mode 100644 index 0000000000..6b1303d511 --- /dev/null +++ b/examples/patterns/configuring_experiments/my_app.py @@ -0,0 +1,13 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +from omegaconf import DictConfig, OmegaConf + +import hydra + + +@hydra.main(config_path="conf", config_name="config") +def my_app(cfg: DictConfig) -> None: + print(OmegaConf.to_yaml(cfg)) + + +if __name__ == "__main__": + my_app() diff --git a/examples/patterns/extending_configs/conf/config.yaml b/examples/patterns/extending_configs/conf/config.yaml new file mode 100644 index 0000000000..65138088ca --- /dev/null +++ b/examples/patterns/extending_configs/conf/config.yaml @@ -0,0 +1,2 @@ +defaults: + - db: ??? diff --git a/examples/patterns/extending_configs/conf/db/base_mysql.yaml b/examples/patterns/extending_configs/conf/db/base_mysql.yaml new file mode 100644 index 0000000000..1ba5cc849a --- /dev/null +++ b/examples/patterns/extending_configs/conf/db/base_mysql.yaml @@ -0,0 +1,4 @@ +host: localhost +port: 3306 +user: ??? +password: ??? diff --git a/examples/patterns/extending_configs/conf/db/mysql_extending_from_another_group.yaml b/examples/patterns/extending_configs/conf/db/mysql_extending_from_another_group.yaml new file mode 100644 index 0000000000..bfb2e03656 --- /dev/null +++ b/examples/patterns/extending_configs/conf/db/mysql_extending_from_another_group.yaml @@ -0,0 +1,7 @@ +defaults: + - /db_schema/base_mysql@_here_ + +user: omry +password: secret +port: 3307 +encoding: utf8 diff --git a/examples/patterns/extending_configs/conf/db/mysql_extending_from_this_group.yaml b/examples/patterns/extending_configs/conf/db/mysql_extending_from_this_group.yaml new file mode 100644 index 0000000000..5b3fea4e6f --- /dev/null +++ b/examples/patterns/extending_configs/conf/db/mysql_extending_from_this_group.yaml @@ -0,0 +1,7 @@ +defaults: + - base_mysql + +user: omry +password: secret +port: 3307 +encoding: utf8 diff --git a/examples/patterns/extending_configs/conf/db_schema/base_mysql.yaml b/examples/patterns/extending_configs/conf/db_schema/base_mysql.yaml new file mode 100644 index 0000000000..1ba5cc849a --- /dev/null +++ b/examples/patterns/extending_configs/conf/db_schema/base_mysql.yaml @@ -0,0 +1,4 @@ +host: localhost +port: 3306 +user: ??? +password: ??? diff --git a/examples/patterns/extending_configs/my_app.py b/examples/patterns/extending_configs/my_app.py new file mode 100644 index 0000000000..6b1303d511 --- /dev/null +++ b/examples/patterns/extending_configs/my_app.py @@ -0,0 +1,13 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +from omegaconf import DictConfig, OmegaConf + +import hydra + + +@hydra.main(config_path="conf", config_name="config") +def my_app(cfg: DictConfig) -> None: + print(OmegaConf.to_yaml(cfg)) + + +if __name__ == "__main__": + my_app() diff --git a/hydra/_internal/defaults_list.py b/hydra/_internal/defaults_list.py index 8009908280..418c447159 100644 --- a/hydra/_internal/defaults_list.py +++ b/hydra/_internal/defaults_list.py @@ -383,7 +383,7 @@ def _update_overrides( if legacy_hydra_override: # DEPRECATED: remove in 1.2 d.override = True - url = "https://hydra.cc/docs/next/upgrades/1.0_to_1.1/default_list_override" + url = "https://hydra.cc/docs/next/upgrades/1.0_to_1.1/defaults_list_override" msg = dedent( f"""\ In {parent.get_config_path()}: Invalid overriding of {d.group}: diff --git a/hydra/conf/__init__.py b/hydra/conf/__init__.py index af18aad6bb..5d4e2365c9 100644 --- a/hydra/conf/__init__.py +++ b/hydra/conf/__init__.py @@ -6,23 +6,6 @@ from hydra.core.config_store import ConfigStore -hydra_defaults = [ - # Hydra's logging config - {"hydra/hydra_logging": "default"}, - # Job's logging config - {"hydra/job_logging": "default"}, - # Launcher config - {"hydra/launcher": "basic"}, - # Sweeper config - {"hydra/sweeper": "basic"}, - # Output directory - {"hydra/output": "default"}, - # --help template - {"hydra/help": "default"}, - # --hydra-help template - {"hydra/hydra_help": "default"}, -] - @dataclass class HelpConf: @@ -106,8 +89,17 @@ class RuntimeConf: @dataclass class HydraConf: - - defaults: List[Any] = field(default_factory=lambda: hydra_defaults.copy()) + defaults: List[Any] = field( + default_factory=lambda: [ + {"output": "default"}, + {"launcher": "basic"}, + {"sweeper": "basic"}, + {"help": "default"}, + {"hydra_help": "default"}, + {"hydra_logging": "default"}, + {"job_logging": "default"}, + ] + ) # Normal run output configuration run: RunDir = RunDir() @@ -152,7 +144,7 @@ class HydraConf: # Typical command lines to manipulate hydra.verbose: # hydra.verbose=true # hydra.verbose=[hydra,__main__] - # TODO: good use case for Union support in OmegaConf + # TODO: good use ca se for Union support in OmegaConf verbose: Any = False # Composition choices dictionary @@ -171,16 +163,6 @@ class HydraConf: cs.store( group="hydra", name="config", - node=HydraConf( - defaults=[ - {"hydra_logging": "default"}, - {"job_logging": "default"}, - {"launcher": "basic"}, - {"sweeper": "basic"}, - {"output": "default"}, - {"help": "default"}, - {"hydra_help": "default"}, - ] - ), + node=HydraConf(), provider="hydra", ) diff --git a/plugins/hydra_ray_launcher/tests/test_ray_launcher.py b/plugins/hydra_ray_launcher/tests/test_ray_launcher.py index c525675e37..60ac7beea7 100644 --- a/plugins/hydra_ray_launcher/tests/test_ray_launcher.py +++ b/plugins/hydra_ray_launcher/tests/test_ray_launcher.py @@ -1,4 +1,4 @@ -# # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved import sys import pytest diff --git a/tests/defaults_list/test_defaults_tree.py b/tests/defaults_list/test_defaults_tree.py index c376c3ff4f..95793e7f48 100644 --- a/tests/defaults_list/test_defaults_tree.py +++ b/tests/defaults_list/test_defaults_tree.py @@ -752,7 +752,7 @@ def test_legacy_hydra_overrides_from_primary_config( """\ Invalid overriding of hydra/help: Default list overrides requires 'override' keyword. - See https://hydra.cc/docs/next/upgrades/1.0_to_1.1/default_list_override for more information.""" + See https://hydra.cc/docs/next/upgrades/1.0_to_1.1/defaults_list_override for more information.""" ) with warns(expected_warning=UserWarning, match=re.escape(msg)): _test_defaults_tree_impl( diff --git a/tests/test_config_loader.py b/tests/test_config_loader.py index c194a0d4e2..a650fb8e30 100644 --- a/tests/test_config_loader.py +++ b/tests/test_config_loader.py @@ -44,15 +44,8 @@ class TopLevelConfig: hydra_load_list: List[LoadTrace] = [ LoadTrace( - config_path="hydra/hydra_logging/default", - package="hydra.hydra_logging", - parent="hydra/config", - search_path="pkg://hydra.conf", - provider="hydra", - ), - LoadTrace( - config_path="hydra/job_logging/default", - package="hydra.job_logging", + config_path="hydra/output/default", + package="hydra", parent="hydra/config", search_path="pkg://hydra.conf", provider="hydra", @@ -72,22 +65,29 @@ class TopLevelConfig: provider="hydra", ), LoadTrace( - config_path="hydra/output/default", - package="hydra", + config_path="hydra/help/default", + package="hydra.help", parent="hydra/config", search_path="pkg://hydra.conf", provider="hydra", ), LoadTrace( - config_path="hydra/help/default", - package="hydra.help", + config_path="hydra/hydra_help/default", + package="hydra.hydra_help", parent="hydra/config", search_path="pkg://hydra.conf", provider="hydra", ), LoadTrace( - config_path="hydra/hydra_help/default", - package="hydra.hydra_help", + config_path="hydra/hydra_logging/default", + package="hydra.hydra_logging", + parent="hydra/config", + search_path="pkg://hydra.conf", + provider="hydra", + ), + LoadTrace( + config_path="hydra/job_logging/default", + package="hydra.job_logging", parent="hydra/config", search_path="pkg://hydra.conf", provider="hydra", @@ -600,15 +600,8 @@ def test_override_hydra_config_group_from_config_file() -> None: ) expected = [ LoadTrace( - config_path="hydra/hydra_logging/hydra_debug", - package="hydra.hydra_logging", - parent="hydra/config", - search_path="pkg://hydra.conf", - provider="hydra", - ), - LoadTrace( - config_path="hydra/job_logging/disabled", - package="hydra.job_logging", + config_path="hydra/output/default", + package="hydra", parent="hydra/config", search_path="pkg://hydra.conf", provider="hydra", @@ -628,22 +621,29 @@ def test_override_hydra_config_group_from_config_file() -> None: provider="hydra", ), LoadTrace( - config_path="hydra/output/default", - package="hydra", + config_path="hydra/help/default", + package="hydra.help", parent="hydra/config", search_path="pkg://hydra.conf", provider="hydra", ), LoadTrace( - config_path="hydra/help/default", - package="hydra.help", + config_path="hydra/hydra_help/default", + package="hydra.hydra_help", parent="hydra/config", search_path="pkg://hydra.conf", provider="hydra", ), LoadTrace( - config_path="hydra/hydra_help/default", - package="hydra.hydra_help", + config_path="hydra/hydra_logging/hydra_debug", + package="hydra.hydra_logging", + parent="hydra/config", + search_path="pkg://hydra.conf", + provider="hydra", + ), + LoadTrace( + config_path="hydra/job_logging/disabled", + package="hydra.job_logging", parent="hydra/config", search_path="pkg://hydra.conf", provider="hydra", diff --git a/tests/test_examples/test_patterns.py b/tests/test_examples/test_patterns.py index 2166d34846..004670abb3 100644 --- a/tests/test_examples/test_patterns.py +++ b/tests/test_examples/test_patterns.py @@ -1,11 +1,16 @@ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +from pathlib import Path from textwrap import dedent -from typing import Any +from typing import Any, List + +from omegaconf import OmegaConf +from pytest import mark, param from hydra.test_utils.test_utils import ( TTaskRunner, assert_text_same, chdir_hydra_root, + get_run_output, run_with_error, verify_dir_outputs, ) @@ -51,3 +56,56 @@ def test_write_protect_config_node(tmpdir: Any) -> None: ) err = run_with_error(cmd) assert_text_same(from_line=expected, to_line=err) + + +@mark.parametrize( # type: ignore + "overrides", + [ + param(["db=mysql_extending_from_this_group"], id="from_same_group"), + param(["db=mysql_extending_from_another_group"], id="from_different_group"), + ], +) +def test_extending_configs( + monkeypatch: Any, tmpdir: Path, overrides: List[str] +) -> None: + monkeypatch.chdir("examples/patterns/extending_configs") + cmd = ["my_app.py", "hydra.run.dir=" + str(tmpdir)] + overrides + result, _err = get_run_output(cmd) + assert OmegaConf.create(result) == { + "db": { + "host": "localhost", + "port": 3307, + "user": "omry", + "password": "secret", + "encoding": "utf8", + } + } + + +@mark.parametrize( # type: ignore + ("overrides", "expected"), + [ + param( + [], + {"db": {"name": "mysql"}, "server": {"name": "apache", "port": 80}}, + id="default", + ), + param( + ["+experiment=nglite"], + {"db": {"name": "sqlite"}, "server": {"name": "nginx", "port": 8080}}, + id="exp1", + ), + param( + ["+experiment=nglite", "server=apache"], + {"db": {"name": "sqlite"}, "server": {"name": "apache", "port": 8080}}, + id="exp1+override", + ), + ], +) +def test_configuring_experiments( + monkeypatch: Any, tmpdir: Path, overrides: List[str], expected: Any +) -> None: + monkeypatch.chdir("examples/patterns/configuring_experiments") + cmd = ["my_app.py", "hydra.run.dir=" + str(tmpdir)] + overrides + result, _err = get_run_output(cmd) + assert OmegaConf.create(result) == expected diff --git a/website/docs/advanced/defaults_list.md b/website/docs/advanced/defaults_list.md index ba67d274a7..08474bdca1 100644 --- a/website/docs/advanced/defaults_list.md +++ b/website/docs/advanced/defaults_list.md @@ -6,217 +6,294 @@ title: The Defaults List ## Introduction :::important -Many of the features described in this page are new to Hydra 1.1 and are considered experimental. -Please report any issues. +Many of the features described in this page are new. Please report any issues. ::: -A Defaults List determines how to build a config object from other configs, and in what order. -Each config can have a Defaults List as a top level element. The Defaults List itself is not a part of resulting config. +The Defaults List is a list in an input config that instructs Hydra how to build the output config. +Each input config can have a Defaults List as a top level element. The Defaults List itself +is not a part of output config. -The most common items in the Default List are Config Group Defaults, which determines which config group option -to use from a particular config group. - -```yaml +```text title="Defaults List YAML syntax" defaults: - - db: mysql # use mysql as the choice for the db config group -``` + (- CONFIG|GROUP_DEFAULT)* -Sometimes a config file should be loaded unconditionally. Such configs can be specified as a string in the -Defaults List: -```yaml -defaults: - - db/mysql # use db/mysql.yaml unconditionally +CONFIG : (CONFIG_GROUP/)?CONFIG_NAME(@PACKAGE)? +GROUP_DEFAULT : [optional|override]? CONFIG_GROUP(@PACKAGE)?: OPTION +OPTION : CONFIG_NAME|null ``` -Config files loaded this way are not a part of a config group and will always be loaded. -They cannot be overridden. In general it is recommended to use the first form (config group default) when possible. -## Defaults list resolution -When composing the [Output Config Object](/terminology.md#output-config-object), Hydra will first create the final Defaults List and will then compose the -config with it. +*CONFIG* : A config to use when creating the output config. e.g. `db/mysql`, `db/mysql@backup`. -Creating the final defaults list is a complex process: Configs mentioned in the list may have -their own defaults list, sometimes defining the same config groups! +*GROUP_DEFAULT* : An *overridable* config. e.g. `db: mysql`, `db@backup: mysql`. +- ***override*** : Overrides the option of a previously defined GROUP_DEFAULT. +- ***optional*** : By default, an OPTION that do not exist causes an error; optional suppresses the error. +- ***null*** : A place-holder for a future override. If it is not overridden the entry is ignored. -The behavior that process is implementing can be described by two simple rules: -1. The last appearance of a config group determines the final value for that group -2. First appearance of a config group determines the composition order for that group +*CONFIG_NAME*: The name of a config, without the file system extension. e.g. `mysql` and not `mysql.yaml`. -The first rule allows you to always override a config group selection that was made earlier. -The second rules ensures that composition order is respected. +*CONFIG_GROUP* : A path to a set of OPTIONS. +The path is relative to the containing config. +It can be made absolute by prefixing it with a `/`. +The path separator is `/` regardless of the operating system. -## Composition order and `_self_` -A config can contain both a Defaults List and config nodes. +*OPTION*: The currently selected *CONFIG_NAME* from a *CONFIG_GROUP*. -The special element `_self_` can be added to determine the composition order of this config relative to the items -in the defaults list. +*PACKAGE* : Where to place the content of the config within the output config. +It is relative to the Package of the containing config by default. See [Packages](overriding_packages.md). -If `_self_` is not specified, it is implicitly inserted at the top of the defaults list. -This means that by default, elements in the defaults list are composed **after** the config declaring the Defaults List. +## An example +```text title="Config directory structure" +├── server +│ ├── db +│ │ ├── mysql.yaml +│ │ └── sqlite.yaml +│ └── apache.yaml +└── config.yaml +``` +Input configs:
-
+
-```yaml title="Input without _self_" +```yaml title="config.yaml" defaults: - - foo: bar + - server/apache -``` -
+debug: false -
-```yaml title="Is equivalent to" -defaults: - - _self_ - - foo: bar -``` -
+```
-An example with two config files: +
-
-
- -```yaml title="config.yaml" +```yaml title="server/apache.yaml" defaults: - - _self_ - - db: mysql -``` + - db: mysql + +name: apache -
-
-```yaml title="db/mysql.yaml" -defaults: - - mysql/engine: innodb - - _self_ ```
-
+
-When composing `config.yaml`, the resulting defaults list will be: -```yaml -defaults: - - config # per defaults list in config.yaml, it comes first (_self_) - - mysql/engine/innodb # first per defaults list in db/mysql - - db/mysql # second per defaults list in db/mysql (_self_) +```yaml title="server/db/mysql.yaml" +name: mysql ``` -The last two items are added as a result of the expansion of `db/mysql.yaml`. - -## Interpolation -The Defaults List supports a limited form of interpolation that differs from the normal interpolation in several aspects. -- The Defaults List is resolved before the config is computed, so it cannot refer to nodes from the computed config. -- The defaults list can interpolate with config groups directly - -```yaml -defaults: - - dataset: imagenet - - model: alexnet - - optional dataset_model: ${dataset}_{model} # will become imagenet_alexnet +```yaml title="server/db/sqlite.yaml" +name: sqlite +``` +
+ +Output config: +```yaml title="$ python my_app.py" +server: + db: + name: mysql + name: apache +debug: false ``` -See [Specializing Configs](/patterns/specializing_config.md) for a more detailed explanation of this example. +## Overriding Config Group options +A Config Group's option can be overridden using a new *GROUP_DEFAULT* with the ***override*** keyword. +If a Group Default is overridden more than once, the last one, in depth first order, wins. + +Extending the previous example: -## Renaming packages -Packages of previously defined config groups can be overridden by later items in the Defaults List. -The syntax is similar to that described in [Basic Override syntax](/advanced/override_grammar/basic.md#modifying-the-defaults-list), -
-```yaml title="Moving to package src" +```yaml title="config.yaml" {3} defaults: - - db: mysql - - 'db@:src': _keep_ + - server/apache + - override server/db: sqlite + +debug: false ``` +
+
-```yaml title="Renaming package from src to dst" -defaults: - - db@src: mysql - - 'db@src:dst': _keep_ +```yaml title="$ python my_app.py" {2,3} +server: + db: + name: sqlite + name: apache +debug: false ``` +
+
-```yaml title="Renaming package and changing choice" -defaults: - - db: mysql - - 'db@:src': postgresql +A Config Group's option can also be overridden via the command line. e.g: +``` +$ python my_app.py server/db=sqlite ``` -
+:::note +TODO: +- link command line overrides to a relevant page if and when we have it +- consider adding a simple example of overriding a config group with a package override +::: -
+## Composition order +The Defaults List is ordered: +- If multiple configs define the same value, the last one wins. +- If multiple configs contribute to the same dictionary, the result is the combined dictionary. -```yaml title="Result" -defaults: - - db@src: mysql +By default, the content of a config is overriding the content of configs in the defaults list. -``` +
+
-```yaml title="Result" +```yaml title="config.yaml" {5} defaults: - - db@dst: mysql + - db: mysql +db: + host: backup ``` -```yaml title="Result" -defaults: - - db@dst: postgresql +
-``` +
+ +```yaml title="Result: db.host from config" {3} +db: + driver: mysql # db/mysql.yaml + host: backup # config.yaml + port: 3306 # db/mysql.yaml +```
+The `_self_` entry determines the relative position of **this** config in the Defaults List. +If it is not specified, it is added automatically as the last item. -## Deleting from the defaults list -Previously defined config groups can be deleted by later items in the Defaults List. -The syntax is similar to that described in [Basic Override syntax](/advanced/override_grammar/basic.md#modifying-the-defaults-list), +
+
-```yaml +```yaml title="config.yaml" {2,6} defaults: - - db: mysql - - ~db # will delete `db` from the list regardless of the choice -``` + - _self_ + - db: mysql # Overrides this config -```yaml -defaults: - - db: mysql - - ~db: mysql # will delete db from the list if the selected value is mysql +db: + host: backup ``` +
+
+```yaml title="Result: All values from db/mysql" {3} +db: + driver: mysql # db/mysql.yaml + host: localhost # db/mysql.yaml + port: 3306 # db/mysql.yaml -## Config "Inheritance" via composition +``` +
+
-TODO: should probably not be here +With `_self_` at the top of the Defaults List, the host field defined in *config.yaml* now precedes the host field defined +in *db/mysql.yaml*, and as a result is overridden. -A common pattern is to "extend" a base config: -```yaml title="agent.yaml" -name: ??? -age: ??? -agency: mi6 -``` +## Interpolation in the Defaults List -```yaml title="bond.yaml" +Config Group Options can be selected using interpolation. +```yaml defaults: - - agent - - _self_ - -name: Bond, James Bond -age: 7 + - server: apache + - db: mysql + - combination_specific_config: ${server}_${db} # apache_mysql +``` +Interpolation keys can be config groups with any @package overrides. +For example: `${db/engine}`, `${db@backup}` + +The selected option for *combination_specific_config* depends on the final selected options for *db* and *server*. +e.g. If *db* is overridden to *sqlite*, *combination_specific_config* will become *apache_sqlite*. + +#### Restrictions: + + - Defaults List interpolation is only supported in the primary config. + - The subtree expanded by an Interpolated Config may not contain overrides. + - Interpolation Keys in the Defaults List cannot reference values in the Final Config Object (it does not yet). + +See [Patterns/Specializing Configs](/patterns/specializing_config.md) for more information. + +## Debugging the Defaults List +Hydra's config composition process is as follows: + + - The Defaults Tree is created. + - The Final Defaults List is created via a DFS walk of the Defaults Tree. + - The Output Config is composed from the entries in the Final Defaults List. + +You can inspect these artifacts via command line flags: + +- `--info defaults-tree` shows the Defaults Tree. +- `--info defaults` Shows the Final Defaults List. +- `--cfg job|hydra|all` Shows the Output Config. + +Example outputs: +
python my_app.py --info defaults-tree + +```yaml title="" +: + hydra/config: + hydra/hydra_logging: default + hydra/job_logging: default + hydra/launcher: basic + hydra/sweeper: basic + hydra/output: default + hydra/help: default + hydra/hydra_help: default + _self_ + config: + server/apache: + server/db: mysql + _self_ + _self_ ``` +
+
python my_app.py --info defaults + +```text +Defaults List +************* +| Config path | Package | _self_ | Parent | +------------------------------------------------------------------------------- +| hydra/hydra_logging/default | hydra.hydra_logging | False | hydra/config | +| hydra/job_logging/default | hydra.job_logging | False | hydra/config | +| hydra/launcher/basic | hydra.launcher | False | hydra/config | +| hydra/sweeper/basic | hydra.sweeper | False | hydra/config | +| hydra/output/default | hydra | False | hydra/config | +| hydra/help/default | hydra.help | False | hydra/config | +| hydra/hydra_help/default | hydra.hydra_help | False | hydra/config | +| hydra/config | hydra | True | | +| server/db/mysql | server.db | False | server/apache | +| server/apache | server | True | config | +| config | | True | | +------------------------------------------------------------------------------- +``` +
+
python my_app.py --cfg job -In the above example, `bond.yaml` is overriding the name and age in `base.yaml` -The resulting config will thus be: ```yaml -name: Bond, James Bond -age: 7 -agency: mi6 +server: + db: + name: mysql + name: apache +debug: false ``` +
+ +## Related topics +- [Packages](overriding_packages.md) +- [Common Patterns/Extending Configs](patterns/extending_configs.md) +- [Common Patterns/Configuring Experiments](patterns/configuring_experiments.md) diff --git a/website/docs/advanced/overriding_packages.md b/website/docs/advanced/overriding_packages.md index bfa87e7015..0e3f434e71 100644 --- a/website/docs/advanced/overriding_packages.md +++ b/website/docs/advanced/overriding_packages.md @@ -1,124 +1,177 @@ --- id: overriding_packages -title: Overriding packages +title: Packages --- -[![Example application](https://img.shields.io/badge/-Example%20application-informational)](https://github.com/facebookresearch/hydra/tree/master/examples/advanced/package_overrides) +The package determines where the content of each input config is placed in the output config. +The default package of an input config is derived from its Config Group. e.g. The default package of `server.db/mysql.yaml` is `server.db`. -The contents of a config file can be relocated, or replicated, within the config, via package overrides. +The default package can be overridden [in the Defaults List](#overriding-packages-using-the-defaults-list) +or via a [Package Directive](#overriding-the-package-via-the-package-directive) at the top of the config file. +Changing the package of a config can be useful when using a config from another library, or when using the same +config group twice in the same app. -### Package specification +The priority for determining the final package for a config is as follows: +1. The package specified in the Defaults List (relative to the package of the including config) +2. The package specified in the Package Directive (absolute) +3. The default package -``` text title="Definition of a package" -PACKAGE : _global_ | COMPONENT[.COMPONENT]* -COMPONENT : _group_ | _name_ | \w+ +We will use the following configs in the examples below: +
+
-_global_ : the top level package (equivalent to the empty string). -_group_ : the config group in dot notation: foo/bar/zoo.yaml -> foo.bar -_name_ : the config file name: foo/bar/zoo.yaml -> zoo -``` +```yaml title="config.yaml" +defaults: + - server/apache + +debug: false -### Overriding the package in a file via a package directive -A `@package directive` specifies a common [package](/terminology.md#package) for all nodes in the config file. -It must be placed at the top of each `config group file`. -```text title="Package directive examples" -# @package foo.bar -# @package _global_ -# @package _group_ -# @package _group_._name_ -# @package foo._group_._name_ ``` -#### Examples -##### A package directive with a literal -
-
+
-```yaml title="mysql.yaml" {1-2} -# @package foo.bar +
-db: - host: localhost - port: 3306 -``` +```yaml title="server/apache.yaml" +defaults: + - db: mysql -
+name: apache -
-```yaml title="Interpretation" {1-2} -foo: - bar: - db: - host: localhost - port: 3306 -``` +```
-
+
+ +```yaml title="server/db/mysql.yaml" +name: mysql +``` + +```yaml title="server/db/sqlite.yaml" +name: sqlite +``` +
+ +```text title="Config directory structure" +├── server +│ ├── db +│ │ ├── mysql.yaml +│ │ └── sqlite.yaml +│ └── apache.yaml +└── config.yaml +``` -##### A package directive with `_group_` and `_name_` +### An example using only default packages +The default package of *config.yaml* is the global package, of *server/apache.yaml* is *server* and of *server/db/mysql.yaml* is *server.db*.
-```yaml title="db/mysql.yaml" {1-2} -# @package _group_._name_ +```yaml title="$ python my_app.py" {1-2} +server: + db: + name: mysql + name: apache +debug: false +``` +
+ +### Overriding packages using the Defaults List +By default, packages specified in the Defaults List are relative to the package of containing config. +As a consequence, overriding a package relocates the entire subtree. + +
+
+ +```yaml title="config.yaml" {2} +defaults: + - server/apache@admin + +debug: false -host: localhost -port: 3306 ``` -
+
+
+ +```yaml title="server/apache.yaml" {2} +defaults: + - db@backup: mysql + +name: apache -```yaml title="Interpretation" {1-2} -db: - mysql: - host: localhost - port: 3306 -``` +``` +
+
+ +```yaml title="Output config" {1-4} +admin: + backup: + name: mysql + name: apache +debug: false +```
-### Overriding the package via the defaults list -The following example adds the `mysql` config in the packages `db.src` and `db.dst`. +Note that content of *server/apache.yaml* is relocated to *admin* +and the content of *server/db/mysql.yaml* to *admin.backup*. + +#### Default List package keywords +We will use this example, replacing *<@PACKAGE>* to demonstrate different cases: +```yaml title="config_group/config.yaml" +defaults: + - /server/db<@PACKAGE>: mysql +``` + +Without a package override, the resulting package is `config_group.server.db`. +##### Relative keywords: +* **@\_here\_**: The resulting package is the same as the containing config (`config_group`). +* **@\_name\_**: \_name\_ is substituted by the name of the config. The resulting package is `config_group.mysql`. +##### Absolute keywords: +* **@\_group\_**: \_group\_ is the absolute default package of the config (`server.db`)* +* **@\_global\_**: The global package. Anything following \_global\_ is absolute. + e.g. **@\_global\_.foo** becomes `foo`. +### Overriding the package via the package directive + +The @package directive changes the package of a config file. The package specified by a @package directive is always absolute. + +```yaml title="server/db/mysql.yaml" {1} +# @package foo.bar +name: mysql +``` + +To change the package to the global (empty) package, use the keyword `_global_`. + +### Using a config group more than once +The following example adds the `db/server/mysql` config in the packages `src` and `dst`.
```yaml title="config.yaml" defaults: - - db@db.src: mysql - - db@db.dst: mysql - - - + - server/db@src: mysql + - server/db@dst: mysql ```
-```yaml title="Interpretation" -db: - src: - host: localhost - port: 3306 - dst: - host: localhost - port: 3306 +```yaml title="$ python my_app.py" +src: + name: mysql +dst: + name: mysql ```
- -### History and future of the package directive -The primary config, named in `@hydra.main()` should not have a package directive. - -For config files in config groups the default depends on the version: - - In **Hydra 0.11**, there was an implicit default of `_global_` - - **Hydra 1.0** the default is `_global_` - A warning is issued for each **config group file** without a `@package` directive. - - In **Hydra 1.1** the default for **config group files** will become `_group_` - -By adding an explicit `@package` to your configs files, you guarantee that they -will not break when you upgrade to Hydra 1.1. +When overriding config groups with a non-default package, the package must be used: +```yaml title="$ python my_app.py server/db@src=sqlite" +src: + name: sqlite +dst: + name: mysql +``` diff --git a/website/docs/configure_hydra/Intro.md b/website/docs/configure_hydra/Intro.md index e87a317d7d..eb6769d2b4 100644 --- a/website/docs/configure_hydra/Intro.md +++ b/website/docs/configure_hydra/Intro.md @@ -21,50 +21,64 @@ your function to reduce confusion. You can view the configuration with `--cfg hydra|job|all` The Hydra configuration itself is composed from multiple config files. here is a partial list: -```yaml +```yaml title="hydra/config" defaults: - - hydra/job_logging : default # Job's logging config - - hydra/launcher: basic # Launcher config - - hydra/sweeper: basic # Sweeper config - - hydra/output: default # Output directory + - job_logging : default # Job's logging config + - launcher: basic # Launcher config + - sweeper: basic # Sweeper config + - output: default # Output directory ``` You can view the Hydra config structure [here](https://github.com/facebookresearch/hydra/tree/master/hydra/conf). -This is a subset of the composed Hydra configuration node: - -```yaml +You can view the Hydra config using `--cfg hydra`: +```yaml title="$ python my_app.py --cfg hydra" hydra: run: - # Output directory for normal runs - dir: ./outputs/${now:%Y-%m-%d_%H-%M-%S} + dir: outputs/${now:%Y-%m-%d}/${now:%H-%M-%S} sweep: - # Output directory for sweep runs - dir: /checkpoint/${env:USER}/outputs/${now:%Y-%m-%d_%H-%M-%S} - # Output sub directory for sweep runs. - subdir: ${hydra.job.num}_${hydra.job.id} + dir: multirun/${now:%Y-%m-%d}/${now:%H-%M-%S} + subdir: ${hydra.job.num} + launcher: + _target_: hydra._internal.core_plugins.basic_launcher.BasicLauncher + sweeper: + _target_: hydra._internal.core_plugins.basic_sweeper.BasicSweeper + max_batch_size: null + hydra_logging: + version: 1 + formatters: + ... ``` ## Runtime variables -The `hydra` package is deleted from your config when the function runs to reduce the amount of noise -in the config passed to the function. -You can still access all config nodes in Hydra through the custom resolver `hydra`. +The Hydra config is large. To reduce clutter in your own config it's being deleted from the config object +Hydra is passing to the function annotated by `@hydra.main()`. + +There are two ways to access the Hydra config: -For example: +#### In your config, using the `hydra` resolver: ```yaml -config_name: ${hydra:job.config_name} +config_name: ${hydra:job.name} ``` Pay close attention to the syntax: The resolver name is `hydra`, and the `key` is passed after the colon. -The following variables are some of the variables populated at runtime. -You can see the full Hydra config using `--cfg hydra`: +#### In your code, using the HydraConfig singleton. +```python +from hydra.core.hydra_config import HydraConfig + +@hydra.main() +def my_app(cfg: DictConfig) -> None: + print(HydraConfig.get().job.name) +``` + +The following variables are populated at runtime. -`hydra.job`: +#### hydra.job: - *hydra.job.name* : Job name, defaults to python file name without suffix. can be overridden. - *hydra.job.override_dirname* : Pathname derived from the overrides for this job - *hydra.job.num* : job serial number in sweep - *hydra.job.id* : Job ID in the underlying jobs system (SLURM etc) -`hydra.runtime`: +#### hydra.runtime: - *hydra.runtime.version*: Hydra's version - *hydra.runtime.cwd*: Original working directory the app was executed from diff --git a/website/docs/patterns/configuring_experiments.md b/website/docs/patterns/configuring_experiments.md new file mode 100644 index 0000000000..06bea325cf --- /dev/null +++ b/website/docs/patterns/configuring_experiments.md @@ -0,0 +1,183 @@ +--- +id: configuring_experiments +title: Configuring Experiments +--- +[![Example application](https://img.shields.io/badge/-Example%20application-informational)](https://github.com/facebookresearch/hydra/tree/master/examples/patterns/configuring_experiments) + +### Problem +A common problem is maintaining multiple configurations of an application. This can get especially +tedious when the configuration differences span multiple dimensions. +This pattern shows how to cleanly support multiple configurations, with each configuration file only specifying +the changes to the master (default) configuration. + +### Solution +Create a config file specifying the overrides to the default configuration, and then call it via the command line. +e.g. `$ python my_app.py +experiment=fast_mode`. + +To avoid clutter, we place the experiment config files in dedicated config group called *experiment*. + +### Example +In this example, we will create configurations for each of the server and database pairings that we want to benchmark. + +The default configuration is: + +
+
+ +```yaml title="config.yaml" +defaults: + - db: mysql + - server: apache + + + + + +``` +
+
+ +```yaml title="db/mysql.yaml" +name: sqlite +``` + +```yaml title="server/apache.yaml" +name: apache +port: 80 +``` +
+ + +
+ +```yaml title="db/sqlite.yaml" +name: sqlite +``` + +```yaml title="server/nginx.yaml" +name: nginx +port: 80 +``` +
+
+ + + +
+
+ +```text title="Directory structure" +├── config.yaml +├── db +│ ├── mysql.yaml +│ └── sqlite.yaml +└── server + ├── apache.yaml + └── nginx.yaml +``` +
+
+ +```yaml title="$ python my_app.py" +db: + name: mysql +server: + name: apache + port: 80 + + +``` +
+
+ +The benchmark config files specify the deltas from the default configuration: + +
+
+ +```yaml title="experiment/aplite.yaml" +# @package _global_ +defaults: + - override /db: sqlite + + +server: + port: 8080 +``` +
+
+ +```yaml title="experiment/nglite.yaml" +# @package _global_ +defaults: + - override /db: sqlite + - override /server: nginx + +server: + port: 8080 +``` +
+
+ +
+
+ +```yaml title="$ python my_app.py +experiment=aplite" +db: + name: sqlite +server: + name: apache + port: 8080 +``` +
+
+ +```yaml title="$ python my_app.py +experiment=nglite" +db: + name: sqlite +server: + name: nginx + port: 8080 +``` +
+ +
+ +Key concepts: +* **\# @package \_global\_** + Changes specified in this config should be interpreted as relative to the \_global\_ package. + We could instead place *nglite.yaml* and *aplite.yaml* next to *config.yaml* and omit this line. +* **The overrides of /db and /server are absolute paths.** + This is necessary because they are outside of the experiment directory. + +Running the experiments from the command line requires prefixing the experiment choice with a `+`. +The experiment config group is an addition, not an override. + +### Sweeping over experiments + +This approach also enables sweeping over those experiments to easily compare their results: + +```text title="$ python my_app.py --multirun +experiment=aplite,nglite" +[HYDRA] Launching 2 jobs locally +[HYDRA] #0 : +experiment=aplite +db: + name: sqlite +server: + name: apache + port: 8080 + +[HYDRA] #1 : +experiment=nglite +db: + name: sqlite +server: + name: nginx + port: 8080 +``` + +To run all the experiment, use the [glob](../../advanced/override_grammar/extended#glob-choice-sweep) syntax: +```text title="$ python my_app.py --multirun '+experiment=glob(*)'" +[HYDRA] #0 : +experiment=aplite +... +[HYDRA] #1 : +experiment=nglite +... +``` \ No newline at end of file diff --git a/website/docs/patterns/extending_configs.md b/website/docs/patterns/extending_configs.md new file mode 100644 index 0000000000..97756cefc2 --- /dev/null +++ b/website/docs/patterns/extending_configs.md @@ -0,0 +1,70 @@ +--- +id: extending_configs +title: Extending Configs +--- +[![Example application](https://img.shields.io/badge/-Example%20applications-informational)](https://github.com/facebookresearch/hydra/tree/master/examples/patterns/extending_configs) + +A common pattern is to extend an existing config, overriding and/or adding new config values to it. +The extension is done by including the base configuration, and then overriding the chosen values in the current config. + +#### Extending a config from the same config group: + +
+
+ +```yaml title="config.yaml" +defaults: + - db: mysql + + + + + +``` +
+
+ +```yaml title="db/mysql.yaml" {2} +defaults: + - base_mysql + +user: omry +password: secret +port: 3307 +encoding: utf8 +``` +
+
+ +```yaml title="db/base_mysql.yaml" +host: localhost +port: 3306 +user: ??? +password: ??? + + + +``` +
+
+ +Output: +```yaml title="$ python my_app.py" +db: + host: localhost # from db/base_mysql + port: 3307 # overriden by db/mysql.yaml + user: omry # populated by db/mysql.yaml + password: secret # populated by db/mysql.yaml + encoding: utf8 # added by db/mysql.yaml +``` + +#### Extending a config from another config group: +To extend a config from a different config group, include it using an absolute path (/), and override +the package to `_here_`. + +```yaml title="db/mysql.yaml" {2} +defaults: + - /db_schema/base_mysql@_here_ +``` + +It is otherwise identical to extending a config within the same config group. diff --git a/website/docs/patterns/write_protect_config_node.md b/website/docs/patterns/write_protect_config_node.md index c65dfd63e8..94634da6ac 100644 --- a/website/docs/patterns/write_protect_config_node.md +++ b/website/docs/patterns/write_protect_config_node.md @@ -49,6 +49,6 @@ Cannot change read-only config container diff --git a/website/docs/terminology.md b/website/docs/terminology.md index 05a0a0ce12..aedd68baa0 100644 --- a/website/docs/terminology.md +++ b/website/docs/terminology.md @@ -34,7 +34,7 @@ class User: ### Defaults List -A list in [input Config](#input-configs) that instructs Hydra how to build the config. +A list in an [Input Config](#input-configs) that instructs Hydra how to build the config. The list is typically composed of [Config Group Options](#config-group-option). ```yaml title="Example: config.yaml" defaults: @@ -55,10 +55,14 @@ One of the configs in a Config Group. A Config Node is either a `Value Node` (a primitive type), or a `Container Node`. A `Container Node` is a list or dictionary of `Value Nodes`. ### Package -A Package is the path of the [Config Node](#config-node) in the [Config Object](#output-config-object). +A Package is the path to [Config Node](#config-node) in the [Config Object](#output-config-object). -### Package directive -The [Package Directive](advanced/overriding_packages.md) specifies the root [Package](#package) of an [Config File](#input-configs) +### Package Directive +The [Package Directive](advanced/overriding_packages.md) specifies the root [Package](#package) of a [Config File](#input-configs) + +:::note +TODO: fix +::: ### Example ```yaml title="Input config: mi6/agent/james_bond.yaml" diff --git a/website/docs/upgrades/1.0_to_1.1/changes_to_default_composition_order.md b/website/docs/upgrades/1.0_to_1.1/changes_to_default_composition_order.md new file mode 100644 index 0000000000..63550aaaeb --- /dev/null +++ b/website/docs/upgrades/1.0_to_1.1/changes_to_default_composition_order.md @@ -0,0 +1,97 @@ +--- +id: default_composition_order +title: Changes to default composition order +hide_title: true +--- +Default composition order is changing in Hydra 1.1. + +For this example, let's assume the following two configs: +
+
+ +```yaml title="config.yaml" +defaults: + - foo: bar + +foo: + x: 10 +``` + +
+ +
+ +```yaml title="foo/bar.yaml" +# @package _group_ +x: 20 + + + +``` +
+
+ + +
+
+ +In **Hydra 1.0**, configs from the Defaults List are overriding *config.yaml*, resulting in the following output: +
+
+ +```yaml {2} +foo: + x: 20 +``` +
+
+ + + +
+
+ +As of **Hydra 1.1**, *config.yaml* is overriding configs from the Defaults List, resulting in the following output: +
+
+ +```yaml {2} +foo: + x: 10 +``` +
+
+ + +### Migration +For the majority of applications, this will not cause issues. If your application requires the previous behavior, +you can achieve it by adding `_self_` as the first item in your Defaults List: + + +
+
+ +```yaml title="config.yaml" {2} +defaults: + - _self_ + - foo: bar + +foo: + x: 10 +``` +
+ +
+ +```yaml title="Output config" +foo: + x: 20 + + + + +``` +
+
+ +The Defaults List is described [here](/advanced/defaults_list.md). diff --git a/website/docs/upgrades/1.0_to_1.1/defaults_list_interpolation_changes.md b/website/docs/upgrades/1.0_to_1.1/defaults_list_interpolation_changes.md index 71b82ac775..653b1cc280 100644 --- a/website/docs/upgrades/1.0_to_1.1/defaults_list_interpolation_changes.md +++ b/website/docs/upgrades/1.0_to_1.1/defaults_list_interpolation_changes.md @@ -36,5 +36,8 @@ Note that: - interpolation keys in the defaults list can not access values from the composed config because it does not yet exist when Hydra is processing the defaults list +The Defaults List is described [here](/advanced/defaults_list.md). + :::warning -Support for the old style will be removed in Hydra 1.2. \ No newline at end of file +Support for the old style will be removed in Hydra 1.2. +::: \ No newline at end of file diff --git a/website/docs/upgrades/1.0_to_1.1/defaults_list_override.md b/website/docs/upgrades/1.0_to_1.1/defaults_list_override.md new file mode 100644 index 0000000000..973efe24c0 --- /dev/null +++ b/website/docs/upgrades/1.0_to_1.1/defaults_list_override.md @@ -0,0 +1,23 @@ +--- +id: defaults_list_override +title: Defaults List Overrides +hide_title: true +--- +Hydra versions prior to 1.1 supported overriding of Hydra config groups via the Defaults List in this manner: +```yaml {3} +defaults: + - model: resnet50 + - hydra/launcher: submitit +``` +As of Hydra 1.1, Config group overrides must be marked explicitly with the `override` keyword: +```yaml {3} +defaults: + - model: resnet50 + - override hydra/launcher: submitit +``` + +The Defaults List is described [here](/advanced/defaults_list.md). + +:::warning +Omitting the `override` keyword when overriding Hydra's config groups will result in an error in Hydra 1.2 +::: \ No newline at end of file diff --git a/website/sidebars.js b/website/sidebars.js index a406dd8897..3b298a553f 100755 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -70,6 +70,8 @@ module.exports = { 'patterns/instantiate_objects/structured_config', ] }, + 'patterns/extending_configs', + 'patterns/configuring_experiments', 'patterns/specializing_config', 'patterns/write_protect_config_node', ], @@ -82,7 +84,7 @@ module.exports = { 'configure_hydra/app_help', ], - 'Plugins': [ + 'Available Plugins': [ 'plugins/colorlog', { 'Launchers': [ @@ -138,6 +140,8 @@ module.exports = { type: 'category', label: '1.0 to 1.1', items: [ + 'upgrades/1.0_to_1.1/default_composition_order', + 'upgrades/1.0_to_1.1/defaults_list_override', 'upgrades/1.0_to_1.1/defaults_list_interpolation', ], },