I use: Python 2.6 and sqlalchemy 0.6.1

This is what I am trying to do:

from sqlalchemy.types import (
    Integer,
    String,
    Boolean
)
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class SampleMeta(type):
    def __new__(cls, name, bases, attrs):
        attrs.update({   'id': Column('Id', Integer, primary_key=True),
                    'name': Column('Name', String),
                    'description': Column('Description', String),
                    'is_active': Column('IsActive', Boolean)
                })
        return super(SampleMeta, cls).__new__(cls, name, bases, attrs)

class Sample(Base):
    __tablename__ = 'Sample'
    __table_args__ = {'useexisting': True}
    __metaclass__ = SampleMeta

    def __init__(self, id, name, description, is_active):
        self.id = id
        self.name = name
        self.description = description
        self.is_active = is_active

    def __repr__(self):
        return "<(%d, '%s', '%s', %r)>" % (self.id, self.name, self.description, self.isactive)

And the error I am getting is this:

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

Now, if I do the same thing above by using

class Sample(object)

instead of

class Sample(Base)

it works absolutely fine.

I need to update the attributes of the class dynamically. So, I will be using dynamic attribute and column names. And I need the above piece code to work in order to be able to get there.

Please help

Dani AI

Generated

Quick summary for : the error is the standard Python “metaclass conflict” — your Base (returned by declarative_base()) uses SQLAlchemy’s DeclarativeMeta, while your SampleMeta subclasses plain type. Python requires the final metaclass to be compatible with (a subclass of) the metaclasses of all base classes, so the class creation fails. (eli.thegreenplace.net)

Two practical approaches that avoid the error.

  1. If you really need a metaclass, make it a subclass of SQLAlchemy’s DeclarativeMeta and add columns by assigning them on the class object (not by mutating the dict passed into __new__/__init__). Newer Declarative internals won’t honor mutations of the incoming attrs dict; assign to cls or use a mixin instead. Also attach your metaclass to the declarative base so mapped classes inherit it. (docs.sqlalchemy.org)

Example pattern (not the same code in the thread — assigns to the class after DeclarativeMeta has run):

from sqlalchemy import Column, Integer, String, Boolean
from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base

class MyDeclarativeMeta(DeclarativeMeta):
    def __init__(cls, name, bases, dct):
        DeclarativeMeta.__init__(cls, name, bases, dct)
        # add dynamic columns by assigning to the class
        cls.id = Column('Id', Integer, primary_key=True)
        cls.name = Column('Name', String)
        cls.is_active = Column('IsActive', Boolean)

Base = declarative_base(metaclass=MyDeclarativeMeta)

class Sample(Base):
    __tablename__ = 'Sample'
  1. Prefer mixins + @declared_attr — this is cleaner, version-stable, and avoids metaclass complexity. Use a mixin that supplies the columns (possibly computed at class construction time) and inherit it alongside Base. (docs.sqlalchemy.org)

Example:

from sqlalchemy.ext.declarative import declared_attr

class CommonColsMixin(object):
    @declared_attr
    def id(cls):
        return Column('Id', Integer, primary_key=True)

    @declared_attr
    def name(cls):
        return Column('Name', String)

class Sample(CommonColsMixin, Base):
    __tablename__ = 'Sample'

Notes and cautions: SQLAlchemy’s declarative implementation has evolved — recent releases introduced DeclarativeBase / DeclarativeBaseNoMeta and __init_subclass__-based setup to avoid metaclass pain, so if upgrading is possible you may prefer those modern patterns for better tool and typing support. Also, DeclarativeMeta intercepts attribute assignment and will append Column objects to the table/mapper if you add them to a mapped class after creation. For these behaviors and for version-specific details, see the SQLAlchemy docs. (docs.sqlalchemy.org)

As hinted, the minimal change is to derive from DeclarativeMeta; the stronger suggestion (and more maintainable path) is to use mixins/declared_attr to inject dynamic columns instead of wrestling with metaclass internals.

I suggest something along the lines of

from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base

class SampleMeta(DeclarativeMeta):
    def __init__(cls, name, bases, attrs): # this is __init__ !
        attrs.update({   'id': Column('Id', Integer, primary_key=True),
                    'name': Column('Name', String),
                    'description': Column('Description', String),
                    'is_active': Column('IsActive', Boolean)
                })
        DeclarativeMeta.__init__(cls, name, bases, attrs)

Base = declarative_base(metaclass = SampleMeta)

class Sample(Base):
    # etc
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.