Skip to content

Instantly share code, notes, and snippets.

@Daenyth
Last active February 3, 2020 19:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Daenyth/37d615e502114009d6a33652a814a7c8 to your computer and use it in GitHub Desktop.
Save Daenyth/37d615e502114009d6a33652a814a7c8 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)
@Daenyth
Copy link
Author

Daenyth commented Sep 14, 2018

Credit to @wTheRockb for the original version of this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment