def get(self, obj_type, parent_class, name_in_parent) -> Parser: if obj_type in BASIC_TYPES: return BasicParserWithCast(obj_type) if obj_type in EXTRA_TYPES: return BasicParser() if obj_type in DATE_TYPES: return DateParser(parent_class, obj_type) if obj_type is Decimal: return DecimalParser() if type(obj_type) is str or type(obj_type) is ForwardRef: return UnresolvedParser(TypeProvider(parent_class, obj_type), self.model_provider) if obj_type is list: type_info = get_cls_attr(parent_class, PYCKSON_TYPEINFO, dict()) if name_in_parent in type_info: sub_type = type_info[name_in_parent] return ListParser( self.get(sub_type, parent_class, name_in_parent)) else: raise TypeError( 'list parameter {} in class {} has no subType'.format( name_in_parent, parent_class.__name__)) if obj_type is set: type_info = get_cls_attr(parent_class, PYCKSON_TYPEINFO, dict()) if name_in_parent in type_info: sub_type = type_info[name_in_parent] return SetParser( self.get(sub_type, parent_class, name_in_parent)) else: raise TypeError( 'set parameter {} in class {} has no subType'.format( name_in_parent, parent_class.__name__)) if is_list_annotation(obj_type): return ListParser( self.get(obj_type.__args__[0], parent_class, name_in_parent)) if is_set_annotation(obj_type): return SetParser( self.get(obj_type.__args__[0], parent_class, name_in_parent)) if is_enum_annotation(obj_type): options = get_cls_attr(obj_type, PYCKSON_ENUM_OPTIONS, {}) if options.get(ENUM_CASE_INSENSITIVE, False): return CaseInsensitiveEnumParser(obj_type) else: return DefaultEnumParser(obj_type) if is_basic_dict_annotation(obj_type): return BasicDictParser() if is_typing_dict_annotation(obj_type): if obj_type.__args__[0] != str: raise TypeError( 'typing.Dict key can only be str in class {}'.format( parent_class)) return TypingDictParser( self.get(obj_type.__args__[1], parent_class, name_in_parent)) if has_cls_attr(obj_type, PYCKSON_PARSER): return CustomDeferredParser(obj_type) return ClassParser(obj_type, self.model_provider)
def get(self, obj_type, parent_class, name_in_parent) -> Serializer: if obj_type in BASIC_TYPES or obj_type in EXTRA_TYPES: return BasicSerializer() if obj_type in DATE_TYPES: return DateSerializer(parent_class, obj_type) if obj_type is Decimal: return DecimalSerializer() if type(obj_type) is str or type(obj_type) is ForwardRef: return GenericSerializer(self.model_provider) if obj_type is list or obj_type is set: type_info = get_cls_attr(parent_class, PYCKSON_TYPEINFO, dict()) if name_in_parent in type_info: sub_type = type_info[name_in_parent] return ListSerializer(self.get(sub_type, parent_class, name_in_parent)) else: raise TypeError('list parameter {} in class {} has no subType'.format(name_in_parent, parent_class.__name__)) if is_list_annotation(obj_type) or is_set_annotation(obj_type): return ListSerializer(self.get(obj_type.__args__[0], parent_class, name_in_parent)) if is_enum_annotation(obj_type): return EnumSerializer() if is_basic_dict_annotation(obj_type): return BasicDictSerializer() if is_typing_dict_annotation(obj_type): if obj_type.__args__[0] != str: raise TypeError('typing.Dict key can only be str in class {}'.format(parent_class)) return TypingDictSerializer(self.get(obj_type.__args__[1], parent_class, name_in_parent)) if has_cls_attr(obj_type, PYCKSON_SERIALIZER): return CustomDeferredSerializer(obj_type) return ClassSerializer(self.model_provider)
def __init__(self, cls, serializer_provider: SerializerProvider, parser_provider: ParserProvider): self.cls = cls apply_defaults(cls) self.serializer_provider = serializer_provider self.parser_provider = parser_provider self.type_info = get_cls_attr(cls, PYCKSON_TYPEINFO, dict()) self.name_rule = get_name_rule(cls)
def caseinsensitive(cls): """Annotation function to set an Enum to be case insensitive on parsing""" if not issubclass(cls, Enum): raise TypeError( 'caseinsensitive decorator can only be applied to subclasses of enum.Enum' ) enum_options = get_cls_attr(cls, PYCKSON_ENUM_OPTIONS, {}) enum_options[ENUM_CASE_INSENSITIVE] = True set_cls_attr(cls, PYCKSON_ENUM_OPTIONS, enum_options) return cls
def get_class_use_explicit_nulls(cls) -> bool: if has_cls_attr(cls, PYCKSON_EXPLICIT_NULLS): return get_cls_attr(cls, PYCKSON_EXPLICIT_NULLS) else: return get_use_explicit_nulls()
def get_class_date_formatter(cls) -> DateFormatter: if has_cls_attr(cls, PYCKSON_DATE_FORMATTER): return get_cls_attr(cls, PYCKSON_DATE_FORMATTER) else: return get_date_formatter()
def get_or_build(self, obj_or_class) -> PycksonModel: if type(obj_or_class) is not type: return self.get_or_build(obj_or_class.__class__) if not is_pyckson(obj_or_class): self.set_model(obj_or_class) return get_cls_attr(obj_or_class, PYCKSON_MODEL)
def class_decorator(cls): type_info = get_cls_attr(cls, PYCKSON_TYPEINFO, dict()) type_info[param_name] = param_sub_type set_cls_attr(cls, PYCKSON_TYPEINFO, type_info) return cls
def apply_defaults(cls): global global_defaults for default in global_defaults: if not has_cls_attr(cls, get_cls_attr(default, PYCKSON_RULE_ATTR)): default(cls)
def get_custom_parser(cls) -> Parser: parser = get_cls_attr(cls, PYCKSON_PARSER) if isinstance(parser, str): parser = TypeProvider(cls, parser).get() return parser()
def get_custom_serializer(cls) -> Serializer: serializer = get_cls_attr(cls, PYCKSON_SERIALIZER) if isinstance(serializer, str): serializer = TypeProvider(cls, serializer).get() return serializer()
def get_name_rule(obj_type): return get_cls_attr(obj_type, PYCKSON_NAMERULE, camel_case_name)
def is_pyckson(obj_type): return get_cls_attr(obj_type, PYCKSON_ATTR, False)