From 8bb34c604b7796d04999e5cb979c9dbb83775d43 Mon Sep 17 00:00:00 2001 From: Anders Ingemann Date: Sat, 20 Dec 2014 23:18:27 +0100 Subject: [PATCH] Fix serious bug in merge_dicts where the original dict would be modified --- tests/integration/manifests/__init__.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/integration/manifests/__init__.py b/tests/integration/manifests/__init__.py index 4eb6dfa..615e3e5 100644 --- a/tests/integration/manifests/__init__.py +++ b/tests/integration/manifests/__init__.py @@ -29,9 +29,21 @@ def merge_manifest_data(standard_partials=[], custom=[]): # Snatched from here: http://stackoverflow.com/a/7205107 def merge_dicts(*args): - def merge(a, b, path=None): - if path is None: - path = [] + def clone(obj): + copy = obj + if isinstance(obj, dict): + copy = {} + for key, value in obj.iteritems(): + copy[key] = clone(value) + if isinstance(obj, list): + copy = [] + copy.extend(obj) + if isinstance(obj, set): + copy = set() + copy.update(obj) + return copy + + def merge(a, b, path=[]): for key in b: if key in a: if isinstance(a[key], dict) and isinstance(b[key], dict): @@ -39,8 +51,8 @@ def merge_dicts(*args): elif a[key] == b[key]: pass else: - raise Exception('Conflict at %s' % '.'.join(path + [str(key)])) + raise Exception('Conflict at `{path}\''.format(path='.'.join(path + [str(key)]))) else: - a[key] = b[key] + a[key] = clone(b[key]) return a return reduce(merge, args, {})