PK OOd..preconvert/__init__.py"""A Library to enable preconversion of any Python type into one that is easily serializable""" import pkg_resources from preconvert import convert, exceptions, output from preconvert.convert import default_serializer from preconvert.register import bson, converter, json, msgpack for plugin in pkg_resources.iter_entry_points("preconvert.converters"): plugin.load() __version__ = "0.0.6" __all__ = [ "converter", "json", "bson", "msgpack", "exceptions", "convert", "output", "default_serializer", "__version__", ] PK O;Vpreconvert/convert.pyfrom enum import Enum from functools import partial from itertools import chain from typing import Any, Callable, Dict, Iterable, Text, Union from preconvert.exceptions import Unconvertable from preconvert.register import converters class PreconversionSource(Enum): """All globally available conversion sources""" ALL_PACKAGES = 1 PRECONVERT = 2 def default_serializer( item: Any, namespace: Text = "base", base_namespace: Text = "base", using: Union[Iterable[Text], PreconversionSource] = PreconversionSource.ALL_PACKAGES, store: Dict[Text, Dict[Text, Dict[Any, Callable]]] = converters, ): if hasattr(item, "__preconvert__"): return item.__preconvert__() package_stores: Any if using == PreconversionSource.ALL_PACKAGES: package_stores = store.values() elif using == PreconversionSource.PRECONVERT: package_stores = (store["preconvert"],) elif isinstance(using, Iterable): package_stores = tuple(store[use_package] for use_package in using) if base_namespace and namespace != base_namespace: preconverters = chain( *( chain(package_store.get(namespace, {}).items(), package_store["base"].items()) for package_store in package_stores ) ) else: preconverters = chain(*(store[base_namespace].items() for package_store in package_stores)) for kind, transformer in reversed(tuple(preconverters)): if isinstance(item, kind): return transformer(item) if hasattr(item, "__iter__"): return list(item) raise Unconvertable(item) json = partial(default_serializer, namespace="json") bson = partial(default_serializer, namespace="bson") msgpack = partial(default_serializer, namespace="msgpack") PK OFepreconvert/converters.pyimport base64 from datetime import date, datetime, timedelta from decimal import Decimal from enum import Enum from types import GeneratorType from typing import Any, Collection, Dict, Mapping, NamedTuple, Union from uuid import UUID from preconvert import register from preconvert.exceptions import Unconvertable try: import dataclasses dataclasses_loaded = True except ImportError: dataclasses_loaded = False if dataclasses_loaded: @register.converter(object) def convert_data_class(instance): if dataclasses.is_dataclass(instance): return dataclasses.asdict(instance) else: raise Unconvertable(instance) register.converter(Collection)(list) register.converter(GeneratorType)(tuple) register.converter(Mapping)(dict) register.converter(Decimal, UUID)(str) @register.converter(date, datetime) def datetime_converter(item): return item.isoformat() @register.converter(timedelta) def time_delta_converter(item): return item.total_seconds() @register.converter(Enum) def use_value_attribute(item): return item.value @register.converter(NamedTuple) def convert_namedtuple(instance: Any) -> Union[Dict, tuple]: """Converts a tuple of type namedtuple to a dict. This isn't registered as injecting this via registration won't work because it will never be falling through to as tuples convert to list. if the tuple isn't a named one, it will return the tuple unchanged """ if hasattr(instance, "_asdict"): return instance._asdict() return instance @register.converter(bytes) def byte_converter(item): try: return item.decode("utf8") except UnicodeDecodeError: return base64.b64encode(item) PK OPp77preconvert/exceptions.py"""Defines all exceptions that can be thrown by the preconvert project""" class Error(Exception): """Base class for exceptions thrown from the preconvert project""" pass class ExistingConverter(Error): """Should be raised when a converter already exists for a specified type""" def __init__(self, kind, existing, new): super().__init__( self, ( "A new converter ({new}) is being registered for {kind} " "but an existing one exists already exists: {existing}. " "If intended, use override=True" ).format(kind=kind, existing=existing, new=new), ) self.kind = kind self.existing = existing self.new = new class Unconvertable(Error): """Raised when the provided item is not convertable using the provided converter(s)""" def __init__(self, item): super().__init__( self, "Object of type {} is not convertible " "into a serializable type".format(type(item)), ) self.item = item PK Opreconvert/register.py"""This module handles the registration of preconverters""" from collections import OrderedDict from enum import Enum from functools import partial from typing import Any, Callable, Dict, Text, Union from preconvert.exceptions import ExistingConverter converters: Dict[Text, Dict[Text, Dict[Text, Callable]]] = {"preconvert": {"base": OrderedDict()}} class AutoPackage(Enum): """Provides options for the automatic determination of a package name""" FUNCTION = 1 PRECONVERT = 2 FUNCTION_OR_PRECONVERT = 3 def converter( *kinds: Any, scope: Text = "base", store: Dict[Text, Dict[Text, Dict[Text, Callable]]] = converters, override: bool = False, package: Union[Text, AutoPackage] = AutoPackage.FUNCTION_OR_PRECONVERT, ) -> Callable: """A decorator that registers the wrapped function as a pre-converter for the provided types in the provided `store` data structure or a default global one. Returns the decorated function unchanged. """ def register_converter(function): nonlocal package nonlocal scope if package == AutoPackage.FUNCTION_OR_PRECONVERT: package = getattr(function, "__package__", None) or "preconvert" if package == AutoPackage.FUNCTION: package = function.__package__ elif package == AutoPackage.PRECONVERT: package = "preconvert" package = store.setdefault(package, {}) scope = package.setdefault(scope, OrderedDict()) if not override: for kind in kinds: if kind in scope: raise ExistingConverter(kind, scope, function) for kind in kinds: # we redo this loop simply to guard against partial application scope[kind] = function return function return register_converter json = partial(converter, scope="json") bson = partial(converter, scope="bson") msgpack = partial(converter, scope="msgpack") PK OPPpreconvert/output/__init__.py"""Exposes all output formatters that have built-in support for preconversion Note: the interesting try: catch: pattern is done as their isn't a guarantee that the user has any of the given output formatters installed, which is required for preconvert to plug-in it's preconversion. """ try: from preconvert.output import json except ImportError: pass try: from preconvert.output import bson except ImportError: pass try: from preconvert.output import msgpack except ImportError: pass try: from preconvert.output import simplejson except ImportError: pass PK OXbpreconvert/output/bson.pyimport bson from bson import * from preconvert import convert from preconvert.converters import convert_namedtuple def dumps(content, *args, on_unknown=convert.bson, **kwargs): # type: ignore """BSON dumps with preconversion for common unserializable types in place""" if isinstance(content, tuple): content = convert_namedtuple(content) return bson.dumps(content, on_unknown=on_unknown, *args, **kwargs) def dump(content, *args, on_unknown=convert.bson, **kwargs): # type: ignore """BSON dump with preconversion for common unserializable types in place""" if isinstance(content, tuple): content = convert_namedtuple(content) return bson.dump(content, on_unknown=on_unknown, *args, **kwargs) PK O9preconvert/output/json.pyimport json from json import * from preconvert import convert from preconvert.converters import convert_namedtuple def dumps(content, *args, default=convert.json, **kwargs): # type: ignore """JSON dumps with preconversion for common unserializable types in place""" if isinstance(content, tuple): content = convert_namedtuple(content) return json.dumps(content, default=default, *args, **kwargs) def dump(content, *args, default=convert.json, **kwargs): # type: ignore """JSON dump with preconversion for common unserializable types in place""" if isinstance(content, tuple): content = convert_namedtuple(content) return json.dump(content, default=default, *args, **kwargs) PK OnѲOOpreconvert/output/msgpack.pyimport msgpack from msgpack import * from preconvert import convert from preconvert.converters import convert_namedtuple def pack(content, *args, default=convert.msgpack, **kwargs): # type: ignore """Msgpacks with preconversion for common unserializable types in place""" if isinstance(content, tuple): content = convert_namedtuple(content) return msgpack.pack(content, default=default, *args, **kwargs) def packb(content, *args, default=convert.msgpack, **kwargs): # type: ignore """Msgpacks with preconversion for common unserializable types in place""" if isinstance(content, tuple): content = convert_namedtuple(content) return msgpack.packb(content, default=default, *args, **kwargs) def dump(content, *args, default=convert.msgpack, **kwargs): # type: ignore """Msgpack dump with preconversion for common unserializable types in place""" if isinstance(content, tuple): content = convert_namedtuple(content) return msgpack.dump(content, default=default, *args, **kwargs) def dumps(content, *args, default=convert.msgpack, **kwargs): # type: ignore """Msgpacks dump with preconversion for common unserializable types in place""" if isinstance(content, tuple): content = convert_namedtuple(content) return msgpack.dumps(content, default=default, *args, **kwargs) PK O(`preconvert/output/simplejson.pyfrom functools import partial import simplejson from simplejson import * from preconvert import convert dumps = partial(simplejson.dumps, default=convert.json) # type: ignore dump = partial(simplejson.dump, default=convert.json) # type: ignore PK O+vAA"preconvert-0.0.6.dist-info/LICENSEThe MIT License (MIT) Copyright (c) 2019 Timothy Edmund Crosley 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 SOFTWARE. PK!HPO preconvert-0.0.6.dist-info/WHEEL HM K-*ϳR03rOK-J,/RH,szd&Y)r$[)T&UrPK!H)^ t#preconvert-0.0.6.dist-info/METADATAYms۸_sf*FrΩi|c7rd24DAb&8I'LH}v>Ϲ*QbB* ÇLS^Tv^YGf%=F'Z0U2+*Lfج2̊&5\ˤbZ'?D%xR%XRU9 c*BDT;I_Xd߾Kp.&a'Ee2an ezi2aOq!sUTfDf/$HfV,8Jr!$9ms1g\,l2aF$*z{:|zP78sEOS-+-K{iR2Z[^ZкsCLD,RLlʠ|ۚimK2uw_U4OPnW(|#8pB'8Y﬷HblZ0,G(~Xeoï M6xLRE l9jOtwVki|eQYB]B}Ss?/e2gSMfz;*WX=C eYb4=H;#ʫZYa& Z߰ʴ葦ZwgI#ŁZH\ig!i2;ȋmj2+)I62͊bH=y0`E;rcE^F]mp b3ro܌І$_IHw u '_3v7"WZUT=/}9Gh1Ŏ.Ti(ar 50; 56lpDw&Xs[Qq=;"#OJګYJVj+|0+7X,ddP[͈ԇn)ѓnrd%B A1[j{-1(:)`& f3@ٖY&AQ3GR!;Re,&I*W -TQ tVv)ʓr)kHSvKl ,y2$#vu dU? XRT&B*lh'J:FeK'p$TKk+iq\OaؾЧp^]:wt0:zu8NOB Gߨq0fhL`Ά7J:zy2T}NzӫeÕ@sU ѡIX((j,l!{MzGv3;ܼ&y:,2瀈 &x&ؘ YaSHvbК;DZ%|~ȨȕZ6"ރ#? qJʀO hFh* R$*B#H-AaqvYeYXtn oWճ xɱ` ^0f{NujvLaGeI_E^Hcl6cm.T #vZi4-3ʔ6Ϻq!PupZ%7• /tKQP`OM&GHhXł,ՆEBPcNnbڤY_ Q?5"uABs-DNH3v*؊X?6{4c1`ߨ;CơucW(yfжEiyЅ+Q@(VڸeO6}k:hVpQ#5x?ܚ Ql;`SQ#JGc֩pxOf7|}Iͻ""{|yϣ}`vyK h>) U 7{ :>DOl(>yo1@gʰߦ{?(Θ{b 8\%l OK{dFB_3)_m&ֲ߲skץ_vwwO45tא;HՎ:⣭\#DcdU-PFn@WE]c JLC˜R6`&FO=(=ZT4b3tt7;[)2pߔ'Fqt8P B}MuKu抝8jA דxw'mZotk ٝ lk7*jhd^,n|L݀eV  f ]$F ֻcWW9°-cmY wtaWF7Zk;ήLr\eיͮX 6+quELJĆægr/E2;j@0wR[JuXE7x>c/E3c@&^֏^4*$Tep+O& t g5 aզamoQ7a;`;UxAa~k2WE1r O׷#y9㶳^OC3X)\TPLFCc& &QW"g6*iGc;}cQzӶ}pS/W3)y ؛+$7J :/z@!^ToգϺIһ^_<"Ep^k]1;4a0m+v5WCș<Yr`ü5מI|`KM+@6VP K2Ь&>7QO|mY@={yW⺺6w9ꖌc6JKr1@,3 -UQ^@cB\PY[>vzrAMx A̼ۤ[FnV š!G#s6X2jb)w-o190u˒̜O:m$Ű?rvQ<$p7cM޴5&[UEoRT\={1g?Of)Օ(1}z #FPfX,"j?;B}g< PK OOd..preconvert/__init__.pyPK O;Vbpreconvert/convert.pyPK OFe preconvert/converters.pyPK OPp77preconvert/exceptions.pyPK Opreconvert/register.pyPK OPPpreconvert/output/__init__.pyPK OXbpreconvert/output/bson.pyPK O9"preconvert/output/json.pyPK OnѲOO%preconvert/output/msgpack.pyPK O(`5+preconvert/output/simplejson.pyPK O+vAA"k,preconvert-0.0.6.dist-info/LICENSEPK!HPO 0preconvert-0.0.6.dist-info/WHEELPK!H)^ t#z1preconvert-0.0.6.dist-info/METADATAPK!Hhb!<preconvert-0.0.6.dist-info/RECORDPK?