سؤال

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.

هل كانت مفيدة؟

المحلول

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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top