Commits

Adrian Dries committed cc086ec

revert to sqlalchemy declarative library

Comments (0)

Files changed (4)

 import time
 import uuid
 from sqlalchemy import event
+from sqlalchemy.ext.declarative import DeclarativeMeta
 
 
-from fenton import decl
 from fenton import util
 from fenton import view
 from fenton import model
             yield row
 
 
-
-
 def GUID():
     from sqlalchemy.dialects import postgresql
     return postgresql.UUID(as_uuid=True)
 
 
+def _prepare_attrs(self, attrs):
+    self.__attrs__ = attrs.get('__attrs__', {})
 
+    for k, v in attrs.iteritems():
+        if isinstance(v, tuple) and len(v)==1 and isinstance(v[0], types.Type):
+            raise TypeError('errant comma at %s.%s' % (self.__name__, k))
+        if isinstance(v, types.Type):
+            v.instrument(self, k)
+            self.__attrs__[k] = v
 
+    fields = getattr(self, '__fields__', None) or ()
+    if fields and isinstance(fields[0], basestring):
+        fields = (('', '', fields),)
+    self.__fields__ = fields
 
-class ModelMetaclass(type):
-    def __init__(self, name, bases, attrs):
-        aa = self.__attrs__ = attrs.get('__attrs__', {})
 
-        for k, v in attrs.iteritems():
-            if isinstance(v, tuple) and len(v)==1 and isinstance(v[0], types.Type):
-                raise TypeError('errant comma at %s.%s' % (name, k))
-            if isinstance(v, types.Type):
-                v.instrument(self, k)
-                aa[k] = v
-
-        fields = getattr(self, '__fields__', None) or ()
-        if fields and isinstance(fields[0], basestring):
-            fields = (('', '', fields),)
-        self.__fields__ = fields
-        return type.__init__(self, name, bases, attrs)
-
-
-
-
-class DbMetaclass(ModelMetaclass):
-    def __init__(self, name, bases, attrs):
-        ModelMetaclass.__init__(self, name, bases, attrs)
-        if DbModel is not None:
-            if DbModel in bases and GUID_ATTR not in self.__dict__:
-                self._configure_history()
-            self._configure_dbmodel()
-            event.listen(self, 'load', self._set_context)
-
-    def _set_context(self, obj, _):
-        m = getmeta(obj, False)
-        if m:
-            m.set_context(orm.object_session(obj).context, obj)
-
-    def _configure_dbmodel(self):
-        if getattr(self, COMMENT_ATTR, False) is not False:
-            self.__fields__ = tuple(list(self.__fields__)
-                                     + [(COMMENT_ATTR,
-                                         ' ',
-                                         (COMMENT_ATTR,))])
-        decl.configure(self)
-        event.listen(self.__table__, 'before_create', _print_create)
-        _register_seed_func(self, _insert_metainfo)
-
-    def _configure_history(self):
+def _init_metainfo(self):
+    if DbModel in self.__bases__ and GUID_ATTR not in self.__dict__:
         guid_col = sql.Column(GUID_ATTR, GUID(), nullable=False, unique=True)
         guid_col._creation_order = -1
         setattr(self, GUID_ATTR, guid_col)
                                   uselist=False,
                                   viewonly=True,
                                   cascade=None)
-
         mattrs = self.__attrs__
         if COMMENT_ATTR not in mattrs and COMMENT_ATTR not in self.__dict__:
             setattr(self, COMMENT_ATTR, None)
                                               showview=False,
                                               label='Add comment')
 
