Hi,

if I declaratively map a class with a mix-in and with a __table__
definition that contains the columns in the mix-in, like so:

class MyMixin(object):
    id =  Column(Integer, primary_key=True)
    def foo(self):
        return 'bar'+str(self.id)

class MyModel(Base,MyMixin):
    __table__ = Table('test', Base.metadata,
        Column('id', Integer, primary_key=True),
        Column('name', String(1000), nullable=False, index=True)
        )

… then I get a fairly cryptic error:

Traceback (most recent call last):
  File "mixin_trouble.py", line 12, in <module>
    class MyModel(Base,MyMixin):
  File "/Users/gthb/extsvn/sqlalchemy/lib/sqlalchemy/ext/
declarative.py", line 830, in __init__
    _as_declarative(cls, classname, cls.__dict__)
  File "/Users/gthb/extsvn/sqlalchemy/lib/sqlalchemy/ext/
declarative.py", line 681, in _as_declarative
    if tablename or k not in parent_columns:
TypeError: Error when calling the metaclass bases
    argument of type 'NoneType' is not iterable

The real reason is that the case of __table__ with a mix-in is not
handled. If MyModel were defined with __tablename__ and id =
Column(Integer, primary_key=True), then tablename would be truey and
parent_columns would not be checked, so this would not come up.

We could just improve the error message by checking for this
unsupported case. But it seems fairly easy to support it. This simple
change makes the above case work, and breaks no unit tests:

diff -r dd463bfb847d lib/sqlalchemy/ext/declarative.py
--- a/lib/sqlalchemy/ext/declarative.py Mon May 31 15:22:55 2010 -0400
+++ b/lib/sqlalchemy/ext/declarative.py Fri Jun 04 19:05:16 2010 +0000
@@ -670,7 +670,9 @@
                                 "Columns with foreign keys to other
columns "
                                 "are not allowed on declarative
mixins at this time."
                             )
-                        if name not in dict_:
+                        if name not in dict_ and not (
+                                '__table__' in dict_ and name in
dict_['__table__'].c
+                                ):
 
potential_columns[name]=column_copies[obj]=obj.copy()
                     elif isinstance(obj, RelationshipProperty):
                         raise exceptions.InvalidRequestError(

I may be missing something else that needs to be done in this case,
but in any case this gets my codebase (which I've just modified to use
a mix-in like this instead of a metaclass) running and passing its
tests without problems.

Also, since I've got your attention there, shouldn't this place really
check (in both this new __table__ case and the already-supported
__tablename__ case) that the column definitions are identical, or at
least mostly equivalent? If they don't, then the mix-in class'
expectations are not fulfilled and that may cause all sorts of trouble
so it's better to bump into it right away.

To that end, is there an existing way to check column definition
equality/equivalence, i.e. comparing at least type, constraints and
default and primary_key, and maybe also autoincrement, base_columns,
etc.?

Regards,

    - Gulli

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to