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