]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- @classproperty (soon/now @mapperproperty) takes effect for
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 20 Sep 2010 16:00:14 +0000 (12:00 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 20 Sep 2010 16:00:14 +0000 (12:00 -0400)
__mapper_args__, __table_args__, __tablename__ on
a base class that is not a mixin, as well as mixins.
[ticket:1922]

CHANGES
lib/sqlalchemy/ext/declarative.py
test/ext/test_declarative.py

diff --git a/CHANGES b/CHANGES
index 7d72f8769fb7e1a05e899be1a9afc428a308cb9b..04457ef447e90ae4ead6ee3512633003818062ee 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -103,6 +103,12 @@ CHANGES
    - as_scalar(), label() can be called on a selectable
      which contains a Column that is not yet named.
      [ticket:1862]
+
+- declarative
+   - @classproperty (soon/now @mapperproperty) takes effect for 
+     __mapper_args__, __table_args__, __tablename__ on 
+     a base class that is not a mixin, as well as mixins.
+     [ticket:1922]
      
 - engine
    
index 40263c7b802974700deb529d4a78111d2a3b2f75..ad08d7873d12bd4b604322f8d36828e60f95a0c2 100755 (executable)
@@ -908,51 +908,63 @@ def _as_declarative(cls, classname, dict_):
     parent_columns = ()
     
     for base in cls.__mro__:
-        if _is_mapped_class(base):
+        class_mapped = _is_mapped_class(base)
+        if class_mapped:
             parent_columns = base.__table__.c.keys()
-        else:
-            for name,obj in vars(base).items():
-                if name == '__mapper_args__':
-                    if not mapper_args:
-                        mapper_args = cls.__mapper_args__
-                elif name == '__tablename__':
-                    if not tablename:
-                        tablename = cls.__tablename__
-                elif name == '__table_args__':
-                    if not table_args:                        
-                        table_args = cls.__table_args__
-                        if base is not cls:
-                            inherited_table_args = True
-                elif base is not cls:
-                    # 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 dict_ and not (
-                                '__table__' in dict_ and 
-                                name in dict_['__table__'].c
-                                ):
-                            potential_columns[name] = \
-                                    column_copies[obj] = \
-                                    obj.copy()
-                            column_copies[obj]._creation_order = \
-                                    obj._creation_order
-                    elif isinstance(obj, MapperProperty):
+            
+        for name,obj in vars(base).items():
+            if name == '__mapper_args__':
+                if not mapper_args and (
+                                        not class_mapped or 
+                                        isinstance(obj, util.classproperty)
+                                    ):
+                    mapper_args = cls.__mapper_args__
+            elif name == '__tablename__':
+                if not tablename and (
+                                        not class_mapped or 
+                                        isinstance(obj, util.classproperty)
+                                    ):
+                    tablename = cls.__tablename__
+            elif name == '__table_args__':
+                if not table_args and (
+                                        not class_mapped or 
+                                        isinstance(obj, util.classproperty)
+                                    ):
+                    table_args = cls.__table_args__
+                    if base is not cls:
+                        inherited_table_args = True
+            elif class_mapped:
+                continue
+            elif base is not cls:
+                # we're a mixin.
+                
+                if isinstance(obj, Column):
+                    if obj.foreign_keys:
                         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):
-                        dict_[name] = ret = \
-                                column_copies[obj] = getattr(cls, name)
-                        if isinstance(ret, (Column, MapperProperty)) and \
-                            ret.doc is None:
-                            ret.doc = obj.__doc__
+                        "Columns with foreign keys to other columns "
+                        "must be declared as @classproperty callables "
+                        "on declarative mixin classes. ")
+                    if name not in dict_ and not (
+                            '__table__' in dict_ and 
+                            name in dict_['__table__'].c
+                            ):
+                        potential_columns[name] = \
+                                column_copies[obj] = \
+                                obj.copy()
+                        column_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):
+                    dict_[name] = ret = \
+                            column_copies[obj] = getattr(cls, name)
+                    if isinstance(ret, (Column, MapperProperty)) and \
+                        ret.doc is None:
+                        ret.doc = obj.__doc__
 
     # apply inherited columns as we should
     for k, v in potential_columns.items():
index 65ec92ca290e095497fec3d4e54973f02066ba4e..f628d1dc74ec7dd118a32affb66f01d7773d28af 100644 (file)
@@ -2458,18 +2458,62 @@ class DeclarativeMixinTest(DeclarativeTestBase):
             __tablename__ = 'test'
 
             @classproperty
-            def __mapper_args__(self):
+            def __mapper_args__(cls):
                 args = {}
                 args.update(MyMixin1.__mapper_args__)
                 args.update(MyMixin2.__mapper_args__)
+                if cls.__name__ != 'MyModel':
+                    args.pop('polymorphic_on')
+                    args['polymorphic_identity'] = cls.__name__
+                    
                 return args
             id = Column(Integer, primary_key=True)
-
-        col = MyModel.__mapper__.polymorphic_on
-        eq_(col.name, 'type_')
-        assert col.table is not None
+        
+        class MySubModel(MyModel):
+            pass
+        
+        eq_(
+            MyModel.__mapper__.polymorphic_on.name, 
+            'type_'
+        )
+        assert MyModel.__mapper__.polymorphic_on.table is not None
         eq_(MyModel.__mapper__.always_refresh, True)
+        eq_(MySubModel.__mapper__.always_refresh, True)
+        eq_(MySubModel.__mapper__.polymorphic_identity, 'MySubModel')
+    
+    def test_mapper_args_property(self):
+        class MyModel(Base):
+            
+            @classproperty
+            def __tablename__(cls):
+                return cls.__name__.lower()
+            
+            @classproperty
+            def __table_args__(cls):
+                return {'mysql_engine':'InnoDB'}
+                
+            @classproperty
+            def __mapper_args__(cls):
+                args = {}
+                args['polymorphic_identity'] = cls.__name__
+                return args
+            id = Column(Integer, primary_key=True)
+        
+        class MySubModel(MyModel):
+            id = Column(Integer, ForeignKey('mymodel.id'), primary_key=True)
 
+        class MySubModel2(MyModel):
+            __tablename__ = 'sometable'
+            id = Column(Integer, ForeignKey('mymodel.id'), primary_key=True)
+        
+        eq_(MyModel.__mapper__.polymorphic_identity, 'MyModel')
+        eq_(MySubModel.__mapper__.polymorphic_identity, 'MySubModel')
+        eq_(MyModel.__table__.kwargs['mysql_engine'], 'InnoDB')
+        eq_(MySubModel.__table__.kwargs['mysql_engine'], 'InnoDB')
+        eq_(MySubModel2.__table__.kwargs['mysql_engine'], 'InnoDB')
+        eq_(MyModel.__table__.name, 'mymodel')
+        eq_(MySubModel.__table__.name, 'mysubmodel')
+        
     def test_single_table_no_propagation(self):
 
         class IdColumn: