- @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]
This commit is contained in:
Mike Bayer
2010-09-20 12:00:14 -04:00
parent c5c8cdf3b4
commit 4fbd16e045
3 changed files with 110 additions and 48 deletions
+6
View File
@@ -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
+55 -43
View File
@@ -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():
+49 -5
View 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: