832 lines
17 KiB
Python
832 lines
17 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from benedict.utils import dict_util as u
|
|
from decimal import Decimal
|
|
|
|
import datetime as dt
|
|
import unittest
|
|
|
|
|
|
class dict_util_test_case(unittest.TestCase):
|
|
|
|
def test_clean(self):
|
|
i = {
|
|
'a': {},
|
|
'b': { 'x': 1 },
|
|
'c': [],
|
|
'd': [0, 1],
|
|
'e': 0.0,
|
|
'f': '',
|
|
'g': None,
|
|
'h': '0'
|
|
}
|
|
|
|
o = i.copy()
|
|
u.clean(o)
|
|
r = {
|
|
'b': { 'x': 1 },
|
|
'd': [0, 1],
|
|
'e': 0.0,
|
|
'h': '0',
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
o = i.copy()
|
|
u.clean(o, dicts=False)
|
|
r = {
|
|
'a': {},
|
|
'b': { 'x': 1 },
|
|
'd': [0, 1],
|
|
'e': 0.0,
|
|
'h': '0'
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
o = i.copy()
|
|
u.clean(o, lists=False)
|
|
r = {
|
|
'b': { 'x': 1 },
|
|
'c': [],
|
|
'd': [0, 1],
|
|
'e': 0.0,
|
|
'h': '0'
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
o = i.copy()
|
|
u.clean(o, strings=False)
|
|
r = {
|
|
'b': { 'x': 1 },
|
|
'd': [0, 1],
|
|
'e': 0.0,
|
|
'f': '',
|
|
'h': '0',
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
def test_clone(self):
|
|
i = {
|
|
'a': {
|
|
'b': {
|
|
'c': 1
|
|
}
|
|
}
|
|
}
|
|
o = u.clone(i)
|
|
self.assertEqual(type(i), type(o))
|
|
self.assertEqual(i, o)
|
|
self.assertFalse(i is o)
|
|
o['a']['b']['c'] = 2
|
|
self.assertEqual(i['a']['b']['c'], 1)
|
|
self.assertEqual(o['a']['b']['c'], 2)
|
|
|
|
def test_dump(self):
|
|
d = {
|
|
'a': {
|
|
'b': {
|
|
'c': 1
|
|
}
|
|
}
|
|
}
|
|
r = """{
|
|
"a": {
|
|
"b": {
|
|
"c": 1
|
|
}
|
|
}
|
|
}"""
|
|
o = u.dump(d)
|
|
self.assertEqual(o, r)
|
|
|
|
def test_dump_with_datetime(self):
|
|
d = {
|
|
'datetime': dt.datetime(2019, 6, 11),
|
|
}
|
|
r = """{
|
|
"datetime": "2019-06-11 00:00:00"
|
|
}"""
|
|
o = u.dump(d)
|
|
self.assertEqual(o, r)
|
|
|
|
def test_dump_with_decimal(self):
|
|
d = {
|
|
'decimal': Decimal('1.75'),
|
|
}
|
|
r = """{
|
|
"decimal": "1.75"
|
|
}"""
|
|
o = u.dump(d)
|
|
self.assertEqual(o, r)
|
|
|
|
def test_filter(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': '4',
|
|
'e': '5',
|
|
'f': 6,
|
|
'g': 7,
|
|
}
|
|
with self.assertRaises(ValueError):
|
|
f = u.filter(i, True)
|
|
o = u.filter(i, lambda key, val: isinstance(val, int))
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'f': 6,
|
|
'g': 7,
|
|
}
|
|
self.assertFalse(i is o)
|
|
self.assertEqual(o, r)
|
|
|
|
def test_flatten(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': {
|
|
'd': {
|
|
'e': 3,
|
|
'f': 4,
|
|
'g': {
|
|
'h': 5,
|
|
}
|
|
}
|
|
},
|
|
}
|
|
o = u.flatten(i)
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c_d_e': 3,
|
|
'c_d_f': 4,
|
|
'c_d_g_h': 5,
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
def test_flatten_with_custom_separator(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': {
|
|
'd': {
|
|
'e': 3,
|
|
'f': 4,
|
|
'g': {
|
|
'h': 5,
|
|
}
|
|
}
|
|
},
|
|
}
|
|
o = u.flatten(i, separator='/')
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c/d/e': 3,
|
|
'c/d/f': 4,
|
|
'c/d/g/h': 5,
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
def test_flatten_with_key_conflict(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': {
|
|
'd': 3,
|
|
},
|
|
'c_d': 4,
|
|
'd_e': 5,
|
|
'd': {
|
|
'e': 6,
|
|
}
|
|
}
|
|
o = u.flatten(i)
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c_d': 4,
|
|
'd_e': 5,
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
def test_invert_with_unique_values(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 4,
|
|
'e': 5,
|
|
}
|
|
o = u.invert(i)
|
|
r = {
|
|
1: ['a'],
|
|
2: ['b'],
|
|
3: ['c'],
|
|
4: ['d'],
|
|
5: ['e'],
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
def test_invert_with_flat_unique_values(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 4,
|
|
'e': 5,
|
|
}
|
|
o = u.invert(i, flat=True)
|
|
r = {
|
|
1: 'a',
|
|
2: 'b',
|
|
3: 'c',
|
|
4: 'd',
|
|
5: 'e',
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
def test_invert_with_multiple_values(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 1,
|
|
'e': 2,
|
|
'f': 3,
|
|
}
|
|
o = u.invert(i)
|
|
self.assertTrue('a' and 'd' in o[1])
|
|
self.assertTrue('b' and 'e' in o[2])
|
|
self.assertTrue('c' and 'f' in o[3])
|
|
|
|
def test_items_sorted_by_keys(self):
|
|
i = {
|
|
'y': 3,
|
|
'a': 6,
|
|
'f': 9,
|
|
'z': 4,
|
|
'x': 1,
|
|
}
|
|
o = u.items_sorted_by_keys(i)
|
|
r = [
|
|
('a', 6,),
|
|
('f', 9,),
|
|
('x', 1,),
|
|
('y', 3,),
|
|
('z', 4,),
|
|
]
|
|
self.assertEqual(o, r)
|
|
|
|
def test_items_sorted_by_keys_reverse(self):
|
|
i = {
|
|
'y': 3,
|
|
'a': 6,
|
|
'f': 9,
|
|
'z': 4,
|
|
'x': 1,
|
|
}
|
|
o = u.items_sorted_by_keys(i, reverse=True)
|
|
r = [
|
|
('z', 4,),
|
|
('y', 3,),
|
|
('x', 1,),
|
|
('f', 9,),
|
|
('a', 6,),
|
|
]
|
|
self.assertEqual(o, r)
|
|
|
|
def test_items_sorted_by_values(self):
|
|
i = {
|
|
'a': 3,
|
|
'b': 6,
|
|
'c': 9,
|
|
'e': 4,
|
|
'd': 1,
|
|
}
|
|
o = u.items_sorted_by_values(i)
|
|
r = [
|
|
('d', 1,),
|
|
('a', 3,),
|
|
('e', 4,),
|
|
('b', 6,),
|
|
('c', 9,),
|
|
]
|
|
self.assertEqual(o, r)
|
|
|
|
def test_items_sorted_by_values_reverse(self):
|
|
i = {
|
|
'a': 3,
|
|
'b': 6,
|
|
'c': 9,
|
|
'e': 4,
|
|
'd': 1,
|
|
}
|
|
o = u.items_sorted_by_values(i, reverse=True)
|
|
r = [
|
|
('c', 9,),
|
|
('b', 6,),
|
|
('e', 4,),
|
|
('a', 3,),
|
|
('d', 1,),
|
|
]
|
|
self.assertEqual(o, r)
|
|
|
|
def test_keypaths(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': {
|
|
'c': {
|
|
'x': 2,
|
|
'y': 3,
|
|
},
|
|
'd': {
|
|
'x': 4,
|
|
'y': 5,
|
|
},
|
|
},
|
|
}
|
|
o = u.keypaths(i)
|
|
r = [
|
|
'a',
|
|
'b',
|
|
'b.c',
|
|
'b.c.x',
|
|
'b.c.y',
|
|
'b.d',
|
|
'b.d.x',
|
|
'b.d.y',
|
|
]
|
|
self.assertEqual(o, r)
|
|
|
|
def test_keypaths_with_custom_separator(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': {
|
|
'c': {
|
|
'x': 2,
|
|
'y': 3,
|
|
},
|
|
'd': {
|
|
'x': 4,
|
|
'y': 5,
|
|
},
|
|
},
|
|
}
|
|
o = u.keypaths(i, separator='/')
|
|
r = [
|
|
'a',
|
|
'b',
|
|
'b/c',
|
|
'b/c/x',
|
|
'b/c/y',
|
|
'b/d',
|
|
'b/d/x',
|
|
'b/d/y',
|
|
]
|
|
self.assertEqual(o, r)
|
|
|
|
def test_keypaths_without_separator(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': {
|
|
'c': {
|
|
'x': 2,
|
|
'y': 3,
|
|
},
|
|
'd': {
|
|
'x': 4,
|
|
'y': 5,
|
|
},
|
|
},
|
|
}
|
|
with self.assertRaises(ValueError):
|
|
o = u.keypaths(i, separator=None)
|
|
|
|
def test_keypaths_with_non_string_keys(self):
|
|
i = {
|
|
True: {
|
|
True: 1,
|
|
},
|
|
False: {
|
|
False: 1,
|
|
},
|
|
None: {
|
|
None: 1,
|
|
},
|
|
}
|
|
o = u.keypaths(i)
|
|
r = [
|
|
'False',
|
|
'False.False',
|
|
'None',
|
|
'None.None',
|
|
'True',
|
|
'True.True',
|
|
]
|
|
self.assertEqual(o, r)
|
|
|
|
def test_merge_with_flatten_dict(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': 1,
|
|
}
|
|
m = {
|
|
'b': 2,
|
|
'c': 3,
|
|
}
|
|
u.merge(d, m)
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_merge_with_multiple_dicts(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': 1,
|
|
}
|
|
a = {
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 3,
|
|
}
|
|
b = {
|
|
'd': 5,
|
|
'e': 5,
|
|
}
|
|
c = {
|
|
'd': 4,
|
|
'f': 6,
|
|
}
|
|
u.merge(d, a, b, c)
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 4,
|
|
'e': 5,
|
|
'f': 6,
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_merge_with_nested_dict(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': {
|
|
'c': {
|
|
'x': 2,
|
|
'y': 3,
|
|
},
|
|
'd': {
|
|
'x': 4,
|
|
'y': 5,
|
|
},
|
|
'e': {
|
|
'x': 6,
|
|
'y': 7,
|
|
},
|
|
},
|
|
}
|
|
m = {
|
|
'a': 0,
|
|
'b': {
|
|
'c': 1,
|
|
'd': {
|
|
'y': 1,
|
|
'z': 2,
|
|
},
|
|
'e': {
|
|
'f': {
|
|
'x': 2,
|
|
'y': 3,
|
|
},
|
|
'g': {
|
|
'x': 4,
|
|
'y': 5,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
u.merge(d, m)
|
|
r = {
|
|
'a': 0,
|
|
'b': {
|
|
'c': 1,
|
|
'd': {
|
|
'x': 4,
|
|
'y': 1,
|
|
'z': 2,
|
|
},
|
|
'e': {
|
|
'f': {
|
|
'x': 2,
|
|
'y': 3,
|
|
},
|
|
'g': {
|
|
'x': 4,
|
|
'y': 5,
|
|
},
|
|
'x': 6,
|
|
'y': 7,
|
|
},
|
|
},
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_move(self):
|
|
d = {
|
|
'a': {
|
|
'x': 1,
|
|
'y': 1,
|
|
},
|
|
'b': {
|
|
'x': 2,
|
|
'y': 2,
|
|
},
|
|
'c': {
|
|
'x': 3,
|
|
'y': 3,
|
|
},
|
|
}
|
|
u.move(d, 'a', 'd')
|
|
r = {
|
|
'b': {
|
|
'x': 2,
|
|
'y': 2,
|
|
},
|
|
'c': {
|
|
'x': 3,
|
|
'y': 3,
|
|
},
|
|
'd': {
|
|
'x': 1,
|
|
'y': 1,
|
|
},
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_move_with_same_key(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': 2,
|
|
}
|
|
u.move(d, 'a', 'a')
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_remove_with_single_key(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
}
|
|
u.remove(d, 'c')
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_remove_with_multiple_keys_as_args(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 4,
|
|
'e': 5,
|
|
}
|
|
u.remove(d, 'c', 'd', 'e')
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_remove_with_multiple_keys_as_list(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 4,
|
|
'e': 5,
|
|
}
|
|
u.remove(d, ['c', 'd', 'e'])
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_standardize(self):
|
|
d = {
|
|
'CamelCase': 1,
|
|
'CamelCamelCase': 1,
|
|
'Camel2Camel2Case': 1,
|
|
'getHTTPResponseCode': 1,
|
|
'get2HTTPResponseCode': 1,
|
|
'HTTPResponseCode': 1,
|
|
'HTTPResponseCodeXYZ': 1,
|
|
' LocationCoordinates ': {
|
|
'Lat. ': 0.0,
|
|
'Lng. ': 0.0,
|
|
},
|
|
}
|
|
u.standardize(d)
|
|
r = {
|
|
'camel_case': 1,
|
|
'camel_camel_case': 1,
|
|
'camel2_camel2_case': 1,
|
|
'get_http_response_code': 1,
|
|
'get2_http_response_code': 1,
|
|
'http_response_code': 1,
|
|
'http_response_code_xyz': 1,
|
|
'location_coordinates': {
|
|
'lat': 0.0,
|
|
'lng': 0.0,
|
|
},
|
|
}
|
|
# print(u.dump(d))
|
|
# print(u.dump(r))
|
|
self.assertEqual(d, r)
|
|
|
|
def test_subset_with_keys_as_args(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 4,
|
|
'e': 5,
|
|
'f': 6,
|
|
}
|
|
o = u.subset(i, 'c', 'f', 'x')
|
|
r = {
|
|
'c': 3,
|
|
'f': 6,
|
|
'x': None,
|
|
}
|
|
self.assertFalse(i is o)
|
|
self.assertEqual(o, r)
|
|
|
|
def test_subset_with_keys_as_list(self):
|
|
i = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
'd': 4,
|
|
'e': 5,
|
|
'f': 6,
|
|
}
|
|
o = u.subset(i, ['c', 'f', 'x'])
|
|
r = {
|
|
'c': 3,
|
|
'f': 6,
|
|
'x': None,
|
|
}
|
|
self.assertFalse(i is o)
|
|
self.assertEqual(o, r)
|
|
|
|
def test_swap(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
}
|
|
u.swap(d, 'a', 'b')
|
|
r = {
|
|
'a': 2,
|
|
'b': 1,
|
|
'c': 3,
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_swap_with_same_key(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': 2,
|
|
}
|
|
u.swap(d, 'a', 'a')
|
|
r = {
|
|
'a': 1,
|
|
'b': 2,
|
|
}
|
|
self.assertEqual(d, r)
|
|
|
|
def test_swap_with_invalid_key(self):
|
|
d = {
|
|
'a': 1,
|
|
'b': 2,
|
|
'c': 3,
|
|
}
|
|
with self.assertRaises(KeyError):
|
|
u.swap(d, 'a', 'd')
|
|
|
|
def test_traverse(self):
|
|
i = {
|
|
'a': {
|
|
'x': 2,
|
|
'y': 3,
|
|
'z': {
|
|
'ok': 5,
|
|
}
|
|
},
|
|
'b': {
|
|
'x': 7,
|
|
'y': 11,
|
|
'z': {
|
|
'ok': 13,
|
|
}
|
|
},
|
|
'c': {
|
|
'x': 17,
|
|
'y': 19,
|
|
'z': {
|
|
'ok': 23,
|
|
}
|
|
},
|
|
}
|
|
o = u.clone(i)
|
|
with self.assertRaises(ValueError):
|
|
u.traverse(o, True)
|
|
def f(parent, key, value):
|
|
if not isinstance(value, dict):
|
|
parent[key] = (value + 1)
|
|
u.traverse(o, f)
|
|
r = {
|
|
'a': {
|
|
'x': 3,
|
|
'y': 4,
|
|
'z': {
|
|
'ok': 6,
|
|
}
|
|
},
|
|
'b': {
|
|
'x': 8,
|
|
'y': 12,
|
|
'z': {
|
|
'ok': 14,
|
|
}
|
|
},
|
|
'c': {
|
|
'x': 18,
|
|
'y': 20,
|
|
'z': {
|
|
'ok': 24,
|
|
}
|
|
},
|
|
}
|
|
self.assertEqual(o, r)
|
|
|
|
def test_unique(self):
|
|
d = {
|
|
'a': {
|
|
'x': 1,
|
|
'y': 1,
|
|
},
|
|
'b': {
|
|
'x': 2,
|
|
'y': 2,
|
|
},
|
|
'c': {
|
|
'x': 1,
|
|
'y': 1,
|
|
},
|
|
'd': {
|
|
'x': 1,
|
|
},
|
|
'e': {
|
|
'x': 1,
|
|
'y': 1,
|
|
'z': 1,
|
|
},
|
|
'f': {
|
|
'x': 2,
|
|
'y': 2,
|
|
},
|
|
}
|
|
u.unique(d)
|
|
rv = [
|
|
{
|
|
'x': 1,
|
|
'y': 1,
|
|
},
|
|
{
|
|
'x': 2,
|
|
'y': 2,
|
|
},
|
|
{
|
|
'x': 1,
|
|
},
|
|
{
|
|
'x': 1,
|
|
'y': 1,
|
|
'z': 1,
|
|
},
|
|
]
|
|
self.assertEqual(len(d.keys()), len(rv))
|
|
self.assertTrue(all([value in rv for value in d.values()]))
|