Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Structured configs docs pass #628

Merged
merged 2 commits into from
May 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class MySQLConfig:
@dataclass
class MyConfig:
db: MySQLConfig = MySQLConfig()
verbose: bool = True


cs = ConfigStore.instance()
Expand Down
6 changes: 4 additions & 2 deletions examples/tutorials/structured_configs/4_defaults/my_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from dataclasses import dataclass, field
from typing import Any, List

from omegaconf import DictConfig
from omegaconf import MISSING, DictConfig

import hydra
from hydra.core.config_store import ConfigStore
Expand Down Expand Up @@ -37,7 +37,9 @@ class PostGreSQLConfig:
class Config(DictConfig):
# this is unfortunately verbose due to @dataclass limitations
defaults: List[Any] = field(default_factory=lambda: defaults)
db: MySQLConfig = MySQLConfig()

# Hydra will populate this field based on the defaults list
db: Any = MISSING


cs = ConfigStore.instance()
Expand Down
1 change: 1 addition & 0 deletions news/628.docs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a new tutorial covering Structured Configs
2 changes: 1 addition & 1 deletion requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
omegaconf>=2.0.1rc5
omegaconf>=2.0.1rc6
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ OPTION : .*
# Changing an existing item
GROUP[@SRC_PKG[:DEST_PKG]][=OPTION]

# Adding a new item
# Appending a new item
+GROUP@[SRC_PKG]=OPTION

# Deleting an existing item
Expand All @@ -31,7 +31,7 @@ VALUE : .*
# Changing an existing item
KEY=VALUE

# Adding a new item
# Appending a new item
+KEY=VALUE

# Deleting an existing item
Expand All @@ -40,9 +40,9 @@ KEY=VALUE

# Examples
## Config values
- Override config value : `key=value`
- Add config value : `+key=value`
- Remove config value : `~key`, `~key=value`,
- Overriding a config value : `foo.bar=value`
- Appending a config value : `+foo.bar=value`
- Removing a config value : `~foo.bar`, `~foo.bar=value`

