Is it possible to convert each value pair of a dictionary into json and then put them back together as one JSON, I tried doing it as such but it failed and produced weird:
def toj(dict):
j=[]
for k,v in dict.items():
try:
j.append({json.dumps(k):json.dumps(v)})
except:
j.append({json.dumps(k):json.dumps(str(v))})
return j
why do I need it? -->
I need to pass around dictionary instance within my app which is currently using Flask as the web framework (It may change in the future).
from datetime import datetime
dic={'1':One, 2:'Two','list1':[1,2,3],'time_stamp':datetime.now()}
This dictionary is not json convertible as you all would know:
raise TypeError(f'Object of type {o.__class__.__name__} '
f'is not JSON serializable')
TypeError: Object of type datetime is not JSON serializable
Json.dumps acts on the entire object and not each key.So either the whole thing has to be sanitized.
Lucky for me, I I can solve this by converting the offending object into str. but this is not possible because
- I do not know which field will be the offending one as the dictionary is created dynamically and can be any length really
- I can not check for type datetime only because it could be one of many objects which can be of any type but all have str implementd
- I can not convert the whole dict to str as then converting it back to dict causes odd issues.
- JUST fyi For very complicated reasons I can not use any other library than json itself.
- Passing a default does not help, because I can not change the class OF THE object I am passing into dumps and again JSON.dumps takes the whole object not pieces of it
Full-disclosure---> my brain does not digest json easily
CodePudding user response:
you can easily do this with default
keyword of json.dump
def handle_conversion(v):
if isinstace(v,datetime):
return str(v)
elif isinstance(v,some_other_thing_that_cannot_be_jsonified):
return "???" # a value that can be jsonified
return v
data = json.dumps(a_dict_with_datetimes,default=handle_conversion)
if you only need to pass serialized data between python you can use the pickle
module instead which serialized almost anything (but sometimes breaks depending on where you are decoding it)
here is a complete working example
import json
from datetime import datetime
class some_other_thing_that_cannot_be_jsonified:
pass
def handle_conversion(v):
if isinstance(v,datetime):
return str(v)
elif isinstance(v,some_other_thing_that_cannot_be_jsonified):
return "???" # a value that can be jsonified
return v
a_dict_with_datetimes = {
"dt":datetime.now(),"a":"hello","w":"world","L":[1,2,3]
}
data = json.dumps(a_dict_with_datetimes,default=handle_conversion)
print(data)
# {"dt": "2022-10-09 16:21:19.643080", "a": "hello", "w": "world", "q": [1, 2, 3]}
you could simplify it to also just always return str (it only calls default
if it could not jsonify the object), this will cause any object that cannot be jsonified to be converted to str
def handle_conversion(v):
# if isinstance(v,datetime):
# return str(v)
# elif isinstance(v,some_other_thing_that_cannot_be_jsonified):
# return "???" # a value that can be jsonified
return str(v)
CodePudding user response:
from datetime import datetime
def toj(dict):
conversions = {datetime: str}
for k, v in dict.items():
for instance, conv in conversions.items():
if isinstance(v, instance):
dict[k] = conv(v)
return json.dumps(dict)
You can update conversions
according to your requirements.
Execution:
In [1]: d = {'1':'One', 2:'Two','list1':[1,2,3],'time_stamp':datetime.now()}
In [2]: toj(d)
Out[2]: '{"1": "One", "2": "Two", "list1": [1, 2, 3], "time_stamp": "2022-10-10 00:39:00.604636"}'
Edit:
Based on your comment if all have string methods available you can do this.
def toj(dict):
for k, v in dict.items():
try:
json.dumps(v)
except (TypeError, OverflowError):
dict[k] = v.__str__()
return json.dumps(dict)