Trying to convert dictionary object with keys of type bytes to json using json.dumps(). Format of dictionary object is not known beforehand. Have found solution for arrays or dictionaries with byte values when using json.dumps (Convert bytes embedded in list (or dict) to str for use with json.dumps) but have not found one for byte keys.
JavaScript
x
14
14
1
import json
2
3
class BytesDump(json.JSONEncoder):
4
def default(self, obj):
5
if isinstance(obj, bytes):
6
return obj.decode()
7
return json.JSONEncoder.default(self, obj)
8
9
foo = {'name': b'bob', 'age': 33, 'attributes': {'hair': b'brown', 'arms': 2}}
10
bar = {b'name': b'bob', b'age': 33, b'attributes': {b'hair': b'brown', b'arms': 2}}
11
12
print(json.dumps(foo, cls=BytesDump)) # this works
13
print(json.dumps(bar, cls=BytesDump)) # this doesn't work
14
Output from above
JavaScript
1
12
12
1
{"name": "bob", "age": 33, "attributes": {"hair": "brown", "arms": 2}}
2
Traceback (most recent call last):
3
File "./test.py", line 15, in <module>
4
print(json.dumps(bar, cls=BytesDump))
5
File "/usr/local/lib/python3.6/json/__init__.py", line 238, in dumps
6
**kw).encode(obj)
7
File "/usr/local/lib/python3.6/json/encoder.py", line 199, in encode
8
chunks = self.iterencode(o, _one_shot=True)
9
File "/usr/local/lib/python3.6/json/encoder.py", line 257, in iterencode
10
return _iterencode(o, 0)
11
TypeError: keys must be a string
12
Advertisement
Answer
you could pre-process the dictionary to convert the keys as strings recursively if they’re bytes
JavaScript
1
30
30
1
import json
2
# your dump code for values, unmodified
3
class BytesDump(json.JSONEncoder):
4
def default(self, obj):
5
if isinstance(obj, bytes):
6
return obj.decode()
7
return json.JSONEncoder.default(self, obj)
8
9
# recursive key as string conversion for byte keys
10
def keys_string(d):
11
rval = {}
12
if not isinstance(d, dict):
13
if isinstance(d,(tuple,list,set)):
14
v = [keys_string(x) for x in d]
15
return v
16
else:
17
return d
18
19
for k,v in d.items():
20
if isinstance(k,bytes):
21
k = k.decode()
22
if isinstance(v,dict):
23
v = keys_string(v)
24
elif isinstance(v,(tuple,list,set)):
25
v = [keys_string(x) for x in v]
26
rval[k] = v
27
return rval
28
29
print(json.dumps(keys_string(bar), cls=BytesDump))
30
with:
JavaScript
1
3
1
bar = {b'name': b'bob', b'age': 33, b'attributes': {b'hair': b'brown', b'arms': 2},
2
b'other': [{b'hair': b'brown', b'arms': 2}]}
3
prints:
JavaScript
1
2
1
{"attributes": {"hair": "brown", "arms": 2}, "age": 33, "name": "bob", "other": [{"hair": "brown", "arms": 2}]}
2