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

handle SCMode.INSTANTIATE with throw_on_missing=False #1104

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
21 changes: 10 additions & 11 deletions omegaconf/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
from .base import Container, DictKeyType, ListMergeMode, Node, SCMode, UnionNode
from .base import (
MISSING,
Container,
DictKeyType,
ListMergeMode,
Node,
SCMode,
UnionNode,
)
from .dictconfig import DictConfig
from .errors import (
KeyValidationError,
Expand All @@ -19,16 +27,7 @@
StringNode,
ValueNode,
)
from .omegaconf import (
II,
MISSING,
SI,
OmegaConf,
Resolver,
flag_override,
open_dict,
read_write,
)
from .omegaconf import II, SI, OmegaConf, Resolver, flag_override, open_dict, read_write
from .version import __version__

__all__ = [
Expand Down
3 changes: 2 additions & 1 deletion omegaconf/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,8 @@ def get_dataclass_fields(obj: Any) -> List["dataclasses.Field[Any]"]:
def get_dataclass_data(
obj: Any, allow_objects: Optional[bool] = None
) -> Dict[str, Any]:
from omegaconf.omegaconf import MISSING, OmegaConf, _maybe_wrap
from omegaconf import MISSING, OmegaConf
from omegaconf.omegaconf import _maybe_wrap

Check notice

Code scanning / CodeQL

Cyclic import

Import of module [omegaconf.omegaconf](1) begins an import cycle.

flags = {"allow_objects": allow_objects} if allow_objects is not None else {}
d = {}
Expand Down
2 changes: 2 additions & 0 deletions omegaconf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
from .grammar_parser import parse
from .grammar_visitor import GrammarVisitor

MISSING: Any = "???"

DictKeyType = Union[str, bytes, int, Enum, float, bool]


Expand Down
2 changes: 1 addition & 1 deletion omegaconf/basecontainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def get_node_value(key: Union[DictKeyType, int]) -> Any:
if structured_config_mode == SCMode.INSTANTIATE and is_structured_config(
conf._metadata.object_type
):
return conf._to_object()
return conf._to_object(throw_on_missing=throw_on_missing)

retdict: Dict[DictKeyType, Any] = {}
for key in conf.keys():
Expand Down
21 changes: 12 additions & 9 deletions omegaconf/dictconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
is_structured_config_frozen,
type_str,
)
from .base import Box, Container, ContainerMetadata, DictKeyType, Node
from .base import MISSING, Box, Container, ContainerMetadata, DictKeyType, Node

Check notice

Code scanning / CodeQL

Cyclic import

Import of module [omegaconf.base](1) begins an import cycle.
from .basecontainer import BaseContainer
from .errors import (
ConfigAttributeError,
Expand Down Expand Up @@ -716,7 +716,7 @@ def _dict_conf_eq(d1: "DictConfig", d2: "DictConfig") -> bool:

return True

def _to_object(self) -> Any:
def _to_object(self, throw_on_missing: bool) -> Any:
"""
Instantiate an instance of `self._metadata.object_type`.
This requires `self` to be a structured config.
Expand All @@ -741,13 +741,16 @@ def _to_object(self) -> Any:
if node._is_missing():
if k not in init_field_names:
continue # MISSING is ignored for init=False fields
self._format_and_raise(
key=k,
value=None,
cause=MissingMandatoryValue(
"Structured config of type `$OBJECT_TYPE` has missing mandatory value: $KEY"
),
)
if throw_on_missing:
self._format_and_raise(
key=k,
value=None,
cause=MissingMandatoryValue(
"Structured config of type `$OBJECT_TYPE` has missing mandatory value: $KEY"
),
)
else:
v = MISSING

Check warning

Code scanning / CodeQL

Variable defined multiple times

This assignment to 'v' is unnecessary as it is [redefined](1) before this value is used. This assignment to 'v' is unnecessary as it is [redefined](2) before this value is used.
if isinstance(node, Container):
v = OmegaConf.to_object(node)
else:
Expand Down
2 changes: 0 additions & 2 deletions omegaconf/omegaconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@
ValueNode,
)

MISSING: Any = "???"

Resolver = Callable[..., Any]


Expand Down
12 changes: 12 additions & 0 deletions tests/test_to_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pytest import fixture, mark, param, raises

from omegaconf import (
MISSING,
DictConfig,
ListConfig,
MissingMandatoryValue,
Expand Down Expand Up @@ -407,6 +408,17 @@ def test_to_container_INSTANTIATE_enum_to_str_True(self, module: Any) -> None:
assert container["color"] == "BLUE"
assert container["obj"].not_optional is Color.BLUE

def test_to_container_INSTANTIATE_throw_on_missing_False(self, module: Any) -> None:
"""Test the lower level `to_container` API with SCMode.INSTANTIATE and throw_on_missing=False"""
src = module.User("Bond") # age: MISSING
cfg = OmegaConf.create(src)
container = OmegaConf.to_container(
cfg, throw_on_missing=False, structured_config_mode=SCMode.INSTANTIATE
)
assert isinstance(container, module.User)
assert container.name == "Bond"
assert container.age is MISSING

def test_to_object_InterpolationResolutionError(self, module: Any) -> None:
with raises(InterpolationResolutionError):
cfg = OmegaConf.structured(module.NestedWithAny)
Expand Down