From 620f3f5f0cb0d578da2207fe511913c8049c45b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zachar?= Date: Tue, 14 Jan 2025 17:15:39 +0100 Subject: [PATCH] Keep merge suffix for nested dictionaries This is necessary to make possible merging dictionaries in adjust rules. Otherwise they would be always set (instead of update). Fix: #276 Reopen: #190 --- docs/features.rst | 22 ++++++++++++++++++++++ docs/releases.rst | 8 ++++++++ examples/deep/main.fmf | 1 + fmf/base.py | 8 +------- tests/unit/test_base.py | 20 ++++++++++++++++++-- 5 files changed, 50 insertions(+), 9 deletions(-) diff --git a/docs/features.rst b/docs/features.rst index 0535a5b..01cbeeb 100644 --- a/docs/features.rst +++ b/docs/features.rst @@ -98,6 +98,9 @@ or when merging a dictionary with a list. Exception ``MergeError`` is raised if types are not compatible. When the ``+`` suffix is applied on dictionaries ``update()`` method is used to merge content of given dictionary instead of replacing it. +When such parent dictionary doesn't exist, but the suffix ``+`` is used +at the top level, the dictionary is created and named without the suffix. +However, for dictionaries at deeper levels, the suffix remains in their name. Example: Merging dictionary with a list:: @@ -159,6 +162,25 @@ results in:: url: https://github.com/project2 filter: "tier:2" +Example: Merging with not yet defined dictionaries:: + + environment+: + CLEAR: "1" + adjust+: + when: distro == fedora + environment+: + FEDORA: "1" + +results in (no ``+`` suffix in ``adjust`` and top ``environment`` keys):: + + adjust: + when: distro == fedora + environment+: + FEDORA: "1" + environment: + CLEAR: "1" + + The special suffix ``+<`` can be used to prepend values instead of appending them. This might be handy when adjusting lists:: diff --git a/docs/releases.rst b/docs/releases.rst index 83573f6..a1d1359 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -4,6 +4,14 @@ Releases ====================== +fmf-1.6.1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to allow adjust rules to merge dictionaries, nested +dictionaries need to keep the suffix in their name. This behavior +reverts to fmf-1.4.0 and is now documented in :ref:`merging` +section. + fmf-1.6.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/examples/deep/main.fmf b/examples/deep/main.fmf index 1051a6f..19eb4d9 100644 --- a/examples/deep/main.fmf +++ b/examples/deep/main.fmf @@ -21,6 +21,7 @@ hardware: model: e1000 # A deep dictionary extending non-existent values +# should keep '+' (important for adjust) /single: undefined+: deeper+: diff --git a/fmf/base.py b/fmf/base.py index 6ad5863..a48b632 100644 --- a/fmf/base.py +++ b/fmf/base.py @@ -190,13 +190,7 @@ def _merge_plus(self, data, key, value, prepend=False): # Set the value if key is not present if key not in data: - # Special handling for dictionaries as their keys might - # contain suffixes which should be removed - if isinstance(value, dict): - data[key] = {} - self._merge_special(data[key], value) - else: - data[key] = value + data[key] = value return # Parent is a list of dict and child is a dict diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index 482209e..5248d96 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -4,6 +4,7 @@ import threading import time from shutil import rmtree +from textwrap import dedent import pytest from ruamel.yaml import YAML @@ -158,6 +159,21 @@ def test_adjust_strips_control_keys(self): assert 'because' not in child.data assert 'foo' in child.data + def test_adjust_can_extend(self): + """ It is possible to extend dictionary with adjust """ + tree = Tree(YAML(typ='safe').load(dedent(""" + /a: + environment+: + FOO: bar + adjust+: + environment+: + BAR: baz + """))) + tree.adjust(context=Context()) + child = tree.find('/a') + assert child.data['environment']['FOO'] == "bar" + assert child.data['environment']['BAR'] == "baz" + def test_deep_hierarchy(self): """ Deep hierarchy on one line """ deep = Tree(EXAMPLES + "deep") @@ -175,12 +191,12 @@ def test_deep_dictionary_undefined_keys(self): """ Extending undefined keys using '+' should work """ deep = Tree(EXAMPLES + "deep") single = deep.find("/single") - assert single.get(["undefined", "deeper", "key"]) == "value" + assert single.get(["undefined", "deeper+", "key"]) == "value" child = deep.find("/parent/child") assert child.get("one") == 2 assert child.get("two") == 4 assert child.get("three") == 3 - assert child.get(["undefined", "deeper", "key"]) == "value" + assert child.get(["undefined", "deeper+", "key"]) == "value" def test_merge_plus(self): """ Extending attributes using the '+' suffix """