Skip to content

Commit ab1d45a

Browse files
committed
Fix clean method not working on nested dicts. #383
1 parent 72afe88 commit ab1d45a

File tree

2 files changed

+140
-13
lines changed

2 files changed

+140
-13
lines changed

benedict/core/clean.py

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,55 @@
1-
from benedict.utils import type_util
1+
def _clean_dict(d, strings, collections):
2+
keys = list(d.keys())
3+
for key in keys:
4+
d[key] = _clean_value(d[key], strings=strings, collections=collections)
5+
if d[key] is None:
6+
del d[key]
7+
return d
8+
9+
10+
def _clean_list(ls, strings, collections):
11+
for i in range(len(ls) - 1, -1, -1):
12+
ls[i] = _clean_value(ls[i], strings=strings, collections=collections)
13+
if ls[i] is None:
14+
ls.pop(i)
15+
return ls
16+
17+
18+
def _clean_set(values, strings, collections):
19+
return {
20+
value
21+
for value in values
22+
if _clean_value(value, strings=strings, collections=collections) is not None
23+
}
224

325

4-
def _clean_item(d, key, strings, collections):
5-
value = d.get(key, None)
6-
if not value:
7-
del_none = value is None
8-
del_string = strings and type_util.is_string(value)
9-
del_collection = collections and type_util.is_collection(value)
10-
return any([del_none, del_string, del_collection])
26+
def _clean_str(s, strings, collections):
27+
return s if s and s.strip() else None
1128

12-
return False
29+
30+
def _clean_tuple(values, strings, collections):
31+
return tuple(
32+
value
33+
for value in values
34+
if _clean_value(value, strings=strings, collections=collections) is not None
35+
)
36+
37+
38+
def _clean_value(value, strings, collections):
39+
if value is None:
40+
return value
41+
elif isinstance(value, list) and collections:
42+
value = _clean_list(value, strings=strings, collections=collections) or None
43+
elif isinstance(value, dict) and collections:
44+
value = _clean_dict(value, strings=strings, collections=collections) or None
45+
elif isinstance(value, set) and collections:
46+
value = _clean_set(value, strings=strings, collections=collections) or None
47+
elif isinstance(value, str) and strings:
48+
value = _clean_str(value, strings=strings, collections=collections) or None
49+
elif isinstance(value, tuple) and collections:
50+
value = _clean_tuple(value, strings=strings, collections=collections) or None
51+
return value
1352

1453

1554
def clean(d, strings=True, collections=True):
16-
keys = list(d.keys())
17-
for key in keys:
18-
if _clean_item(d, key, strings, collections):
19-
del d[key]
55+
return _clean_dict(d, strings=strings, collections=collections)

tests/core/test_clean.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ def test_clean(self):
1818
"f": "",
1919
"g": None,
2020
"h": "0",
21+
"i": (1, None, 2, 3, " "),
22+
"j": {1, None, 2, 3, " "},
2123
}
2224

2325
o = i.copy()
@@ -27,6 +29,8 @@ def test_clean(self):
2729
"d": [0, 1],
2830
"e": 0.0,
2931
"h": "0",
32+
"i": (1, 2, 3),
33+
"j": {1, 2, 3},
3034
}
3135
self.assertEqual(o, r)
3236

@@ -39,6 +43,8 @@ def test_clean(self):
3943
"d": [0, 1],
4044
"e": 0.0,
4145
"h": "0",
46+
"i": (1, None, 2, 3, " "),
47+
"j": {1, None, 2, 3, " "},
4248
}
4349
self.assertEqual(o, r)
4450

@@ -50,5 +56,90 @@ def test_clean(self):
5056
"e": 0.0,
5157
"f": "",
5258
"h": "0",
59+
"i": (1, 2, 3, " "),
60+
"j": {1, 2, 3, " "},
5361
}
5462
self.assertEqual(o, r)
63+
64+
def test_clean_nested_dicts(self):
65+
# https://github.com/fabiocaccamo/python-benedict/issues/383
66+
d = {
67+
"a": {
68+
"b": {
69+
"c": {},
70+
},
71+
},
72+
}
73+
_clean(d, collections=True)
74+
r = {}
75+
self.assertEqual(d, r)
76+
77+
d = {
78+
"a": {
79+
"b": {
80+
"c": {},
81+
},
82+
"d": 1,
83+
},
84+
}
85+
_clean(d, collections=True)
86+
r = {
87+
"a": {
88+
"d": 1,
89+
},
90+
}
91+
self.assertEqual(d, r)
92+
93+
d = {
94+
"a": {
95+
"b": [
96+
0,
97+
1,
98+
2,
99+
3,
100+
{},
101+
{
102+
"c": [None, 4, None, 5],
103+
},
104+
],
105+
},
106+
}
107+
_clean(d, collections=True)
108+
r = {
109+
"a": {
110+
"b": [
111+
0,
112+
1,
113+
2,
114+
3,
115+
{
116+
"c": [4, 5],
117+
},
118+
],
119+
},
120+
}
121+
self.assertEqual(d, r)
122+
123+
d = {
124+
"a": {
125+
"b": [
126+
(None, None, None),
127+
(None, 1, 2),
128+
{3, None, 4},
129+
{5, 6, None},
130+
],
131+
"c": (None, None),
132+
"d": {None},
133+
},
134+
}
135+
_clean(d, collections=True)
136+
r = {
137+
"a": {
138+
"b": [
139+
(1, 2),
140+
{3, 4},
141+
{5, 6},
142+
],
143+
},
144+
}
145+
self.assertEqual(d, r)

0 commit comments

Comments
 (0)