Skip to content

Instantly share code, notes, and snippets.

@wTheRockb
Forked from Daenyth/json_namedtuple.py
Created February 3, 2020 19:33
Show Gist options
  • Save wTheRockb/c3cbe3b23de15af56939739c0dcab585 to your computer and use it in GitHub Desktop.
Save wTheRockb/c3cbe3b23de15af56939739c0dcab585 to your computer and use it in GitHub Desktop.
Parse json via python NamedTuple
import hashlib
import json
from decimal import Decimal
from typing import Any, Dict, Type
from typing_inspect import get_args, get_generic_bases, is_generic_type, is_union_type # type: ignore
Json = Dict[str, Any]
def json_decoder(nt: Type, data: Json) -> Dict:
"""
Takes a NamedTuple class object and Json, and converts the json into a dict ready to be constructed into the
NamedTuple, or excepts if there is not sufficient data. You can then do `MyNamedTuple(**result)`
"""
decoded = {}
field_types = nt._field_types
for key in field_types:
value = data.get(key)
if value is None:
possible_types = get_args(field_types[key])
if len(possible_types) < 2 or type(None) not in possible_types: # confirm the field is optional
raise ValueError(
"Error decoding Json for {nt}. key '{key}' was 'None' but not listed as optional field.".format(
nt=nt, key=key))
else:
field_type = field_types[key]
if is_generic_type(field_type):
field_type = get_generic_bases(field_type)[0]
elif is_union_type(field_type):
field_type = get_args(field_types[key])[0]
value = field_type(value)
decoded[key] = value
return decoded
def dict_md5(obj: Json) -> str:
# sort_keys=True so that ordering of keys doesn't change the md5 value.
json_obj = json.dumps(obj, sort_keys=True, cls=SmartEncoder).encode('utf-8')
return hashlib.md5(json_obj).hexdigest()
class SmartEncoder(json.JSONEncoder):
def default(self, o: Any) -> Any:
if isinstance(o, set):
return sorted(list(o))
if isinstance(o, Decimal):
return str(o)
return super(SmartEncoder, self).default(o)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment