Skip to content

Commit

Permalink
Fix merge when parent is a dict and child is a list
Browse files Browse the repository at this point in the history
  • Loading branch information
psss committed Nov 29, 2024
1 parent f4950f4 commit e2b9c19
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 3 deletions.
3 changes: 3 additions & 0 deletions examples/merge/parent-dict.fmf
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
discover:
how: fmf
summary: test.

/path:
discover+:
- name: upstream
url: https://some.url
summary+: upstream
- name: downstream
url: https://other.url
summary+: downstream
4 changes: 4 additions & 0 deletions examples/merge/parent-list.fmf
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
discover:
- how: fmf
url: https://github.com/project1
summary: project1.
- how: fmf
url: https://github.com/project2
summary: project2.

/tier1:
summary: basic tests
discover+:
filter: "tier: 1"
summary+: tier1

/tier2:
summary: detailed tests
discover+:
filter: "tier: 2"
summary+: tier2
14 changes: 11 additions & 3 deletions fmf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ def _merge_plus(self, data, key, value, prepend=False):
data[key] = value
return

# Special handling for merging lists with dictionary
# Parent is a list of dict and child is a dict
# (just update every parent list item using the special merge)
if isinstance(data[key], list) and isinstance(value, dict):
for list_item in data[key]:
if not isinstance(list_item, dict):
Expand All @@ -187,20 +188,27 @@ def _merge_plus(self, data, key, value, prepend=False):
list_item, self.name))
self._merge_special(list_item, value)
return

# Parent is a dict and child is a list of dict
# (replace parent dict with the list of its special-merged copies)
if isinstance(data[key], dict) and isinstance(value, list):
result_list = []
for list_item in value:
if not isinstance(list_item, dict):
raise utils.MergeError(
"MergeError: Item '{0}' in {1} must be a dictionary.".format(
list_item, self.name))
self._merge_special(list_item, data[key])
data[key] = value
result_dict = copy.deepcopy(data[key])
self._merge_special(result_dict, list_item)
result_list.append(result_dict)
data[key] = result_list
return

# Use the special merge for merging dictionaries
if type(data[key]) == type(value) == dict:
self._merge_special(data[key], value)
return

# Attempt to apply the plus operator
try:
if prepend:
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,22 +160,32 @@ def test_merge_plus(self):
with pytest.raises(utils.MergeError):
child.data["time+"] = "string"
child.inherit()

def test_merge_plus_parent_dict(self):
""" Merging parent dict with child list """
child = self.merge.find('/parent-dict/path')
assert len(child.data['discover']) == 2
assert child.data['discover'][0]['how'] == 'fmf'
assert child.data['discover'][0]['name'] == 'upstream'
assert child.data['discover'][0]['url'] == 'https://some.url'
assert child.data['discover'][0]['summary'] == 'test.upstream'
assert child.data['discover'][1]['how'] == 'fmf'
assert child.data['discover'][1]['name'] == 'downstream'
assert child.data['discover'][1]['url'] == 'https://other.url'
assert child.data['discover'][1]['summary'] == 'test.downstream'

def test_merge_plus_parent_list(self):
""" Merging parent list with child dict """
for i in [1, 2]:
child = self.merge.find(f'/parent-list/tier{i}')
assert child.data['summary'] == 'basic tests' if i == 1 else 'detailed tests'
assert len(child.data['discover']) == 2
assert child.data['discover'][0]['filter'] == f'tier: {i}'
assert child.data['discover'][0]['url'] == 'https://github.com/project1'
assert child.data['discover'][0]['summary'] == f'project1.tier{i}'
assert child.data['discover'][1]['filter'] == f'tier: {i}'
assert child.data['discover'][1]['url'] == 'https://github.com/project2'
assert child.data['discover'][1]['summary'] == f'project2.tier{i}'

def test_merge_minus(self):
""" Reducing attributes using the '-' suffix """
Expand Down

0 comments on commit e2b9c19

Please sign in to comment.