268 lines
8.7 KiB
Python
268 lines
8.7 KiB
Python
from collections import defaultdict
|
|
from .._compat import PY2, with_metaclass, iteritems, to_unicode, to_bytes, \
|
|
string_types
|
|
from .._gae import gae
|
|
from ..helpers._internals import Dispatcher
|
|
from ..helpers.regex import REGEX_TYPE
|
|
|
|
representers = Dispatcher("representer")
|
|
|
|
|
|
class for_type(object):
|
|
def __init__(self, field_type, encode=False, adapt=True):
|
|
self.field_type = field_type
|
|
self.encode = encode
|
|
self.adapt = adapt
|
|
|
|
def __call__(self, f):
|
|
self.f = f
|
|
return self
|
|
|
|
|
|
class before_type(object):
|
|
def __init__(self, field_type):
|
|
self.field_type = field_type
|
|
|
|
def __call__(self, f):
|
|
self.f = f
|
|
return self
|
|
|
|
|
|
class for_instance(object):
|
|
def __init__(self, inst_type, repr_type=False):
|
|
self.inst_type = inst_type
|
|
self.repr_type = repr_type
|
|
|
|
def __call__(self, f):
|
|
self.f = f
|
|
return self
|
|
|
|
|
|
class pre(object):
|
|
_inst_count_ = 0
|
|
|
|
def __init__(self, is_breaking=None):
|
|
self.breaking = is_breaking
|
|
self._inst_count_ = pre._inst_count_
|
|
pre._inst_count_ += 1
|
|
|
|
def __call__(self, f):
|
|
self.f = f
|
|
return self
|
|
|
|
|
|
class MetaRepresenter(type):
|
|
def __new__(cls, name, bases, attrs):
|
|
new_class = type.__new__(cls, name, bases, attrs)
|
|
if bases == (object,):
|
|
return new_class
|
|
#: collect declared attributes
|
|
trepresenters = {}
|
|
irepresenters = {}
|
|
tbefore = {}
|
|
pres = {}
|
|
for key, value in list(attrs.items()):
|
|
if isinstance(value, for_type):
|
|
trepresenters[key] = value
|
|
elif isinstance(value, before_type):
|
|
tbefore[key] = value
|
|
elif isinstance(value, for_instance):
|
|
irepresenters[key] = value
|
|
elif isinstance(value, pre):
|
|
pres[key] = value
|
|
#: get super declared attributes
|
|
declared_trepresenters = {}
|
|
declared_irepresenters = {}
|
|
declared_tbefore = {}
|
|
declared_pres = {}
|
|
for base in reversed(new_class.__mro__[1:]):
|
|
if hasattr(base, '_declared_trepresenters_'):
|
|
declared_trepresenters.update(base._declared_trepresenters_)
|
|
if hasattr(base, '_declared_irepresenters_'):
|
|
declared_irepresenters.update(base._declared_irepresenters_)
|
|
if hasattr(base, '_declared_tbefore_'):
|
|
declared_tbefore.update(base._declared_tbefore_)
|
|
if hasattr(base, '_declared_pres_'):
|
|
declared_pres.update(base._declared_pres_)
|
|
#: set trepresenters
|
|
declared_trepresenters.update(trepresenters)
|
|
declared_irepresenters.update(irepresenters)
|
|
declared_tbefore.update(tbefore)
|
|
declared_pres.update(pres)
|
|
new_class._declared_trepresenters_ = declared_trepresenters
|
|
new_class._declared_irepresenters_ = declared_irepresenters
|
|
new_class._declared_tbefore_ = declared_tbefore
|
|
new_class._declared_pres_ = declared_pres
|
|
return new_class
|
|
|
|
|
|
class TReprMethodWrapper(object):
|
|
def __init__(self, representer, obj, extra=None):
|
|
self.representer = representer
|
|
self.obj = obj
|
|
if extra:
|
|
self.extra = extra
|
|
self.call = self._call_with_extras
|
|
else:
|
|
self.call = self._call
|
|
if self.obj.encode and PY2:
|
|
self.inner_call = self._inner_call_with_encode
|
|
else:
|
|
self.inner_call = self._inner_call
|
|
if self.obj.adapt:
|
|
self.adapt = self._adapt
|
|
else:
|
|
self.adapt = self._no_adapt
|
|
|
|
def _adapt(self, value):
|
|
return self.representer.adapt(value)
|
|
|
|
def _no_adapt(self, value):
|
|
return value
|
|
|
|
def _inner_call(self, value, **kwargs):
|
|
return self.obj.f(self.representer, value, **kwargs)
|
|
|
|
def _inner_call_with_encode(self, value, **kwargs):
|
|
if isinstance(value, unicode):
|
|
value = value.encode(self.representer.adapter.db_codec)
|
|
return self.obj.f(self.representer, value, **kwargs)
|
|
|
|
def _call_with_extras(self, value, field_type):
|
|
extras = self.extra(self.representer, field_type)
|
|
return self.inner_call(value, **extras)
|
|
|
|
def _call(self, value, field_type):
|
|
return self.inner_call(value)
|
|
|
|
def __call__(self, value, field_type):
|
|
return self.adapt(self.call(value, field_type))
|
|
|
|
|
|
class IReprMethodWrapper(object):
|
|
def __init__(self, representer, obj):
|
|
self.representer = representer
|
|
self.obj = obj
|
|
|
|
def __call__(self, value, field_type):
|
|
rv = self.obj.f(self.representer, value, field_type)
|
|
return self.obj.repr_type, rv
|
|
|
|
|
|
class PreMethodWrapper(object):
|
|
def __init__(self, representer, obj):
|
|
self.representer = representer
|
|
self.obj = obj
|
|
if self.obj.breaking is None:
|
|
self.call = self._call_autobreak
|
|
elif self.obj.breaking == True:
|
|
self.call = self._call_break
|
|
else:
|
|
self.call = self._call_nobreak
|
|
|
|
def _call_autobreak(self, value, field_type):
|
|
rv = self.obj.f(self.representer, value, field_type)
|
|
if rv is not None:
|
|
return True, rv
|
|
return False, value
|
|
|
|
def _call_break(self, value, field_type):
|
|
return self.obj.f(
|
|
self.representer, value, field_type)
|
|
|
|
def _call_nobreak(self, value, field_type):
|
|
return False, self.obj.f(self.representer, value, field_type)
|
|
|
|
def __call__(self, value, field_type):
|
|
return self.call(value, field_type)
|
|
|
|
|
|
class Representer(with_metaclass(MetaRepresenter)):
|
|
def __init__(self, adapter):
|
|
self.adapter = adapter
|
|
self.dialect = adapter.dialect
|
|
self._tbefore_registry_ = {}
|
|
for name, obj in iteritems(self._declared_tbefore_):
|
|
self._tbefore_registry_[obj.field_type] = obj.f
|
|
self.registered_t = defaultdict(lambda self=self: self._default)
|
|
for name, obj in iteritems(self._declared_trepresenters_):
|
|
if obj.field_type in self._tbefore_registry_:
|
|
self.registered_t[obj.field_type] = TReprMethodWrapper(
|
|
self, obj, self._tbefore_registry_[obj.field_type]
|
|
)
|
|
else:
|
|
self.registered_t[obj.field_type] = TReprMethodWrapper(
|
|
self, obj
|
|
)
|
|
self.registered_i = {}
|
|
for name, obj in iteritems(self._declared_irepresenters_):
|
|
self.registered_i[obj.inst_type] = IReprMethodWrapper(self, obj)
|
|
self._pre_registry_ = []
|
|
pres = []
|
|
for name, obj in iteritems(self._declared_pres_):
|
|
pres.append(obj)
|
|
pres.sort(key=lambda x: x._inst_count_)
|
|
for pre in pres:
|
|
self._pre_registry_.append(PreMethodWrapper(self, pre))
|
|
|
|
def _default(self, value, field_type):
|
|
return self.adapt(value)
|
|
|
|
def _default_instance(self, value, field_type):
|
|
return True, value
|
|
|
|
def get_representer_for_instance(self, value):
|
|
for inst, representer in iteritems(self.registered_i):
|
|
if isinstance(value, inst):
|
|
return representer
|
|
return self._default_instance
|
|
|
|
def get_representer_for_type(self, field_type):
|
|
key = REGEX_TYPE.match(field_type).group(0)
|
|
return self.registered_t[key]
|
|
|
|
def adapt(self, value):
|
|
if PY2:
|
|
if not isinstance(value, string_types):
|
|
value = str(value)
|
|
value = to_bytes(value)
|
|
try:
|
|
value.decode(self.adapter.db_codec)
|
|
except:
|
|
value = value.decode('latin1').encode(self.adapter.db_codec)
|
|
else:
|
|
value = to_unicode(value)
|
|
return self.adapter.adapt(value)
|
|
|
|
def exceptions(self, value, field_type):
|
|
return None
|
|
|
|
def represent(self, value, field_type):
|
|
pre_end = False
|
|
for pre in self._pre_registry_:
|
|
pre_end, value = pre(value, field_type)
|
|
if pre_end:
|
|
break
|
|
if pre_end:
|
|
return value
|
|
repr_type, rv = self.get_representer_for_instance(value)(
|
|
value, field_type)
|
|
if repr_type:
|
|
rv = self.get_representer_for_type(field_type)(rv, field_type)
|
|
return rv
|
|
|
|
|
|
from .base import BaseRepresenter, SQLRepresenter, NoSQLRepresenter
|
|
from .sqlite import SQLiteRepresenter, SpatialiteRepresenter
|
|
from .postgre import PostgreRepresenter
|
|
from .mysql import MySQLRepresenter
|
|
from .mssql import MSSQLRepresenter
|
|
from .mongo import MongoRepresenter
|
|
from .db2 import DB2Representer
|
|
from .informix import InformixRepresenter
|
|
from .oracle import OracleRepresenter
|
|
from .couchdb import CouchDBRepresenter
|
|
|
|
if gae is not None:
|
|
from .google import GoogleDatastoreRepresenter
|