# configen

Automatically generates Structured Configs that can be used with hydra.utils.instantiate()

This is optional at two levels:
1. Structured Configs are optional, one can use Hydra without them.
2. One can manually code these dataclasses. The advantage of this tool is that it does the work automatically.

# Setup
Configen requires config file per project. The config indicates what classes to generate code for, where to put
the generated code etc.
Configen will suggest creating a config on the first run:
```
$ configen
[2020-08-14 12:06:11,359][configen.configen][ERROR] -
Use --config-dir DIR --config-name NAME
e.g:
	configen --config-dir conf --config-name configen

If you have no config dir yet use init_config_dir=DIR to create an initial config dir.
e.g:
	configen init_config_dir=conf
```

This will generate a basic config similar to:
```yaml
$ cat conf/configen.yaml
defaults:
  - configen_schema

configen:
  # output directory
  output_dir: ${hydra:runtime.cwd}/example

  header: |
    # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
    # Generated by configen, do not edit.
    # See https://github.com/facebookresearch/hydra/tree/master/tools/configen
    # fmt: off
    # isort:skip_file
    # flake8: noqa

  module_path_pattern: 'config/{{module_path}}.py'

  # list of modules to generate configs for
  modules:
    - name: configen.samples.my_module
      # for each module, a list of classes
      classes:
        - User
        - Admin
```

Configen comes with a few samples [classes](configen/samples) that are being processed by the default config.
For example:
```python title="configen/samples/my_module.py"
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved


class User:
    def __init__(self, age: int, name: str):
        self.age = age
        self.name = name

    def __repr__(self):
        return f"User: name={self.name}, age={self.age}"


class Admin(User):
    def __init__(self, private_key: str, age: int, name: str) -> None:
        super().__init__(age, name)
        self.private_key = private_key

    def __repr__(self):
        return (
            f"Admin: name={self.name}, age={self.age}, private_key={self.private_key}"
        )
```

Running configen with this config directory:
```
$ configen --config-dir conf --config-name configen
[2020-08-14 12:44:54,990][configen.configen][INFO] - configen.samples.my_module.configen.samples.my_module -> /home/omry/tmp/configen/example/config/configen/samples/my_module.py
```

Will result in a file `example/config/configen/samples/my_module.py` like:
```python
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
# Generated by configen, do not edit.
# See https://github.com/facebookresearch/hydra/tree/master/tools/configen
# fmt: off
# isort:skip_file
# flake8: noqa

from dataclasses import dataclass, field
from omegaconf import MISSING


@dataclass
class UserConf:
    _target_: str = "configen.samples.my_module.User"
    age: int = MISSING
    name: str = MISSING


@dataclass
class AdminConf:
    _target_: str = "configen.samples.my_module.Admin"
    private_key: str = MISSING
    age: int = MISSING
    name: str = MISSING
```

The generated code can be used by a Hydra application to instantiate the user object.
See the [example aplication](example/my_app.py).