## Defaults list
- Overriding selected Option: `db=mysql`
Expand Down
6 changes: 3 additions & 3 deletions website/docs/tutorials/structured_config/0_intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ id: intro
title: Introduction to Structured Configs
sidebar_label: Introduction to Structured Configs
---
This is an advanced tutorial that assumes that you are comfortable with the concepts introduced in the [Basic Tutorial](/tutorials/basic/1_simple_cli_app.md).
This is an advanced tutorial that assumes that you are comfortable with the concepts introduced in the [Basic Tutorial](/tutorials/basic/your_first_app/1_simple_cli.md).
The examples in this tutorial are available [here](https://github.com/facebookresearch/hydra/tree/master/examples/tutorials/structured_configs).

Structured Configs use Python [dataclasses](https://docs.python.org/3.7/library/dataclasses.html) to
Expand All @@ -14,7 +14,7 @@ describe your configuration structure and types. They enable:

#### Structured Configs supports:
- Primitive types (`int`, `bool`, `float`, `str`, `Enums`)
- Nesting of structured configs
- Nesting of Structured Configs
- Containers (List and Dict) containing primitives or Structured Configs
- Optional fields

Expand All @@ -34,7 +34,7 @@ Structured Configs are a feature of OmegaConf. This tutorial does not assume any
It is recommended that you visit the <a class="external" href="https://omegaconf.readthedocs.io/en/latest/structured_config.html" target="_blank">OmegaConf Structured Configs page</a> to learn more later.

<div class="alert alert--info" role="alert">
1. The APIs and behaviors described in this tutorial are experimental and may change in a future version<br/>
1. The APIs and behaviors described in this tutorial are new and are subject to change<br/>
2. Structured configs are new, please report any issues<br/>
</div>
<br/>
8 changes: 3 additions & 5 deletions website/docs/tutorials/structured_config/1_minimal_example.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ With structured configs, Hydra will catch these and runtime errors that mypy can
A type error in the code:
```
$ python my_app_type_error.py
Traceback (most recent call last):
...
omegaconf.errors.ConfigAttributeError: Key 'pork' not in 'MySQLConfig'
Key 'pork' not in 'MySQLConfig'
full_key: pork
reference_type=Optional[MySQLConfig]
object_type=MySQLConfig
Expand All @@ -64,8 +62,8 @@ omegaconf.errors.ConfigAttributeError: Key 'pork' not in 'MySQLConfig'
A type error in the command line:
```
$ python my_app_type_error.py port=fail
...
omegaconf.errors.ValidationError: Value 'fail' could not be converted to Integer
Error merging override port=fail
Value 'fail' could not be converted to Integer
full_key: port
reference_type=Optional[MySQLConfig]
object_type=MySQLConfig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class MySQLConfig:
@dataclass
class MyConfig:
db: MySQLConfig = MySQLConfig()
verbose: bool = True

cs = ConfigStore.instance()
cs.store(name="config", node=MyConfig)
Expand Down
30 changes: 16 additions & 14 deletions website/docs/tutorials/structured_config/3_config_groups.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
---
id: config_groups
title: Config groups
title: Config Groups
---
Structured Configs support config groups which are similar to file-based config groups.
The config options in config groups can be used as building blocks when composing the output config object.
One difference is that Structured Configs introduce runtime type safety which ensures that the resulting config object
adheres to the declared types.

This example adds `mysql` and `postgresql` configs into the config group `db`.
The config group `db` corresponds to the directory name inside the config directory in config-file based examples.
This example adds `mysql` and `postgresql` configs into the Config Group `db`.
Like with config files, the configs in the `ConfigStore` acts as building blocks to be used when composing the
output config object.

Noteworthy things in the example:
- The two config classes `MySQLConfig` and `PostGreSQLConfig` have no common superclass
- The type of the `db` field in `Config` is `Any`, This means it offers *no* type safety (static or runtime)

A good solution here might have been to use a `Union[MySQLConfig, PostGreSQLConfig]`, but Unions are not currently
supported by Structured Configs, so we use `Any` as a last resort.
The type of variable `db` in the `Config` is `Any`. This allows both `MySQLConfig` and `PostGreSQLConfig`
to be merged into it despite them not having a common superclass.

```python
@dataclass
Expand Down Expand Up @@ -43,7 +44,7 @@ def my_app(cfg: Config) -> None:
```
You can select the database from the command line:
```yaml
$ python my_app.py db=postgresql
$ python my_app.py +db=postgresql
db:
driver: postgresql
host: localhost
Expand All @@ -56,9 +57,10 @@ db:
#### Config inheritance
We can improve on the above example by modeling the configuration with inheritance.
Noteworthy things in the example:
- We can move fields to the top level class, reducing repetition of field names, type and default values
- The type of the `db` field in `Config` is `DBConfig`, this offers static and runtime type safety
- We can use OmegaConf.get_type() to obtain the underlying type, and cast() to coerce the type checker to accept it
- We can move fields to the top level class, reducing repetition of field names, type and default values.
- The type of the `db` field in `Config` is `DBConfig`. This ensures that only subclasses of `DBConfig`
can be merged into db.
- We can use OmegaConf.get_type() to obtain the underlying type, and cast() to coerce the type checker to accept it.

```python
@dataclass
Expand Down Expand Up @@ -107,6 +109,6 @@ def my_app(cfg: Config) -> None:

Example output:
```
$ python my_app_with_inheritance.py db=postgresql
$ python my_app_with_inheritance.py +db=postgresql
Connecting to PostGreSQL: localhost:5432 (timeout=10)
```
20 changes: 12 additions & 8 deletions website/docs/tutorials/structured_config/4_defaults.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ defaults = [
{"database": "mysql"}
]


@dataclass
class Config(DictConfig):
# this is unfortunately verbose due to @dataclass limitations
defaults: List[Any] = field(default_factory=lambda: defaults)
db: MySQLConfig = MySQLConfig()


# Hydra will populate this field based on the defaults list
db: Any = MISSING

cs = ConfigStore.instance()
cs.store(group="db", name="mysql", node=MySQLConfig)
Expand All @@ -43,13 +42,18 @@ def my_app(cfg: Config) -> None:
if __name__ == "__main__":
my_app()
```
As expected, running it loads gives you the mysql config.
Running `my_app.py` loads the mysql config option by default:
```yaml
$ python my_app.py
db:
driver: mysql
host: localhost
password: secret
port: 3306
user: omry
...
```

You can override the default option via the command line:
```yaml
$ python my_app.py db=postgresql
db:
driver: postgresql
...
```
12 changes: 7 additions & 5 deletions website/docs/tutorials/structured_config/5_schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ def my_app(cfg: DictConfig) -> None:
When `db/mysql.yaml` and `db/postgresql.yaml` are loaded, the corresponding configs from the `ConfigStore` are used automatically.
This can be used to validate that both the configuration files (`mysql.yaml` and `postgresql.yaml`) and the command line overrides are conforming to the schema.

```bash
$ python my_app.py db.port=fail
Traceback (most recent call last):
..
omegaconf.errors.ValidationError: Error setting 'db.port = fail' : Value 'fail' could not be converted to Integer
```
$ python my_app.py db.port=fail
Error merging override db.port=fail
Value 'fail' could not be converted to Integer
full_key: db.port
reference_type=Optional[MySQLConfig]
object_type=MySQLConfig
```