0

Edit

The problem was in importing. What I should have done was write: from SomeInterface import SomeInterface. Really I should write module name in lowercase someinterface.py as per Python styleguide (PEP 8).


I have a file model.py the defines all classes related to my DB as well as instantiates my Base.

# model.py
metadata = MetaData()
DeclarativeBase = declarative_base()
metadata = DeclarativeBase.metadata

class Bar(DeclarativeBase):
    __tablename__ = 'Bar'
    __table_args__ = {}
    # column and relation definitions

The file model.py is autogenerated so I can't really touch it. What I did instead was create a file called modelaugmented.py where I add extra functionality to some of the model classes via inheritance.

# modelaugmented.py
from model import *
import SomeInterface

class BarAugmented(Bar, SomeInterface):
    pass

# SomeInterface.py
class SomeInterface(object):
    some_method(): pass

The problem I'm having is that for classes like BarAugmented, I'm getting the following error:

 TypeError: Error when calling the metaclass bases
 metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

I only get this error when SomeInterface is in a separate file instead of being inside modelaugmented.py.

I understand that the metaclass for SomeInterface and Bar are different. The problem is that I can't figure out how to resolve this problem. I tried the solution suggested in Triple inheritance causes metaclass conflict... Sometimes which works in the example given, but not in my case. Not sure if SqlAlchmey has anything to do with it.

class MetaAB(type(DeclarativeBase), type(SomeInterface)):
    pass

class BarAugmented(Bar, SomeInterface):
    __metaclass__ = MetaAB

But then I get the error:

TypeError: Error when calling the metaclass 
bases multiple bases have instance lay-out conflict

Using SQLAlchemy 0.8 and Python 2.7.

Community
  • 1
  • 1
Kamil Sindi
  • 21,782
  • 19
  • 96
  • 120
  • yep... you're facing a problem of multiple inheritance. There will be another problem... In `BarAugmented`, what's the `__table__ ` it has to save the data to? Table `foo`? Table `bar`? Do you REALLY need this type of schema? (just asking, but it looks like a very complex structure for any ORM to handle properly) – Savir Apr 09 '14 at 21:13
  • @BorrajaX very fair points. I edited my question. – Kamil Sindi Apr 09 '14 at 21:21
  • MHmm... It looks like the problem is not in SqlAlchemy... Take a look to this: http://stackoverflow.com/questions/6557407/triple-inheritance-causes-metaclass-conflict-sometimes and http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/ (I just found those links, I don't know if they'll be helpful) Could you try a non-declarative declaration? (just declare your table, then your class, then your mapping) ? – Savir Apr 09 '14 at 21:27
  • @BorrajaX thanks for the links. I tried them earlier but unfortunately I get the error `'SomeInterface' has no attribute '_decl_class_registry'`. – Kamil Sindi Apr 09 '14 at 21:31
  • 1
    Sorry about that **:-(** I'd go with a non-declarative, then. Doing the declarative model will probably alter your class `__metaclass__` (but wait for a real answer, though... you may not need to do that anyways) – Savir Apr 09 '14 at 21:33
  • I assume it is not the case, but if you need the same base class/interface for all your mapped classes, you could specify it as a `cls` parameter of [`declarative_base`](http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative.html#sqlalchemy.ext.declarative.declarative_base.params.cls) – van Apr 10 '14 at 08:32
  • Thanks for the suggestion. Unfortunately that's not the case. – Kamil Sindi Apr 10 '14 at 11:49

1 Answers1

1

Ok, there must be something I'm missing, because I created a similar file layout to yours (I think) and it works in my machine. I appreciate you kept your question short and simple, but maybe is missing some little detail that alters... something? Dunno... (maybe SomeInterface has an abc.abstract metaclass?) If you update your question, please let me know trough a comment to this answer, and I'll try to update my answer.

Here it goes:

File stack29A.py (equivalent to your model.py):

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session

DSN = "mysql://root:foobar@localhost/so_tests?charset=utf8"
engine = create_engine(DSN)
Session = scoped_session(sessionmaker(bind=engine))
session = Session()

DeclarativeBase = declarative_base()

class Bar(DeclarativeBase):
    __tablename__ = 'Bar'
    _id = Column('_id', Integer, primary_key=True)
    email = Column('email', String(50)) 

File stack29B.py (equivalent to your someinterface.py):

class SomeInterface(object):
    def some_method(self):
        print "hellou"   

File stack29C.py (equivalent to your modelaugmented.py):

from stack29A import Bar
from stack29B import SomeInterface

class BarAugmented(Bar, SomeInterface):
    pass

File stack29D.py (like a kind of main.py: table creator and sample):

from stack29C import BarAugmented
from stack29A import session, engine, DeclarativeBase

if __name__ == "__main__":
    DeclarativeBase.metadata.create_all(engine)
    b1 = BarAugmented()
    b1.email = "foo@bar.baz"
    b2 = BarAugmented()
    b2.email = "baz@bar.foo"
    session.add_all([b1, b2])
    session.commit()
    b3 = session.query(BarAugmented)\
                    .filter(BarAugmented.email == "foo@bar.baz")\
                    .first()
    print "b3.email: %s" % b3.email                    
    b3.some_method()

If I run the "main" file (stack29D.py) everything works as expected:

(venv_SO)borrajax@borrajax:~/Documents/Tests$ python ./stack29D.py
b3.email: foo@bar.baz
hellou
Savir
  • 17,568
  • 15
  • 82
  • 136
  • Thanks @BorrajaX. Really helpful. Trying to figure out why mine is not working. It could be because my `SomeInterface` has methods that do session queries (but it still inherits from object). – Kamil Sindi Apr 10 '14 at 19:26
  • I'll figure it out and report back. – Kamil Sindi Apr 10 '14 at 19:37
  • Yeah, that's odd... that wouldn't alter the metaclass... Yeah, let me know. I'm curious myself now **:-)** – Savir Apr 10 '14 at 19:38
  • very embarrasing. The problem was in importing. What I should have done was write: `from SomeInterface import SomeInterface`. I'm relatively new to Python. – Kamil Sindi Apr 10 '14 at 19:57
  • Glad I was helpful somehow... (somehow... because I hope I helped figuring out the problem, not that I solved the problem) **:-D** – Savir Apr 10 '14 at 20:28
  • definitely helped figure it out. Also taught me I shouldn't be inheriting from multiple table classes. – Kamil Sindi Apr 10 '14 at 20:29