+    if getattr(self, COMMENT_ATTR, False) is not False:
+        self.__fields__ = tuple(list(self.__fields__)
+                                 + [(COMMENT_ATTR, ' ', (COMMENT_ATTR,))])
 
 
+def _init_events(self):
+    _register_seed_func(self, _insert_metainfo)
+    event.listen(self, 'load', _set_context)
+    event.listen(self.__table__, 'before_create', _print_create)
+
+
+def _set_context(obj, _):
+    m = getmeta(obj, False)
+    if m:
+        m.set_context(orm.object_session(obj).context, obj)
+
+
+
+
+class ModelMetaclass(type):
+    def __init__(self, name, bases, attrs):
+        _prepare_attrs(self, attrs)
+        return type.__init__(self, name, bases, attrs)
+
+
+
+
+class DbMetaclass(DeclarativeMeta):
+    def __init__(self, name, bases, attrs):
+        superinit = DeclarativeMeta.__init__
+        if DbModel is None:
+            superinit(self, name, bases, attrs)
+        else:
+            _prepare_attrs(self, attrs)
+            _init_metainfo(self)
+            superinit(self, name, bases, attrs)
+            _init_events(self)
+
 
 
 
 
 
 
-class DbBase(ModelBase):
+@model.IterMeta.declare(metaclass=ModelMetaclass)
+class Iter(ModelBase, model.ModelIterator):
+    pass
+
+
+
+
+@TransientMeta.declare(metaclass=ModelMetaclass)
+class Transient(ModelBase):
+    pass
+
+
+
+
+@DbMeta.declare(metadata=METADATA, metaclass=DbMetaclass)
+class DbModel(ModelBase):
     def set_attribute_event(self, key, value, form):
         if key == COMMENT_ATTR:
             self._cx.history_logger.log_comment(self, value)
             else:
                 old_str = meta.attributes[key].format_value(old, self._cx)
             self._cx.history_logger.log_update(self, key, old_str, new_str)
-        return super(DbBase, self).set_attribute_event(key, value, form)
+        return super(DbModel, self).set_attribute_event(key, value, form)
 
     def after_delete_event(self):
         self._cx.history_logger.log_delete(self)
 
 
 
-Iter = model.IterMeta.create_base(bases=(ModelBase, model.ModelIterator,),
-                                  metaclass=ModelMetaclass)
-
-Transient = TransientMeta.create_base(bases=(ModelBase,),
-                                      metaclass=ModelMetaclass)
-
-DbModel = DbMeta.create_base(bases=(DbBase,),
-                             metadata=METADATA,
-                             metaclass=DbMetaclass)
-
-
-
 class Nav(Transient):
     __classid__ = None
     __view__ = view.NavScreen
     #attr_old = sql.Column(sql.String(), nullable=False)
     #attr_new = sql.Column(sql.String(), nullable=False)
     event = orm.relation('MetaObjectEvent', back_populates='attrs')
-    __table_args__ = sql.ForeignKeyConstraint(['userid', 'timestamp', 'object_guid'],
+    __table_args__ = (sql.ForeignKeyConstraint(['userid', 'timestamp', 'object_guid'],
                                               ['meta_object_event.userid',
                                                'meta_object_event.timestamp',
-                                               'meta_object_event.object_guid'])
+                                               'meta_object_event.object_guid']),)
 
     @property
     def summary(self):

fenton/decl.py

