python - Inheriting AbstractConcreteBase multiple times [was: Adding an Auto-ID field to a model base class via mixin] -


i have created modelbase class application of mine based on sqlalchemy.

to save me tedious work of having type out id = column(integer, primary_key=true) provided attribute default id on modelbase class.

base = declarative_base()  class modelbase(abstractconcretebase, base):     id = column(integer, primary_key=true)      def __init__(self, *args, **kwargs):         """ constructor """         # nifty magic, keyword cleaning on kwargs, might have data          # coming json input          super(modelbase,self).__init__(*args, **kwargs)      def do_sth_else(self):          """ shared fundamental logic, json (de)serialization """ 

i should't have done this, because classes have id integer field. turns out, want use composite keys on models, still want have default of model class having id primary key. decided write mixin class , provide different modelbase classes.

base = declarative_base()  class idmixin(object):     id = column(integer, primary_key=true)  class abstractmodelbase(object):      def __init__(self, json_data='', *args, **kwargs):         """ same constructor """         super(abstractmodelbase,self).__init__(*args, **kwargs)      def do_sth_else(self):          """ same shared fundamental logic """  class modelbase(abstractconcretebase, base, idmixin, abstractmodelbase):     """ new model base class """  class noidmodelbase(abstractconcretebase, base, abstractmodelbase):     """ new model base class """ 

however, instantiating class keyword dictionary gave me painful stack trace:

$ ./manage.py test # no, not django ;) # test 1 of 30 =============== traceback (most recent call last):   file "./manage.py", line 40, in <module>     execute_command(sys.argv)   file "./manage.py", line 36, in execute_command     cmd(argv[2:])   file "./management/test.py", line 362, in handle     dbtestrunner(verbosity=args.verbosity).run(tests)   file "./management/test.py", line 172, in run     setupdb(t)   file "./management/test.py", line 134, in setupdb     instance = model_class(**d) ### instantiation occurs here ###   file "<string>", line 2, in __init__   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/orm/instrumentation.py", line 310, in _new_state_if_none     state = self._state_constructor(instance, self)   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 582, in __get__     obj.__dict__[self.__name__] = result = self.fget(obj)   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/orm/instrumentation.py", line 145, in _state_constructor     self.dispatch.first_init(self, self.class_)   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/event.py", line 409, in __call__     fn(*args, **kw)   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2197, in _event_on_first_init     configure_mappers()   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2123, in configure_mappers     _call_configured.dispatch.after_configured()   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/event.py", line 372, in __call__     fn(*args, **kw)   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/orm/events.py", line 489, in wrap     wrapped_fn(*arg, **kw)   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 51, in go     cls.__declare_last__()   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 347, in __declare_last__     cls.__mapper__ = m = mapper(cls, pjoin, polymorphic_on=pjoin.c.type)   file "/path/to/code/refactoring/.env/lib/python2.7/site-packages/sqlalchemy/util/_collections.py", line 172, in __getattr__     raise attributeerror(key) attributeerror: type 

the constructor of model class called in method:

def setupdb(test):     test.db_engine = create_engine('sqlite:///:memory:', convert_unicode=true)     session_factory.configure(bind=test.db_engine)     db_session = scoped_session(session_factory)     modelbase.metadata.create_all(test.db_engine)      test.client = client(app, response)      if (hasattr(test, "fixtures")):         # load fixtures json         fixtures = test.fixtures         if isinstance(fixtures, basestring):             fixtures = (fixtures, )         elif isinstance(fixtures, collections.iterable):             pass         else:             raise exception(                 "fixtures attribute needs string or iterable of strings")          fixture in fixtures:             try:                 open(fixture, 'r') f:                     fixture = json.loads(f.read())                  # apply fixture database                 entry in fixture:                     model = entry["model"]                     # import module containing model class                     model_module = importlib.import_module(                         model[:model.rfind(".")])                     # model class                     model_class = getattr(                         model_module, model[model.rfind(".") + 1:])                      # create instance of model class                     # each entry in "data"                     data = entry["data"]                     d in data:                         instance = model_class(**d)                         instance.save()             except ioerror e:                 print "could not load fixture!\n"                 print e                 sys.exit(1) 

you have deeper problem notice traceback (though it's related). column needs called once each actual column in database, if 4 tables have id columns, need equal number of column objects created.

fortunately, that's exact problem solved declared_attr. can arrange declarative_base set common functionality across subclasses, cls argument. combining both:

from sqlalchemy.ext.declarative import declarative_base sqlalchemy.ext.declarative import declared_attr   class modelbase(object):      def __init__(self, json_data='', *args, **kwargs):         """ same constructor """         super(modelbase,self).__init__(*args, **kwargs)      def do_sth_else(self):          """ same shared fundamental logic """   base = declarative_base(cls=modelbase)  class idmixin(object):     @declared_attr     def id(cls):         return column(integer, primary_key=true)  class modelbase(base, idmixin):     """ new model base class """  class noidmodelbase(base):     """ new model base class """ 

Comments

Popular posts from this blog

curl - PHP fsockopen help required -

HTTP/1.0 407 Proxy Authentication Required PHP -

c# - Resource not found error -