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

[Question] Limit possible values of config fields using Literal? #1332

Closed
hoangthienan95 opened this issue Jan 24, 2021 · 1 comment
Closed
Labels
bug Something isn't working

Comments

@hoangthienan95
Copy link

🐛 Bug

Description

Is it possible to limit the possible values of a field in a config yaml file using type hints? I want to limit the values of the STEP_NAME variable in step1.yaml to only 2 values: "extract_info" and "run_ovp"

I tried using the Literal["extract_info", "run_ovp"] type but it threw an error. When the type was str it worked fine

Checklist

  • [ X] I checked on the latest version of Hydra
  • [ X] I created a minimal repro (See this for tips).

To reproduce

** Minimal Code/Config snippet to reproduce **
Directory structure:

├── conf
│   ├── hydra_all_confs
│   │   ├── config.yaml
│   │   └── step
│   │       └── step1.yaml
├── hydra_test_app.py
Content of hydra_test_app.py

import logging
from dataclasses import dataclass
import os
from typing import Literal, Union
from enum import Enum

from omegaconf import DictConfig, OmegaConf, MISSING
import hydra
from hydra.core.config_store import ConfigStore


# A logger for this file
log = logging.getLogger(__name__)


# +
@dataclass
class step1:
    STEP_NAME: Literal["extract_info", "run_ovp", "???"] = MISSING #read this from step1.yaml and limit the step name to 2 possible values

@dataclass
class Config:
    step = MISSING


# -

cs = ConfigStore.instance()

cs.store(name="config", node=Config)
cs.store(group="step", name="step1", node=step1)

@hydra.main(config_path='conf/hydra_all_confs', config_name="config")
def my_app(cfg: DictConfig) -> None:
    log.debug(cfg)
    log.info(OmegaConf.to_yaml(cfg))
    log.info("Working directory : {}".format(os.getcwd()))


if __name__ == "__main__":
    my_app()

Content of config.yaml

defaults:
 - step: ??? #want user to provide this at run time

** Stack trace/error message **

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-26-89e95316894d> in <module>
      1 cs.store(name="config", node=Config)
----> 2 cs.store(group="step", name="step1", node=step1)

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/hydra/core/config_store.py in store(self, name, node, group, package, provider)
     83             name = f"{name}.yaml"
     84         assert isinstance(cur, dict)
---> 85         cfg = OmegaConf.structured(node)
     86         cur[name] = ConfigNode(
     87             name=name, node=cfg, group=group, package=package, provider=provider

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/omegaconf/omegaconf.py in structured(obj, parent)
    138     @staticmethod
    139     def structured(obj: Any, parent: Optional[BaseContainer] = None) -> Any:
--> 140         return OmegaConf.create(obj, parent)
    141 
    142     @staticmethod

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/omegaconf/omegaconf.py in create(obj, parent)
    175         obj: Any = _EMPTY_MARKER_, parent: Optional[BaseContainer] = None
    176     ) -> Union[DictConfig, ListConfig]:
--> 177         return OmegaConf._create_impl(obj=obj, parent=parent)
    178 
    179     @staticmethod

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/omegaconf/omegaconf.py in _create_impl(obj, parent)
    219                     else:
    220                         key_type, element_type = get_dict_key_value_types(ref_type)
--> 221                     return DictConfig(
    222                         content=obj,
    223                         parent=parent,

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/omegaconf/dictconfig.py in __init__(self, content, key, parent, ref_type, key_type, element_type, is_optional)
     72 
     73         if is_structured_config(content) or is_structured_config(ref_type):
---> 74             self._set_value(content)
     75             if is_structured_config_frozen(content) or is_structured_config_frozen(
     76                 ref_type

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/omegaconf/dictconfig.py in _set_value(self, value)
    540             if is_structured_config(value):
    541                 self._metadata.object_type = None
--> 542                 data = get_structured_config_data(value)
    543                 for k, v in data.items():
    544                     self.__setitem__(k, v)

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/omegaconf/_utils.py in get_structured_config_data(obj)
    316 def get_structured_config_data(obj: Any) -> Dict[str, Any]:
    317     if is_dataclass(obj):
--> 318         return get_dataclass_data(obj)
    319     elif is_attr_class(obj):
    320         return get_attr_data(obj)

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/omegaconf/_utils.py in get_dataclass_data(obj)
    259             )
    260             format_and_raise(node=None, key=None, value=value, cause=e, msg=str(e))
--> 261         d[name] = _maybe_wrap(
    262             ref_type=type_, is_optional=is_optional, key=name, value=value, parent=None
    263         )

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/omegaconf/omegaconf.py in _maybe_wrap(ref_type, key, value, is_optional, parent)
    762         return value
    763     else:
--> 764         return _node_wrap(
    765             type_=ref_type,
    766             parent=parent,

/lab/corradin_biobank/FOR_AN/OVP/2019_MSGWAS_OVGen_GWAS_PAIR_RUN/corradin_ovp_kedro/.venv/lib/python3.8/site-packages/omegaconf/omegaconf.py in _node_wrap(type_, parent, is_optional, value, key, ref_type)
    727     elif type_ == Any or type_ is None:
    728         node = AnyNode(value=value, key=key, parent=parent, is_optional=is_optional)
--> 729     elif issubclass(type_, Enum):
    730         node = EnumNode(
    731             enum_type=type_,

TypeError: issubclass() arg 1 must be a class

Expected Behavior

System information

  • Hydra Version :
  • Python version :
  • Virtual environment type and version :
  • Operating system :

Additional context

Add any other context about the problem here.

@hoangthienan95 hoangthienan95 added the bug Something isn't working label Jan 24, 2021
@omry
Copy link
Collaborator

omry commented Jan 24, 2021

Literals are not supported by OmegaConf. use an Enum.

See feature request in omry/omegaconf#422.

@omry omry closed this as completed Jan 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants