From 2f50c30ea6cd7617a0c02a9325f1604717febdb0 Mon Sep 17 00:00:00 2001 From: Fabio Caccamo Date: Mon, 7 Oct 2019 12:03:01 +0200 Subject: [PATCH] Moved all utilities to dict_util. --- benedict/dicts/__init__.py | 32 ++++------------------- benedict/utils/dict_util.py | 51 +++++++++++++++++++++++++++++-------- tests/test_benedict.py | 8 ++++++ 3 files changed, 53 insertions(+), 38 deletions(-) diff --git a/benedict/dicts/__init__.py b/benedict/dicts/__init__.py index 89dc640..22340fc 100644 --- a/benedict/dicts/__init__.py +++ b/benedict/dicts/__init__.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- -from six import string_types - from benedict.dicts.io import IODict from benedict.dicts.keypath import KeypathDict from benedict.dicts.parse import ParseDict @@ -25,7 +23,6 @@ class benedict(IODict, KeypathDict, ParseDict): def clean(self, strings=True, dicts=True, lists=True): dict_util.clean(self, strings=strings, dicts=dicts, lists=lists) - @benediction def clone(self): return dict_util.clone(self) @@ -42,11 +39,9 @@ class benedict(IODict, KeypathDict, ParseDict): def dump(self, data=None): return dict_util.dump(data or self) - @benediction def filter(self, predicate): return dict_util.filter(self, predicate) - @benediction def flatten(self, separator='_'): return dict_util.flatten(self, separator) @@ -80,7 +75,6 @@ class benedict(IODict, KeypathDict, ParseDict): def from_yaml(s, **kwargs): return IODict.from_yaml(s, **kwargs) - @benediction def invert(self, flat=False): return dict_util.invert(self, flat) @@ -91,32 +85,16 @@ class benedict(IODict, KeypathDict, ParseDict): return dict_util.items_sorted_by_values(self, reverse=reverse) def merge(self, other, *args): - dicts = [other] + list(args) - for d in dicts: - dict_util.merge(self, d) + dict_util.merge(self, other, *args) def move(self, key_src, key_dest): - self[key_dest] = self.pop(key_src) + dict_util.move(self, key_src, key_dest) def remove(self, keys, *args): - if isinstance(keys, string_types): - keys = [keys] - keys += args - for key in keys: - try: - del self[key] - except KeyError: - continue + dict_util.remove(self, keys, *args) - @benediction def subset(self, keys, *args): - d = self.__class__() - if isinstance(keys, string_types): - keys = [keys] - keys += args - for key in keys: - d[key] = self.get(key, None) - return d + return dict_util.subset(self, keys, *args) def swap(self, key1, key2): - self[key1], self[key2] = self[key2], self[key1] + dict_util.swap(self, key1, key2) diff --git a/benedict/utils/dict_util.py b/benedict/utils/dict_util.py index 44eaa81..9264cbb 100644 --- a/benedict/utils/dict_util.py +++ b/benedict/utils/dict_util.py @@ -31,7 +31,7 @@ def dump(data): def flatten(d, separator='_', base=''): - new_dict = {} + new_dict = d.__class__() keys = sorted(d.keys()) for key in keys: value = d.get(key) @@ -46,7 +46,7 @@ def flatten(d, separator='_', base=''): def filter(d, predicate): if not callable(predicate): raise ValueError('predicate argument must be a callable.') - new_dict = {} + new_dict = d.__class__() keys = d.keys() for key in keys: value = d.get(key, None) @@ -56,10 +56,11 @@ def filter(d, predicate): def invert(d, flat=False): + new_dict = d.__class__() if flat: - new_dict = { value:key for key, value in d.items() } + for key, value in d.items(): + new_dict.setdefault(value, key) else: - new_dict = {} for key, value in d.items(): new_dict.setdefault(value, []).append(key) return new_dict @@ -73,11 +74,39 @@ def items_sorted_by_values(d, reverse=False): return sorted(d.items(), key=lambda item: item[1], reverse=reverse) -def merge(d, other): - for key, value in other.copy().items(): - src = d.get(key, None) - if isinstance(src, dict) and isinstance(value, dict): - merge(src, value) - else: - d[key] = value +def merge(d, other, *args): + others = [other] + list(args) + for other in others: + for key, value in other.items(): + src = d.get(key, None) + if isinstance(src, dict) and isinstance(value, dict): + merge(src, value) + else: + d[key] = value return d + + +def move(d, key_src, key_dest): + d[key_dest] = d.pop(key_src) + + +def remove(d, keys, *args): + if isinstance(keys, string_types): + keys = [keys] + keys += args + for key in keys: + d.pop(key, None) + + +def subset(d, keys, *args): + new_dict = d.__class__() + if isinstance(keys, string_types): + keys = [keys] + keys += args + for key in keys: + new_dict[key] = d.get(key, None) + return new_dict + + +def swap(d, key1, key2): + d[key1], d[key2] = d[key2], d[key1] diff --git a/tests/test_benedict.py b/tests/test_benedict.py index 4feab54..19afff9 100644 --- a/tests/test_benedict.py +++ b/tests/test_benedict.py @@ -73,6 +73,8 @@ class BenedictTestCase(unittest.TestCase): } b = benedict(d) c = b.clone() + self.assertEqual(type(b), type(c)) + self.assertTrue(isinstance(c, benedict)) self.assertEqual(b, c) self.assertFalse(c is b) c['a']['b']['c'] = 2 @@ -90,6 +92,7 @@ class BenedictTestCase(unittest.TestCase): b = benedict(d) c = b.copy() self.assertEqual(type(b), type(c)) + self.assertTrue(isinstance(c, benedict)) self.assertEqual(b, c) self.assertFalse(c is b) c['a.b.c'] = 2 @@ -288,6 +291,8 @@ class BenedictTestCase(unittest.TestCase): 'f': 6, 'g': 7, } + self.assertEqual(type(b), type(f)) + self.assertTrue(isinstance(f, benedict)) self.assertEqual(f, r) self.assertFalse(b is f) @@ -352,6 +357,7 @@ class BenedictTestCase(unittest.TestCase): 'c_d_g_h': 5, } self.assertEqual(f, r) + self.assertEqual(type(b), type(f)) self.assertTrue(isinstance(f, benedict)) def test_flatten_with_custom_separator(self): @@ -1057,6 +1063,8 @@ class BenedictTestCase(unittest.TestCase): } self.assertEqual(f, r) self.assertFalse(f is b) + self.assertEqual(type(b), type(f)) + self.assertTrue(isinstance(f, benedict)) def test_subset_with_keys_args(self): d = {