Skip to content

Instantly share code, notes, and snippets.

@jab
Forked from Daenyth/json_namedtuple.py
Created January 29, 2020 00:04
Show Gist options
  • Save jab/f7532d3a88b39beda9432bd437177c6f to your computer and use it in GitHub Desktop.
Save jab/f7532d3a88b39beda9432bd437177c6f 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