From f40738db2ed977cc64849780d76cc3e636aa00b2 Mon Sep 17 00:00:00 2001 From: vermont Date: Mon, 14 Aug 2023 03:15:52 -0400 Subject: [PATCH 01/10] First try at fixing dict[..., dict[..., StructuredConfig]]. --- omegaconf/basecontainer.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/omegaconf/basecontainer.py b/omegaconf/basecontainer.py index a83907f8e..8540b132d 100644 --- a/omegaconf/basecontainer.py +++ b/omegaconf/basecontainer.py @@ -384,12 +384,18 @@ def expand(node: Container) -> None: dest_node = dest._get_node(key) is_optional, et = _resolve_optional(dest._metadata.element_type) - if dest_node is None and is_structured_config(et) and not src_node_missing: - # merging into a new node. Use element_type as a base - dest[key] = DictConfig( - et, parent=dest, ref_type=et, is_optional=is_optional - ) - dest_node = dest._get_node(key) + if dest_node is None and not src_node_missing: + if is_structured_config(et): + # merging into a new node. Use element_type as a base + dest[key] = DictConfig( + et, parent=dest, ref_type=et, is_optional=is_optional + ) + dest_node = dest._get_node(key) + elif is_dict_annotation(et): + dest[key] = DictConfig({}, parent=dest, ref_type=et, is_optional=is_optional) + dest_node = dest._get_node(key) + elif is_list_annotation(et): + dest[key] = ListConfig([], parent=dest, ref_type=et, is_optional=is_optional) if dest_node is not None: if isinstance(dest_node, BaseContainer): From 87606cfb8c90afff9151403cfe1022a797aa3096 Mon Sep 17 00:00:00 2001 From: vermont Date: Mon, 14 Aug 2023 03:40:28 -0400 Subject: [PATCH 02/10] Forgot to import ListConfig. test_nested_containers.py::test_merge_bad_element type still fails but I don't have time to fix it. --- omegaconf/basecontainer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/omegaconf/basecontainer.py b/omegaconf/basecontainer.py index 8540b132d..49a0c33d4 100644 --- a/omegaconf/basecontainer.py +++ b/omegaconf/basecontainer.py @@ -304,7 +304,7 @@ def _map_merge( list_merge_mode: ListMergeMode = ListMergeMode.REPLACE, ) -> None: """merge src into dest and return a new copy, does not modified input""" - from omegaconf import AnyNode, DictConfig, ValueNode + from omegaconf import AnyNode, DictConfig, ListConfig, ValueNode assert isinstance(dest, DictConfig) assert isinstance(src, DictConfig) From e5d8a20f8bae82409d5d2d173909470ca2c70323 Mon Sep 17 00:00:00 2001 From: vermont Date: Mon, 14 Aug 2023 04:27:55 -0400 Subject: [PATCH 03/10] typo --- omegaconf/basecontainer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/omegaconf/basecontainer.py b/omegaconf/basecontainer.py index 49a0c33d4..98c5e7c9d 100644 --- a/omegaconf/basecontainer.py +++ b/omegaconf/basecontainer.py @@ -396,6 +396,7 @@ def expand(node: Container) -> None: dest_node = dest._get_node(key) elif is_list_annotation(et): dest[key] = ListConfig([], parent=dest, ref_type=et, is_optional=is_optional) + dest_node = dest._get_node(key) if dest_node is not None: if isinstance(dest_node, BaseContainer): From 54d515f6c9674072ec6bf4c8362c79fe6d65cedc Mon Sep 17 00:00:00 2001 From: vermont Date: Sat, 21 Oct 2023 19:25:08 -0400 Subject: [PATCH 04/10] Explicitly set key_type and element_type for nested map merge. First try to fix nested list merge. --- omegaconf/basecontainer.py | 46 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/omegaconf/basecontainer.py b/omegaconf/basecontainer.py index 98c5e7c9d..ba00119aa 100644 --- a/omegaconf/basecontainer.py +++ b/omegaconf/basecontainer.py @@ -305,6 +305,7 @@ def _map_merge( ) -> None: """merge src into dest and return a new copy, does not modified input""" from omegaconf import AnyNode, DictConfig, ListConfig, ValueNode + from ._utils import get_dict_key_value_types, get_list_element_type assert isinstance(dest, DictConfig) assert isinstance(src, DictConfig) @@ -380,22 +381,27 @@ def expand(node: Container) -> None: if dest_node is not None and dest_node._is_interpolation(): target_node = dest_node._maybe_dereference_node() if isinstance(target_node, Container): - dest[key] = target_node + dest.__setitem__(key, target_node) dest_node = dest._get_node(key) is_optional, et = _resolve_optional(dest._metadata.element_type) if dest_node is None and not src_node_missing: + # check if merging into a new node if is_structured_config(et): - # merging into a new node. Use element_type as a base - dest[key] = DictConfig( - et, parent=dest, ref_type=et, is_optional=is_optional - ) + # Use element_type as a base + dest.__setitem__(key, DictConfig(et, parent=dest, ref_type=et, is_optional=is_optional)) dest_node = dest._get_node(key) elif is_dict_annotation(et): - dest[key] = DictConfig({}, parent=dest, ref_type=et, is_optional=is_optional) + key_type, element_type = get_dict_key_value_types(et) + dest.__setitem__(key, DictConfig( + {}, parent=dest, ref_type=et, key_type=key_type, element_type=element_type, is_optional=is_optional + )) dest_node = dest._get_node(key) elif is_list_annotation(et): - dest[key] = ListConfig([], parent=dest, ref_type=et, is_optional=is_optional) + element_type = get_list_element_type(et) + dest.__setitem__(key, ListConfig( + [], parent=dest, ref_type=et, element_type=element_type, is_optional=is_optional + )) dest_node = dest._get_node(key) if dest_node is not None: @@ -435,9 +441,9 @@ def expand(node: Container) -> None: if is_structured_config(src_type): # verified to be compatible above in _validate_merge with open_dict(dest): - dest[key] = src._get_node(key) + dest.__setitem__(key, src._get_node(key)) else: - dest[key] = src._get_node(key) + dest.__setitem__(key, src._get_node(key)) _update_types(node=dest, ref_type=src_ref_type, object_type=src_type) @@ -455,6 +461,7 @@ def _list_merge( list_merge_mode: ListMergeMode = ListMergeMode.REPLACE, ) -> None: from omegaconf import DictConfig, ListConfig, OmegaConf + from ._utils import get_dict_key_value_types, get_list_element_type assert isinstance(dest, ListConfig) assert isinstance(src, ListConfig) @@ -473,15 +480,22 @@ def _list_merge( dest.__dict__["_metadata"] ) is_optional, et = _resolve_optional(dest._metadata.element_type) + + prototype: Optional[Union[DictConfig, ListConfig]] = None + if is_structured_config(et): prototype = DictConfig(et, ref_type=et, is_optional=is_optional) - for item in src._iter_ex(resolve=False): - if isinstance(item, DictConfig): - item = OmegaConf.merge(prototype, item) - temp_target.append(item) - else: - for item in src._iter_ex(resolve=False): - temp_target.append(item) + elif is_dict_annotation(et): + key_type, element_type = get_dict_key_value_types(et) + prototype = DictConfig({}, ref_type=et, key_type=key_type, element_type=element_type, is_optional=is_optional) + elif is_list_annotation(et): + element_type = get_list_element_type(et) + prototype = ListConfig([], ref_type=et, element_type=element_type, is_optional=is_optional) + + for item in src._iter_ex(resolve=False): + if prototype is not None: + item = OmegaConf.merge(prototype, item) + temp_target.append(item) if list_merge_mode == ListMergeMode.EXTEND: dest.__dict__["_content"].extend(temp_target.__dict__["_content"]) From ca25af827e31e9163cc63a3c80634ba524801bab Mon Sep 17 00:00:00 2001 From: vermont Date: Sat, 21 Oct 2023 19:29:03 -0400 Subject: [PATCH 05/10] Missed the ListMergeMode. --- omegaconf/basecontainer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/omegaconf/basecontainer.py b/omegaconf/basecontainer.py index ba00119aa..ea52f4e4a 100644 --- a/omegaconf/basecontainer.py +++ b/omegaconf/basecontainer.py @@ -494,7 +494,7 @@ def _list_merge( for item in src._iter_ex(resolve=False): if prototype is not None: - item = OmegaConf.merge(prototype, item) + item = OmegaConf.merge(prototype, item, list_merge_mode=list_merge_mode) temp_target.append(item) if list_merge_mode == ListMergeMode.EXTEND: From 6961f4758973d3c6b27c21979302d00d07f098b7 Mon Sep 17 00:00:00 2001 From: vermont Date: Sat, 21 Oct 2023 22:42:08 -0400 Subject: [PATCH 06/10] Fix error msg for one test; add tests for DeeplyNestedUser. --- tests/structured_conf/data/attr_classes.py | 8 +++++ tests/structured_conf/data/dataclasses.py | 8 +++++ .../data/dataclasses_pre_311.py | 8 +++++ .../structured_conf/test_structured_config.py | 32 ++++++++++++++++++- tests/test_nested_containers.py | 2 +- 5 files changed, 56 insertions(+), 2 deletions(-) diff --git a/tests/structured_conf/data/attr_classes.py b/tests/structured_conf/data/attr_classes.py index f0b32d02c..ad145b573 100644 --- a/tests/structured_conf/data/attr_classes.py +++ b/tests/structured_conf/data/attr_classes.py @@ -260,6 +260,14 @@ class NestedWithAny: var: Any = Nested() +@attr.s(auto_attribs=True) +class DeeplyNestedUser: + dsdsu: Dict[str, Dict[str, User]] + dslu: Dict[str, List[User]] + ldsu: List[Dict[str, User]] + llu: List[List[User]] + + @attr.s(auto_attribs=True) class NoDefaultValue: no_default: Any diff --git a/tests/structured_conf/data/dataclasses.py b/tests/structured_conf/data/dataclasses.py index b79640794..674ab7aa3 100644 --- a/tests/structured_conf/data/dataclasses.py +++ b/tests/structured_conf/data/dataclasses.py @@ -263,6 +263,14 @@ class NestedWithAny: var: Any = field(default_factory=Nested) +@dataclass +class DeeplyNestedUser: + dsdsu: Dict[str, Dict[str, User]] + dslu: Dict[str, List[User]] + ldsu: List[Dict[str, User]] + llu: List[List[User]] + + @dataclass class NoDefaultValue: no_default: Any diff --git a/tests/structured_conf/data/dataclasses_pre_311.py b/tests/structured_conf/data/dataclasses_pre_311.py index 1401d4324..f86595d04 100644 --- a/tests/structured_conf/data/dataclasses_pre_311.py +++ b/tests/structured_conf/data/dataclasses_pre_311.py @@ -261,6 +261,14 @@ class NestedWithAny: var: Any = Nested() +@dataclass +class DeeplyNestedUser: + dsdsu: Dict[str, Dict[str, User]] + dslu: Dict[str, List[User]] + ldsu: List[Dict[str, User]] + llu: List[List[User]] + + @dataclass class NoDefaultValue: no_default: Any diff --git a/tests/structured_conf/test_structured_config.py b/tests/structured_conf/test_structured_config.py index 67ac2189f..1d5c0734d 100644 --- a/tests/structured_conf/test_structured_config.py +++ b/tests/structured_conf/test_structured_config.py @@ -24,7 +24,7 @@ ValidationError, _utils, ) -from omegaconf.errors import ConfigKeyError, InterpolationToMissingValueError +from omegaconf.errors import ConfigKeyError, ConfigTypeError, InterpolationToMissingValueError from tests import Color, Enum1, User, warns_dict_subclass_deprecated @@ -1892,6 +1892,36 @@ def test_assign_none( with raises(ValidationError): node[last_key] = value + @mark.parametrize( + "user_value, expected_error", + [ + param({'name': 'Bond', 'age': 7}, None, id='user'), + param({'cat': 'Bond', 'turnip': 7}, ConfigKeyError, id='user-bad-key'), + param({'name': 'Bond', 'age': 'two hundred billion'}, ValidationError, id='user-bad-type1'), + param([1, 2, 3], ConfigTypeError, id='user-bad-type2'), + ] + ) + @mark.parametrize( + "key, make_nested_value", + [ + param('dsdsu', lambda uv: {'level1': {'level2': uv}}, id='dsdsu'), + param('dslu', lambda uv: {'level1': [uv]}, id='dslu'), + param('ldsu', lambda uv: [{'level1': uv}], id='ldsu'), + param('llu', lambda uv: [[uv]], id='llu'), + ] + ) + def test_merge_with_deep_nesting( + self, module: Any, key: str, make_nested_value, user_value, expected_error + ) -> None: + conf = OmegaConf.structured(module.DeeplyNestedUser) + src = {key: make_nested_value(user_value)} + + if expected_error is None: + OmegaConf.merge(conf, src) + else: + with raises(expected_error): + OmegaConf.merge(conf, src) + class TestUnionsOfPrimitiveTypes: @mark.parametrize( diff --git a/tests/test_nested_containers.py b/tests/test_nested_containers.py index 0be4a8984..90018e9f8 100644 --- a/tests/test_nested_containers.py +++ b/tests/test_nested_containers.py @@ -1408,7 +1408,7 @@ def test_merge_nested_list_promotion() -> None: ), param( [DictConfig({}, element_type=Dict[str, int]), {"foo": 123}], - "Value 123 (int) is incompatible with type hint 'typing.Dict[str, int]'", + "Cannot assign int to Dict[str, int]", id="merge-int-into-dict", ), param( From a45da17abc26a8e61d74c81efdb4278cd2960037 Mon Sep 17 00:00:00 2001 From: vermont Date: Sat, 21 Oct 2023 23:11:36 -0400 Subject: [PATCH 07/10] Test even deeper nesting; add checks for key_type and element_type. --- tests/structured_conf/data/attr_classes.py | 8 +-- tests/structured_conf/data/dataclasses.py | 8 +-- .../data/dataclasses_pre_311.py | 8 +-- .../structured_conf/test_structured_config.py | 54 +++++++++++++++---- 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/tests/structured_conf/data/attr_classes.py b/tests/structured_conf/data/attr_classes.py index ad145b573..c663cc521 100644 --- a/tests/structured_conf/data/attr_classes.py +++ b/tests/structured_conf/data/attr_classes.py @@ -262,10 +262,10 @@ class NestedWithAny: @attr.s(auto_attribs=True) class DeeplyNestedUser: - dsdsu: Dict[str, Dict[str, User]] - dslu: Dict[str, List[User]] - ldsu: List[Dict[str, User]] - llu: List[List[User]] + dsdsdsu: Dict[str, Dict[str, Dict[str, User]]] + dsdslu: Dict[str, Dict[str, List[User]]] + lldsu: List[List[Dict[str, User]]] + lllu: List[List[List[User]]] @attr.s(auto_attribs=True) diff --git a/tests/structured_conf/data/dataclasses.py b/tests/structured_conf/data/dataclasses.py index 674ab7aa3..6065e2b29 100644 --- a/tests/structured_conf/data/dataclasses.py +++ b/tests/structured_conf/data/dataclasses.py @@ -265,10 +265,10 @@ class NestedWithAny: @dataclass class DeeplyNestedUser: - dsdsu: Dict[str, Dict[str, User]] - dslu: Dict[str, List[User]] - ldsu: List[Dict[str, User]] - llu: List[List[User]] + dsdsdsu: Dict[str, Dict[str, Dict[str, User]]] + dsdslu: Dict[str, Dict[str, List[User]]] + lldsu: List[List[Dict[str, User]]] + lllu: List[List[List[User]]] @dataclass diff --git a/tests/structured_conf/data/dataclasses_pre_311.py b/tests/structured_conf/data/dataclasses_pre_311.py index f86595d04..4b74140c4 100644 --- a/tests/structured_conf/data/dataclasses_pre_311.py +++ b/tests/structured_conf/data/dataclasses_pre_311.py @@ -263,10 +263,10 @@ class NestedWithAny: @dataclass class DeeplyNestedUser: - dsdsu: Dict[str, Dict[str, User]] - dslu: Dict[str, List[User]] - ldsu: List[Dict[str, User]] - llu: List[List[User]] + dsdsdsu: Dict[str, Dict[str, Dict[str, User]]] + dsdslu: Dict[str, Dict[str, List[User]]] + lldsu: List[List[Dict[str, User]]] + lllu: List[List[List[User]]] @dataclass diff --git a/tests/structured_conf/test_structured_config.py b/tests/structured_conf/test_structured_config.py index 1d5c0734d..af23e0c41 100644 --- a/tests/structured_conf/test_structured_config.py +++ b/tests/structured_conf/test_structured_config.py @@ -24,7 +24,11 @@ ValidationError, _utils, ) -from omegaconf.errors import ConfigKeyError, ConfigTypeError, InterpolationToMissingValueError +from omegaconf.errors import ( + ConfigKeyError, + ConfigTypeError, + InterpolationToMissingValueError, +) from tests import Color, Enum1, User, warns_dict_subclass_deprecated @@ -1895,29 +1899,57 @@ def test_assign_none( @mark.parametrize( "user_value, expected_error", [ - param({'name': 'Bond', 'age': 7}, None, id='user'), + param({'name': 'Bond', 'age': 7}, None, id='user-good'), param({'cat': 'Bond', 'turnip': 7}, ConfigKeyError, id='user-bad-key'), - param({'name': 'Bond', 'age': 'two hundred billion'}, ValidationError, id='user-bad-type1'), + param({'name': 'Bond', 'age': 'abc'}, ValidationError, id='user-bad-type1'), param([1, 2, 3], ConfigTypeError, id='user-bad-type2'), ] ) @mark.parametrize( - "key, make_nested_value", + "key, make_nested, indices", [ - param('dsdsu', lambda uv: {'level1': {'level2': uv}}, id='dsdsu'), - param('dslu', lambda uv: {'level1': [uv]}, id='dslu'), - param('ldsu', lambda uv: [{'level1': uv}], id='ldsu'), - param('llu', lambda uv: [[uv]], id='llu'), + param( + 'dsdsdsu', + lambda uv: {'l1': {'l2': {'l3': uv}}}, + ['l1', 'l2', 'l3'], + id='dsdsdsu' + ), + param( + 'dsdslu', + lambda uv: {'l1': {'l2': [uv]}}, + ['l1', 'l2', 0], + id='dsdslu' + ), + param( + 'lldsu', + lambda uv: [[{'l3': uv}]], + [0, 0, 'l3'], + id='lldsu' + ), + param( + 'lllu', + lambda uv: [[[uv]]], + [0, 0, 0], + id='lllu' + ), ] ) def test_merge_with_deep_nesting( - self, module: Any, key: str, make_nested_value, user_value, expected_error + self, module: Any, key: str, make_nested, indices, user_value, expected_error ) -> None: conf = OmegaConf.structured(module.DeeplyNestedUser) - src = {key: make_nested_value(user_value)} + src = {key: make_nested(user_value)} if expected_error is None: - OmegaConf.merge(conf, src) + merged = OmegaConf.merge(conf, src) + assert isinstance(merged, DictConfig) + value = merged[key] + for index in indices: + previous = value + value = value[index] + assert previous._metadata.key_type is type(index) + assert previous._metadata.element_type is value._metadata.ref_type + assert value._metadata.ref_type is module.User else: with raises(expected_error): OmegaConf.merge(conf, src) From 598bace730f910e1894c157379897a5d37862ee7 Mon Sep 17 00:00:00 2001 From: vermont Date: Sat, 21 Oct 2023 23:15:48 -0400 Subject: [PATCH 08/10] standardize the quotes --- .../structured_conf/test_structured_config.py | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/structured_conf/test_structured_config.py b/tests/structured_conf/test_structured_config.py index af23e0c41..b51873b83 100644 --- a/tests/structured_conf/test_structured_config.py +++ b/tests/structured_conf/test_structured_config.py @@ -1899,38 +1899,38 @@ def test_assign_none( @mark.parametrize( "user_value, expected_error", [ - param({'name': 'Bond', 'age': 7}, None, id='user-good'), - param({'cat': 'Bond', 'turnip': 7}, ConfigKeyError, id='user-bad-key'), - param({'name': 'Bond', 'age': 'abc'}, ValidationError, id='user-bad-type1'), - param([1, 2, 3], ConfigTypeError, id='user-bad-type2'), + param({"name": "Bond", "age": 7}, None, id="user-good"), + param({"cat": "Bond", "turnip": 7}, ConfigKeyError, id="user-bad-key"), + param({"name": "Bond", "age": "abc"}, ValidationError, id="user-bad-type1"), + param([1, 2, 3], ConfigTypeError, id="user-bad-type2"), ] ) @mark.parametrize( "key, make_nested, indices", [ param( - 'dsdsdsu', - lambda uv: {'l1': {'l2': {'l3': uv}}}, - ['l1', 'l2', 'l3'], - id='dsdsdsu' + "dsdsdsu", + lambda uv: {"l1": {"l2": {"l3": uv}}}, + ["l1", "l2", "l3"], + id="dsdsdsu" ), param( - 'dsdslu', - lambda uv: {'l1': {'l2': [uv]}}, - ['l1', 'l2', 0], - id='dsdslu' + "dsdslu", + lambda uv: {"l1": {"l2": [uv]}}, + ["l1", "l2", 0], + id="dsdslu" ), param( - 'lldsu', - lambda uv: [[{'l3': uv}]], - [0, 0, 'l3'], - id='lldsu' + "lldsu", + lambda uv: [[{"l3": uv}]], + [0, 0, "l3"], + id="lldsu" ), param( - 'lllu', + "lllu", lambda uv: [[[uv]]], [0, 0, 0], - id='lllu' + id="lllu" ), ] ) From 81e826be396bbd06e1a70c4f3e1acf7e83f83421 Mon Sep 17 00:00:00 2001 From: vermont Date: Sat, 21 Oct 2023 23:26:48 -0400 Subject: [PATCH 09/10] isort and black --- omegaconf/basecontainer.py | 52 +++++++++++++++---- .../structured_conf/test_structured_config.py | 25 +++------ 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/omegaconf/basecontainer.py b/omegaconf/basecontainer.py index ea52f4e4a..2665e940e 100644 --- a/omegaconf/basecontainer.py +++ b/omegaconf/basecontainer.py @@ -305,6 +305,7 @@ def _map_merge( ) -> None: """merge src into dest and return a new copy, does not modified input""" from omegaconf import AnyNode, DictConfig, ListConfig, ValueNode + from ._utils import get_dict_key_value_types, get_list_element_type assert isinstance(dest, DictConfig) @@ -389,19 +390,39 @@ def expand(node: Container) -> None: # check if merging into a new node if is_structured_config(et): # Use element_type as a base - dest.__setitem__(key, DictConfig(et, parent=dest, ref_type=et, is_optional=is_optional)) + dest.__setitem__( + key, + DictConfig( + et, parent=dest, ref_type=et, is_optional=is_optional + ), + ) dest_node = dest._get_node(key) elif is_dict_annotation(et): key_type, element_type = get_dict_key_value_types(et) - dest.__setitem__(key, DictConfig( - {}, parent=dest, ref_type=et, key_type=key_type, element_type=element_type, is_optional=is_optional - )) + dest.__setitem__( + key, + DictConfig( + {}, + parent=dest, + ref_type=et, + key_type=key_type, + element_type=element_type, + is_optional=is_optional, + ), + ) dest_node = dest._get_node(key) elif is_list_annotation(et): element_type = get_list_element_type(et) - dest.__setitem__(key, ListConfig( - [], parent=dest, ref_type=et, element_type=element_type, is_optional=is_optional - )) + dest.__setitem__( + key, + ListConfig( + [], + parent=dest, + ref_type=et, + element_type=element_type, + is_optional=is_optional, + ), + ) dest_node = dest._get_node(key) if dest_node is not None: @@ -461,6 +482,7 @@ def _list_merge( list_merge_mode: ListMergeMode = ListMergeMode.REPLACE, ) -> None: from omegaconf import DictConfig, ListConfig, OmegaConf + from ._utils import get_dict_key_value_types, get_list_element_type assert isinstance(dest, ListConfig) @@ -487,14 +509,24 @@ def _list_merge( prototype = DictConfig(et, ref_type=et, is_optional=is_optional) elif is_dict_annotation(et): key_type, element_type = get_dict_key_value_types(et) - prototype = DictConfig({}, ref_type=et, key_type=key_type, element_type=element_type, is_optional=is_optional) + prototype = DictConfig( + {}, + ref_type=et, + key_type=key_type, + element_type=element_type, + is_optional=is_optional, + ) elif is_list_annotation(et): element_type = get_list_element_type(et) - prototype = ListConfig([], ref_type=et, element_type=element_type, is_optional=is_optional) + prototype = ListConfig( + [], ref_type=et, element_type=element_type, is_optional=is_optional + ) for item in src._iter_ex(resolve=False): if prototype is not None: - item = OmegaConf.merge(prototype, item, list_merge_mode=list_merge_mode) + item = OmegaConf.merge( + prototype, item, list_merge_mode=list_merge_mode + ) temp_target.append(item) if list_merge_mode == ListMergeMode.EXTEND: diff --git a/tests/structured_conf/test_structured_config.py b/tests/structured_conf/test_structured_config.py index b51873b83..b80eafe37 100644 --- a/tests/structured_conf/test_structured_config.py +++ b/tests/structured_conf/test_structured_config.py @@ -1903,7 +1903,7 @@ def test_assign_none( param({"cat": "Bond", "turnip": 7}, ConfigKeyError, id="user-bad-key"), param({"name": "Bond", "age": "abc"}, ValidationError, id="user-bad-type1"), param([1, 2, 3], ConfigTypeError, id="user-bad-type2"), - ] + ], ) @mark.parametrize( "key, make_nested, indices", @@ -1912,27 +1912,14 @@ def test_assign_none( "dsdsdsu", lambda uv: {"l1": {"l2": {"l3": uv}}}, ["l1", "l2", "l3"], - id="dsdsdsu" - ), - param( - "dsdslu", - lambda uv: {"l1": {"l2": [uv]}}, - ["l1", "l2", 0], - id="dsdslu" + id="dsdsdsu", ), param( - "lldsu", - lambda uv: [[{"l3": uv}]], - [0, 0, "l3"], - id="lldsu" + "dsdslu", lambda uv: {"l1": {"l2": [uv]}}, ["l1", "l2", 0], id="dsdslu" ), - param( - "lllu", - lambda uv: [[[uv]]], - [0, 0, 0], - id="lllu" - ), - ] + param("lldsu", lambda uv: [[{"l3": uv}]], [0, 0, "l3"], id="lldsu"), + param("lllu", lambda uv: [[[uv]]], [0, 0, 0], id="lllu"), + ], ) def test_merge_with_deep_nesting( self, module: Any, key: str, make_nested, indices, user_value, expected_error From 95a3f332250aba1069e2ee72206a48d40de0d75b Mon Sep 17 00:00:00 2001 From: vermont Date: Sun, 22 Oct 2023 00:54:06 -0400 Subject: [PATCH 10/10] test params readability --- .../structured_conf/test_structured_config.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/structured_conf/test_structured_config.py b/tests/structured_conf/test_structured_config.py index b80eafe37..a0099a855 100644 --- a/tests/structured_conf/test_structured_config.py +++ b/tests/structured_conf/test_structured_config.py @@ -1915,10 +1915,23 @@ def test_assign_none( id="dsdsdsu", ), param( - "dsdslu", lambda uv: {"l1": {"l2": [uv]}}, ["l1", "l2", 0], id="dsdslu" + "dsdslu", + lambda uv: {"l1": {"l2": [uv]}}, + ["l1", "l2", 0], + id="dsdslu", + ), + param( + "lldsu", + lambda uv: [[{"l3": uv}]], + [0, 0, "l3"], + id="lldsu", + ), + param( + "lllu", + lambda uv: [[[uv]]], + [0, 0, 0], + id="lllu", ), - param("lldsu", lambda uv: [[{"l3": uv}]], [0, 0, "l3"], id="lldsu"), - param("lllu", lambda uv: [[[uv]]], [0, 0, 0], id="lllu"), ], ) def test_merge_with_deep_nesting(