diff --git a/dvc/utils/collections.py b/dvc/utils/collections.py index 15363180d..71bbde03b 100644 --- a/dvc/utils/collections.py +++ b/dvc/utils/collections.py @@ -84,13 +84,17 @@ def merge_params(src: Dict, to_update: Dict) -> Dict: """Recursively merges params with benedict's syntax support in-place.""" from benedict import benedict + data = benedict(src) if src: - benedict(src).merge(to_update, overwrite=True) + data.merge(to_update, overwrite=True) else: + # NOTE: the following line may seem like an unnecessary duplication + # data.merge might affect the `src` if it's not empty, so we cannot + # check `if src` later, as it may have been mutated already. + data.merge(to_update, overwrite=True) # benedict has issues keeping references to an empty dictionary # see: https://github.com/iterative/dvc/issues/6374. - # Also, passing to_update through benedict to expand the syntax. - src.update(benedict(to_update)) + src.update(data) return src diff --git a/tests/unit/utils/test_collections.py b/tests/unit/utils/test_collections.py index f7b02d1c1..1d032c3b5 100644 --- a/tests/unit/utils/test_collections.py +++ b/tests/unit/utils/test_collections.py @@ -202,6 +202,7 @@ def test_merge_params(changes, expected): [ [{"foo": "baz"}, {"foo": "baz"}], [{"foo": "baz", "goo": "bar"}, {"foo": "baz", "goo": "bar"}], + [{"foo[1]": ["baz", "goo"]}, {"foo": [None, ["baz", "goo"]]}], ], ) def test_merge_params_on_empty_src(changes, expected):