-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e1a599f
commit 8972c91
Showing
7 changed files
with
556 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
New resolvers `oc.dict.keys` and `oc.dict.values` provide a list view of the keys or values of a DictConfig node. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import os | ||
import warnings | ||
from typing import Any, List, Optional | ||
|
||
from ._utils import _DEFAULT_MARKER_, Marker, _get_value, decode_primitive | ||
from .base import Container | ||
from .basecontainer import BaseContainer | ||
from .dictconfig import DictConfig | ||
from .errors import ConfigKeyError, ValidationError | ||
from .grammar_parser import parse | ||
from .listconfig import ListConfig | ||
from .nodes import AnyNode | ||
from .omegaconf import OmegaConf | ||
|
||
# Special marker use as default value when calling `OmegaConf.select()`. It must be | ||
# different from `_DEFAULT_MARKER_`, which is used by `OmegaConf.select()`. | ||
_DEFAULT_SELECT_MARKER_: Any = Marker("_DEFAULT_SELECT_MARKER_") | ||
|
||
|
||
def decode(expr: Optional[str], _parent_: Container) -> Any: | ||
""" | ||
Parse and evaluate `expr` according to the `singleElement` rule of the grammar. | ||
If `expr` is `None`, then return `None`. | ||
""" | ||
if expr is None: | ||
return None | ||
|
||
if not isinstance(expr, str): | ||
raise TypeError( | ||
f"`oc.decode` can only take strings or None as input, " | ||
f"but `{expr}` is of type {type(expr).__name__}" | ||
) | ||
|
||
parse_tree = parse(expr, parser_rule="singleElement", lexer_mode="VALUE_MODE") | ||
val = _parent_.resolve_parse_tree(parse_tree) | ||
return _get_value(val) | ||
|
||
|
||
def dict_keys( | ||
key: str, | ||
_parent_: Container, | ||
) -> ListConfig: | ||
assert isinstance(_parent_, BaseContainer) | ||
|
||
in_dict = _get_and_validate_dict_input( | ||
key, parent=_parent_, resolver_name="oc.dict.keys" | ||
) | ||
|
||
ret = OmegaConf.create(list(in_dict.keys()), parent=_parent_) | ||
assert isinstance(ret, ListConfig) | ||
return ret | ||
|
||
|
||
def dict_values(key: str, _root_: BaseContainer, _parent_: Container) -> ListConfig: | ||
assert isinstance(_parent_, BaseContainer) | ||
in_dict = _get_and_validate_dict_input( | ||
key, parent=_parent_, resolver_name="oc.dict.values" | ||
) | ||
|
||
content = in_dict._content | ||
assert isinstance(content, dict) | ||
|
||
ret = ListConfig([]) | ||
for k in content: | ||
ref_node = AnyNode(f"${{{key}.{k}}}") | ||
ret.append(ref_node) | ||
|
||
# Finalize result by setting proper type and parent. | ||
element_type: Any = in_dict._metadata.element_type | ||
ret._metadata.element_type = element_type | ||
ret._metadata.ref_type = List[element_type] | ||
ret._set_parent(_parent_) | ||
|
||
return ret | ||
|
||
|
||
def env(key: str, default: Any = _DEFAULT_MARKER_) -> Optional[str]: | ||
""" | ||
:param key: Environment variable key | ||
:param default: Optional default value to use in case the key environment variable is not set. | ||
If default is not a string, it is converted with str(default). | ||
None default is returned as is. | ||
:return: The environment variable 'key'. If the environment variable is not set and a default is | ||
provided, the default is used. If used, the default is converted to a string with str(default). | ||
If the default is None, None is returned (without a string conversion). | ||
""" | ||
try: | ||
return os.environ[key] | ||
except KeyError: | ||
if default is not _DEFAULT_MARKER_: | ||
return str(default) if default is not None else None | ||
else: | ||
raise KeyError(f"Environment variable '{key}' not found") | ||
|
||
|
||
# DEPRECATED: remove in 2.2 | ||
def legacy_env(key: str, default: Optional[str] = None) -> Any: | ||
warnings.warn( | ||
"The `env` resolver is deprecated, see https://github.com/omry/omegaconf/issues/573" | ||
) | ||
|
||
try: | ||
return decode_primitive(os.environ[key]) | ||
except KeyError: | ||
if default is not None: | ||
return decode_primitive(default) | ||
else: | ||
raise ValidationError(f"Environment variable '{key}' not found") | ||
|
||
|
||
def _get_and_validate_dict_input( | ||
key: str, | ||
parent: BaseContainer, | ||
resolver_name: str, | ||
) -> DictConfig: | ||
if not isinstance(key, str): | ||
raise TypeError( | ||
f"`{resolver_name}` requires a string as input, but obtained `{key}` " | ||
f"of type: {type(key).__name__}" | ||
) | ||
|
||
in_dict = OmegaConf.select( | ||
parent, | ||
key, | ||
throw_on_missing=True, | ||
absolute_key=True, | ||
default=_DEFAULT_SELECT_MARKER_, | ||
) | ||
|
||
if in_dict is _DEFAULT_SELECT_MARKER_: | ||
raise ConfigKeyError(f"Key not found: '{key}'") | ||
|
||
if not isinstance(in_dict, DictConfig): | ||
raise TypeError( | ||
f"`{resolver_name}` cannot be applied to objects of type: " | ||
f"{type(in_dict).__name__}" | ||
) | ||
|
||
return in_dict |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.