-
-from sqlalchemy import util, exceptions
-from sqlalchemy.schema import Table, Column
-from sqlalchemy.orm import mapper as orm_mapper, class_mapper
-from sqlalchemy.orm.interfaces import MapperProperty
-from sqlalchemy.orm.properties import RelationshipProperty, ColumnProperty
-from sqlalchemy.orm.util import _is_mapped_class
-from sqlalchemy.sql.util import join_condition
-
-
-REGISTRY_ATTR = '____declarative_class_registry____'
-METADATA_ATTR = '____declarative_metadata____'
-
-
-def declarative_base(metadata=None, mapper=None, bases=(object,),
-                     registry=None, metaclass=None):
-
-    if metaclass is None:
-        metaclass = DeclarativeMeta
-
-    if registry is None:
-        registry = {}
-
-    attrs = {REGISTRY_ATTR: registry,
-             METADATA_ATTR: metadata}
-    if mapper:
-        attrs['__mapper_class__'] = mapper
-    return metaclass('Base', bases, attrs)
-
-
-def _register(Class):
-    _get_registry(Class)[Class.__name__] = Class
-
-
-def _get_registry(Class):
-    return getattr(Class, REGISTRY_ATTR)
-
-
-def _get_metadata(Class):
-    return getattr(Class, METADATA_ATTR)
-
-
-def configure(Class):
-
-    if REGISTRY_ATTR in Class.__dict__:
-        return
-
-    attrs = dict(Class.__dict__)
-
-    copies = {}
-    potentials = {}
-    mapper_args = {}
-    parent_columns = ()
-    tablename = None
-    table_args = None
-    inherited_table_args = None
-
-    for ancestor in Class.__mro__:
-        if _is_mapped_class(ancestor):
-            parent_columns = ancestor.__table__.c.keys()
-            continue
-
-        for name, obj in vars(ancestor).items():
-            if name == '__mapper_args__':
-                if not mapper_args:
-                    mapper_args = Class.__mapper_args__
-            elif name == '__tablename__':
-                if not tablename:
-                    tablename = Class.__tablename__
-            elif name == '__table_args__':
-                if not table_args:
-                    table_args = Class.__table_args__
-                    if ancestor is not Class:
-                        inherited_table_args = True
-            elif ancestor is not Class:
-                # we're a mixin.
-
-                if isinstance(obj, Column):
-                    if obj.foreign_keys:
-                        raise exceptions.InvalidRequestError(
-                        'Columns with foreign keys to other columns '
-                        'must be declared as @classproperty callables '
-                        'on declarative mixin classes. ')
-                    if name not in attrs and not (
-                            '__table__' in attrs and
-                            name in attrs['__table__'].c
-                            ):
-                        potentials[name] = copies[obj] = obj.copy()
-                        copies[obj]._creation_order = obj._creation_order
-                elif isinstance(obj, MapperProperty):
-                    raise exceptions.InvalidRequestError(
-                        'Mapper properties (i.e. deferred,'
-                        'column_property(), relationship(), etc.) must '
-                        'be declared as @classproperty callables '
-                        'on declarative mixin classes.')
-                elif isinstance(obj, util.classproperty):
-                    x = attrs[name] = copies[obj] = getattr(Class, name)
-                    if isinstance(x, (Column, MapperProperty)) and x.doc is None:
-                        x.doc = obj.__doc__
-
-    # apply inherited columns as we should
-    for k in potentials:
-        if tablename or k not in parent_columns:
-            attrs[k] = potentials[k]
-
-    if inherited_table_args and not tablename:
-        table_args = None
-
-    # make sure that column copies are used rather
-    # than the original columns from any mixins
-    for k, v in mapper_args.iteritems():
-        if v in copies:
-            mapper_args[k] = copies[v]
-
-    # extract columns from the class dict in order
-    cols = []
-    props = {}
-    ordered = []
-    for (k, v) in attrs.items():
-        if isinstance(v, util.classproperty):
-            v = getattr(Class, k)
-
-        if (isinstance(v, tuple) and len(v) == 1 and
-           isinstance(v[0], (Column, MapperProperty))):
-            util.warn('Spurious comma at %s.%s' % (name, k))
-            continue
-        if isinstance(v, (Column, MapperProperty)):
-            ordered.append((k, _deferred_relationship(k, Class, v)))
-
-    #ordered = [(k, _deferred_relationship(Class, v))
-    #           for (k, v) in attrs.items()
-    #           if isinstance(v, (Column, MapperProperty))]
-
-    for key, c in sorted(ordered, key=lambda x: x[1]._creation_order):
-        if isinstance(c, ColumnProperty):
-            for col in c.columns:
-                if isinstance(col, Column) and col.table is None:
-                    _undefer_column_name(key, col)
-                    cols.append(col)
-        elif isinstance(c, Column):
-            _undefer_column_name(key, c)
-            cols.append(c)
-            # if the column is the same name as the key,
-            # remove it from the explicit properties dict.
-            # the normal rules for assigning column-based properties
-            # will take over, including precedence of columns
-            # in multi-column ColumnProperties.
-            if key == c.key:
-                continue
-        props[key] = c
-
-    table = None
-    if tablename is not None:
-        if isinstance(table_args, dict):
-            targs, tkw = (), table_args
-        elif isinstance(table_args, (list, tuple)):
-            if isinstance(table_args[-1], dict):
-                targs = table_args[0:-1]
-                tkw = table_args[-1]
-            else:
-                targs = table_args
-                tkw = {}
-        else:
-            targs = (table_args,)
-            tkw = {}
-
-        table = Class.__table__ = Table(tablename,
-                                        _get_metadata(Class),
-                                        *(tuple(cols) + tuple(targs)),
-                                        **tkw)
-
-    if 'inherits' not in mapper_args:
-        for c in Class.__bases__:
-            if _is_mapped_class(c):
-                mapper_args['inherits'] = _get_registry(Class).get(c.__name__)
-                break
-
-    if table is None and 'inherits' not in mapper_args:
-        raise exceptions.InvalidRequestError(
-            'Class %r does not have a __table__ or __tablename__ '
-            'specified and does not inherit from an existing '
-            'table-mapped class.' % Class
-            )
-
-    if 'inherits' in mapper_args and not mapper_args.get('concrete'):
-        inherited_mapper = class_mapper(mapper_args['inherits'],
-                                        compile=False)
-        inherited_table = inherited_mapper.local_table
-        if 'inherit_condition' not in mapper_args and table is not None:
-            # figure out the inherit condition with relaxed rules
-            # about nonexistent tables, to allow for ForeignKeys to
-            # not-yet-defined tables (since we know for sure that our
-            # parent table is defined within the same MetaData)
-            join = join_condition(mapper_args['inherits'].__table__, table,
-                                  ignore_nonexistent_tables=True)
-            mapper_args['inherit_condition'] = join
-
-        if table is None:
-            # single table inheritance.
-            # ensure no table args
-            if table_args:
-                raise exceptions.ArgumentError(
-                    'Can\'t place __table_args__ on an inherited class '
-                    'with no table.'
-                    )
-
-            # add any columns declared here to the inherited table.
-            for c in cols:
-                if c.primary_key:
-                    raise exceptions.ArgumentError(
-                        'Can\'t place primary key columns on an inherited '
-                        'class with no table.'
-                        )
-                if c.name in inherited_table.c:
-                    raise exceptions.ArgumentError(
-                        'Column \'%s\' on class %s conflicts with '
-                        'existing column \'%s\'' %
-                        (c, Class, inherited_table.c[c.name])
-                    )
-                inherited_table.append_column(c)
-
-        # single or joined inheritance
-        # exclude any cols on the inherited table which are not mapped on the
-        # parent class, to avoid
-        # mapping columns specific to sibling/nephew classes
-
-        if 'exclude_properties' not in mapper_args:
-            exclude = set([c.key for c in inherited_table.c
-                           if c not in inherited_mapper._columntoproperty])
-            exclude.difference_update([c.key for c in cols])
-            mapper_args['exclude_properties'] = exclude
-
-    _register(Class)
-    mapper_class = getattr(Class, '__mapper_class__', orm_mapper)
-    Class.__mapper__ = mapper_class(Class, table, properties=props,
-                                    **mapper_args)
-
-def _resolve_arg(name, arg, Class, prop):
-    import sqlalchemy
-
-    def lookup(key):
-        reg = _get_registry(Class)
-        if key in reg:
-            return _deferred(reg[key])
-        metadata = _get_metadata(Class)
-        if key in metadata:
-            return metadata.tables[key]
-        if key in sqlalchemy.__dict__:
-            return sqlalchemy.__dict__[key]
-        raise KeyError(key)
-
-    def lazy(env=util.PopulateDict(lookup)):
-        try:
-            x = eval(arg, {}, env)
-        except NameError, e:
-            raise NameError('Failed resolving %r in property %r on %r' % (arg, name, prop.parent))
-        return type(x) is _deferred and x() or x
-
-    return lazy
-
-
-def _deferred_relationship(name, Class, prop):
-    relprop_deferrable = ('argument', 'order_by', 'primaryjoin', 'secondaryjoin',
-                          'secondary', '_user_defined_foreign_keys', 'remote_side')
-    backref_deferrable = ('primaryjoin', 'secondaryjoin', 'secondary',
-                          'foreign_keys', 'remote_side', 'order_by')
-
-    if isinstance(prop, RelationshipProperty):
-        for attr in relprop_deferrable:
-            v = getattr(prop, attr)
-            if isinstance(v, basestring):
-                setattr(prop, attr, _resolve_arg(name, v, Class, prop))
-
-        if prop.backref and isinstance(prop.backref, tuple):
-            key, kwargs = prop.backref
-            for attr in backref_deferrable:
-               if attr in kwargs and isinstance(kwargs[attr], basestring):
-                   kwargs[attr] = _resolve_arg(name, kwargs[attr], Class, prop)
-
-    return prop
-
-
-
-def _undefer_column_name(key, column):
-    if column.key is None:
-        column.key = key
-    if column.name is None:
-        column.name = key
-
-
-
-class DeclarativeMeta(type):
-    def __init__(Class, name, bases, attrs):
-        configure(Class)
-        return type.__init__(Class, name, bases, attrs)
-
-
-
-
-class _deferred(object):
-    def __init__(self, __class):
-        self.__class = __class
-
-    def __call__(self):
-        return self.__class
-
-    def __getattr__(self, key):
-        mapper = class_mapper(self.__class, compile=False)
-        if mapper:
-            prop = mapper.get_property(key, raiseerr=False)
-            if prop is None:
-                raise exceptions.InvalidRequestError(
-                            'Class %r does not have a mapped column named %r'
-                            % (self.__class, key))
-            elif not isinstance(prop, ColumnProperty):
-                raise exceptions.InvalidRequestError(
-                            'Property %r is not an instance of'
-                            ' ColumnProperty (i.e. does not correspond'
-                            ' directly to a Column).' % key)
-
-        return getattr(self.__class, key)
-
-

