Last active
February 3, 2020 19:33
-
-
Save Daenyth/37d615e502114009d6a33652a814a7c8 to your computer and use it in GitHub Desktop.
Parse json via python NamedTuple
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
Credit to @wTheRockb for the original version of this