PK!v@2??deserialize/__init__.py"""A module for deserializing data to Python objects.""" #pylint: disable=unidiomatic-typecheck #pylint: disable=protected-access #pylint: disable=too-many-branches #pylint: disable=wildcard-import import enum import functools import typing from typing import Any, Callable, Dict, List, Optional, Union from deserialize.decorators import ignore, _should_ignore, key, _get_key, parser, _get_parser from deserialize.exceptions import DeserializeException, InvalidBaseTypeException from deserialize.type_checks import * def deserialize(class_reference, data): """Deserialize data to a Python object.""" if not isinstance(data, dict) and not isinstance(data, list): raise InvalidBaseTypeException("Only lists and dictionaries are supported as base raw data types") try: name = class_reference.__name__ except AttributeError: name = str(class_reference) return _deserialize(class_reference, data, name) def _deserialize(class_reference, data, debug_name): """Deserialize data to a Python object, but allow base types""" if is_union(class_reference): valid_types = union_types(class_reference) for valid_type in valid_types: try: return _deserialize(valid_type, data, debug_name) except: pass if isinstance(data, dict): return _deserialize_dict(class_reference, data, debug_name) if isinstance(data, list): return _deserialize_list(class_reference, data, debug_name) if not is_typing_type(class_reference) and issubclass(class_reference, enum.Enum): try: return class_reference(data) #pylint:disable=bare-except except: #pylint:enable=bare-except # This will be handled at the end pass # If we still have a type from the typing module, we don't know how to # handle it if is_typing_type(class_reference): raise DeserializeException(f"Unsupported deserialization type: {class_reference}") # Whatever we have left now is either correct, or invalid if isinstance(data, class_reference): return data raise DeserializeException(f"Cannot deserialize '{type(data)}' to '{class_reference}' for '{debug_name}'") def _deserialize_list(class_reference, list_data, debug_name): if not isinstance(list_data, list): raise DeserializeException(f"Cannot deserialize '{type(list_data)}' as a list.") if not is_list(class_reference): raise DeserializeException(f"Cannot deserialize a list to '{class_reference}'") list_content_type_value = list_content_type(class_reference) output = [] for index, item in enumerate(list_data): deserialized = _deserialize(list_content_type_value, item, f"{debug_name}[{index}]") output.append(deserialized) return output def _deserialize_dict(class_reference, data, debug_name): """Deserialize a dictionary to a Python object.""" # Check if we are doing a straightforward dictionary parse first, or if it # has to be deserialized if is_dict(class_reference): key_type, value_type = dict_content_types(class_reference) result = {} for dict_key, dict_value in data.items(): if not isinstance(dict_key, key_type): raise DeserializeException(f"Could not deserialize key {dict_key} to type {key_type} for {debug_name}") result[dict_key] = _deserialize(value_type, dict_value, f"{debug_name}.{dict_key}") return result # It wasn't a straight forward dictionary, so we are in deserialize mode hints = typing.get_type_hints(class_reference) if len(hints) == 0: raise DeserializeException(f"Could not deserialize {data} into {class_reference} due to lack of type hints") class_instance = class_reference() for attribute_name, attribute_type in hints.items(): if _should_ignore(class_reference, attribute_name): continue property_key = _get_key(class_reference, attribute_name) parser_function = _get_parser(class_reference, property_key) property_value = parser_function(data.get(property_key)) deserialized_value = _deserialize(attribute_type, property_value, f"{debug_name}.{attribute_name}") setattr(class_instance, attribute_name, deserialized_value) return class_instance PK!ŀ deserialize/decorators.py"""Decorators used for adding functionality to the library.""" def ignore(property_name): """A decorator function for marking keys as those which should be ignored.""" def store_key_map(class_reference): """Store the key map.""" try: _ = class_reference.__deserialize_ignore_map__ except AttributeError: setattr(class_reference, "__deserialize_ignore_map__", {}) class_reference.__deserialize_ignore_map__[property_name] = True return class_reference return store_key_map def _should_ignore(class_reference, property_name): """Check if a property should be ignored.""" try: return class_reference.__deserialize_ignore_map__.get(property_name, False) except AttributeError: return False def key(property_name, key_name): """A decorator function for mapping key names to properties.""" def store_key_map(class_reference): """Store the key map.""" try: _ = class_reference.__deserialize_key_map__ except AttributeError: setattr(class_reference, "__deserialize_key_map__", {}) class_reference.__deserialize_key_map__[property_name] = key_name return class_reference return store_key_map def _get_key(class_reference, property_name): """Get the key for the given class and property name.""" try: return class_reference.__deserialize_key_map__.get(property_name, property_name) except AttributeError: return property_name def parser(key_name, parser_function): """A decorator function for mapping parsers to key names.""" def store_parser_map(class_reference): """Store the parser map.""" try: _ = class_reference.__deserialize_parser_map__ except AttributeError: setattr(class_reference, "__deserialize_parser_map__", {}) class_reference.__deserialize_parser_map__[key_name] = parser_function return class_reference return store_parser_map def _get_parser(class_reference, key_name): """Get the parser for the given class and keu name.""" def identity_parser(value): """This parser does nothing. It's simply used as the default.""" return value try: return class_reference.__deserialize_parser_map__.get(key_name, identity_parser) except AttributeError: return identity_parser PK!5r&&deserialize/exceptions.py"""Module for all exceptions used in the library.""" class DeserializeException(Exception): """Represents an error deserializing a value.""" pass class InvalidBaseTypeException(DeserializeException): """An error where the "base" type to be deserialized was invalid.""" pass PK!cӅ deserialize/type_checks.py"""Convenience checks for typing.""" import sys import typing import deserialize.exceptions #pylint: disable=protected-access def is_typing_type(class_reference): """Check if the supplied type is one defined by the `typing` module. This behaves differently on 3.6 and 3.7+ """ if sys.version_info < (3, 7): # Union/Optional is a special case since it doesn't inherit. try: if class_reference.__origin__ == typing.Union: return True except: # Not everything has the __origin__ member pass if isinstance(class_reference, typing._TypeAlias): return True return isinstance(class_reference, typing.GenericMeta) return isinstance(class_reference, typing._GenericAlias) def is_union(type_value): """Check if a type is an optional type.""" if not is_typing_type(type_value): return False return type_value.__origin__ == typing.Union def union_types(type_value): """Return the list of types in a Union.""" if not is_union(type_value): raise deserialize.exceptions.DeserializeException(f"Cannot extract union types from non-union type: {type_value}") return list(type_value.__args__) def is_list(type_value): """Check if a type is a list type.""" if not is_typing_type(type_value): return False try: if sys.version_info < (3, 7): return type_value.__origin__ == typing.List return type_value.__origin__ == list except AttributeError: return False def list_content_type(type_value): """Strip the List wrapper from a type. e.g. List[int] -> int """ if not is_list(type_value): raise TypeError(f"{type_value} is not a List type") return type_value.__args__[0] def is_dict(type_value): """Check if a type is a dict type.""" if not is_typing_type(type_value): return False try: if sys.version_info < (3, 7): return type_value.__origin__ == typing.Dict return type_value.__origin__ == dict except AttributeError: return False def dict_content_types(type_value): """Return the content types for a dictionay. e.g. Dict[str, int] -> (str, int) """ if not is_dict(type_value): raise TypeError(f"{type_value} is not a Dict type") return type_value.__args__[0], type_value.__args__[1] PK!WI::$deserialize-0.10.0.dist-info/LICENSEMIT License Copyright (c) Dale Myers. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWAREPK!HnHTU"deserialize-0.10.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!H3%deserialize-0.10.0.dist-info/METADATAWn6}WLYNI %qwKJRl{ϐV8ERL ztN*]NRTrN(Q?e4ܹ܎.ڪf;3*UfHNS%pBRm=ӕɕF*U蹨W-!'ɍKݨ_\#' s%m\olUNmHy"mnTp8~9r:N~v'U7uݚ:F"ZIG dӧ:2mMiR5^Xu Sn3!娵,d0֑[xLjI[F 5u}-GQ_@N3<_Gܣ{k ,Э~Bx~/Ƹ8c \bj2&Sv4oA$GTvu1]]-1gk3R+עl% o~kB)$צ,Եܙ#\z!JDGd Miʾα#qX/ܨ4> J+F=*z> |f^0~PluzqG.GhUU=#yii˵p'thh73{ HfVpR ̯Y\XNXfe>6#a{z 1zߘ Tq-4[__Y2'% 2S.`T| V" &aK9kiBʆrLG K򳨚RƾܬqPn _گ+֙Ai.uʕ#YU`RtkyvCg5ö^zb/r aCX$Q'CKida]K,tRBdTnVL8d.01t-Y̶  <'ӂkHhӂN0^-أ #KmǣqCzvALwdB+IP@M'}o0u [Xu{legԃ36Z#XDzso&czOUrD(h89#o*~CºL 0łAyQ6  rcۦ)`%wH`9qZn/;mM-bNѱ~%Akf;&/r1 @Kh_ͭ'a&,2rxٵҭWnUf >a{ JtH#fm 顸*PK!Humݑ#deserialize-0.10.0.dist-info/RECORD}r@@}4.@02i 4/ofG]łh!7L_ `55`xhr-pKϜV cy6I طle.pׯD! -8üL@