fenton/ext/crowd.py

 from sqlalchemy.ext.associationproxy import association_proxy
 from sqlalchemy.orm.collections import column_mapped_collection as coldict
 
-from fenton import decl
 from fenton import types
 from fenton import logging
 from fenton import security
 CROWD_DIRECTORY_ID = 32769
 CROWD_COOKIE = 'crowd.token_key'
 
-# crowd database
-metadata = sql.MetaData()
-
 
 
 
     Principal.tz = app.tz
 
 
+def declarative(**kw):
+    from sqlalchemy.ext.declarative import declarative_base
+    return lambda C: declarative_base(cls=C, **kw)
+
+
 def synchronize(cx):
     keep_users = ['crowd-admin']
     keep_groups = ['crowd-administrators']
 
 
 
-def _get(Class, db, name):
-    q = db.query(Class).filter_by(directory_id=CROWD_DIRECTORY_ID)
-    return q.filter(getattr(Class, Class.key) == name.lower()).first()
+@declarative()
+class CrowdObject:
 
+    @classmethod
+    def _get(Class, db, name):
+        q = db.query(Class).filter_by(directory_id=CROWD_DIRECTORY_ID)
+        return q.filter(getattr(Class, Class.key) == name.lower()).first()
 
-def _ensure(Class, db, name):
-    x =  Class._get(db, name)
-    if x is None:
-        logging.log.info('creating %s for %s', Class.__name__, name)
-        x = Class(name)
-        db.add(x)
-    return x
+    @classmethod
+    def _ensure(Class, db, name):
+        x =  Class._get(db, name)
+        if x is None:
+            logging.log.info('creating %s for %s', Class.__name__, name)
+            x = Class(name)
+            db.add(x)
+        return x
 
 
-CrowdObject = decl.declarative_base(metadata=metadata)
-CrowdObject._get = classmethod(_get)
-CrowdObject._ensure = classmethod(_ensure)
 
 
 class Membership(CrowdObject):
         self.group_type = 'GROUP'
         self.membership_type = 'GROUP_USER'
 
