Skip to content

Commit

Permalink
merge_dict now returns a copy of all the elements #26
Browse files Browse the repository at this point in the history
Data structures passed as parameters are not modified.

Closes #26
  • Loading branch information
nemesifier committed Nov 2, 2015
1 parent d71a72c commit cd4b217
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 8 deletions.
17 changes: 9 additions & 8 deletions netjsonconfig/utils.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
from collections import OrderedDict
from copy import deepcopy


def merge_config(template, config):
"""
merge two dicts `template` and `config`
values of `config` are merged in values present in `template`
lists present in `config` will be added to lists in `template`
returns merged dict
"""
result = template.copy()
for key, value in config.items():
if isinstance(value, dict):
# get node or create one
node = template.setdefault(key, {})
merge_config(node, value)
elif isinstance(value, list) and isinstance(template.get(key), list):
template[key] += value
node = result.get(key, {})
result[key] = merge_config(node, value)
elif isinstance(value, list) and isinstance(result.get(key), list):
result[key] = deepcopy(result[key]) + deepcopy(value)
else:
template[key] = value

return template
result[key] = value
return result


def sorted_dict(dictionary):
Expand Down
61 changes: 61 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,64 @@ def test_merge_config_list(self):
"element2"
]
})

def test_merge_originals_unchanged(self):
template = {
"str": "original",
"dict": {"a": "a"},
"list": ["element1"]
}
config = {
"str": "changed",
"dict": {"b": "b"},
"list": ["element2"]
}
result = merge_config(template, config)
# ensure original structures not changed
self.assertEqual(template, {
"str": "original",
"dict": {"a": "a"},
"list": ["element1"]
})
self.assertEqual(config, {
"str": "changed",
"dict": {"b": "b"},
"list": ["element2"]
})

def test_merge_list_of_dicts_unchanged(self):
template = {
"list": [
{"a": "original"},
{"b": "original"}
]
}
config = {
"list": [
{"c": "original"}
]
}
result = merge_config(template, config)
template['list'][0]['a'] = 'changed'
config['list'][0]['c'] = 'changed'
result['list'][1]['b'] = 'changed'
# ensure originals changed
# but not result of merge
self.assertEqual(template, {
"list": [
{"a": "changed"},
{"b": "original"}
]
})
self.assertEqual(config, {
"list": [
{"c": "changed"}
]
})
self.assertEqual(result, {
"list": [
{"a": "original"},
{"b": "changed"},
{"c": "original"}
]
})

0 comments on commit cd4b217

Please sign in to comment.