-    __table_args__ = [
+    __table_args__ = (
         sql.ForeignKeyConstraint(['directory_id', 'lower_parent_name'],
                                  ['cwd_group.directory_id', 'cwd_group.lower_group_name']),
         sql.ForeignKeyConstraint(['directory_id', 'lower_child_name'],
                                  ['cwd_user.directory_id', 'cwd_user.lower_user_name']),
-    ]
+    )
 
 # end class Membership
 
 
 import sqlalchemy.orm as orm
 
-from fenton import decl
 from fenton import util
 from fenton import view
 from fenton import types
     return Class
 
 
-def create_base_class(metanint,
+def create_base_class(metainit,
                       metaclass=type,
                       classfactory=create_class,
                       **kw):
         def __init__(self, name, bases, attrs):
             metaclass.__init__(self, name, bases, attrs)
             if base_class and self is not base_class:
-                #print '  ->',  '::'.join(map(util.classname, reversed(self.__mro__)))
-                metanint(self)
+                metainit(self)
     kw['metaclass'] = submeta
     base_class = classfactory(**kw)
-    #print 'create_base_class:'
-    #print ' metanint: ', metanint
-    #print ' metaclass:', metaclass
-    #print ' classfactory:', classfactory
-    #print ' ->',  '::'.join(map(util.classname, reversed(base_class.__mro__)))
     return base_class
 
 
             return None
 
 
+    # decorator
+    @classmethod
+    def declare(Class, **kw):
+        def classdecorator(newclass):
+            return Class.create_base(bases=(newclass,), **kw)
+        return classdecorator
+
+
     @classmethod
     def create_base(Class, **kw):
         if 'bases' not in kw:
 
 class DbMeta(ModelMeta):
 
-    base_class_factory = staticmethod(decl.declarative_base)
+    @staticmethod
+    def base_class_factory(**kw):
+        if 'bases' in kw:
+            kw['cls'] = kw.pop('bases')
+        from sqlalchemy.ext.declarative import declarative_base
+        return declarative_base(**kw)
 
     @util.classproperty
     def metaclass(self):
-        return decl.DeclarativeMeta
+        from sqlalchemy.ext.declarative import DeclarativeMeta
+        return DeclarativeMeta
 
     def get_db(self, context):
         raise NotImplementedError