def test_as_declarative(self): class User(ComparableEntity): __tablename__ = 'users' id = Column('id', Integer, primary_key=True) name = Column('name', String(50)) addresses = relation("Address", backref="user") class Address(ComparableEntity): __tablename__ = 'addresses' id = Column('id', Integer, primary_key=True) email = Column('email', String(50)) user_id = Column('user_id', Integer, ForeignKey('users.id')) reg = {} decl.instrument_declarative(User, reg, Base.metadata) decl.instrument_declarative(Address, reg, Base.metadata) Base.metadata.create_all() u1 = User(name='u1', addresses=[ Address(email='one'), Address(email='two'), ]) sess = create_session() sess.add(u1) sess.flush() sess.clear() eq_(sess.query(User).all(), [User(name='u1', addresses=[ Address(email='one'), Address(email='two'), ])])
def test_as_declarative(self): class User(fixtures.ComparableEntity): __tablename__ = "users" id = Column("id", Integer, primary_key=True, test_needs_autoincrement=True) name = Column("name", String(50)) addresses = relationship("Address", backref="user") class Address(fixtures.ComparableEntity): __tablename__ = "addresses" id = Column("id", Integer, primary_key=True, test_needs_autoincrement=True) email = Column("email", String(50)) user_id = Column("user_id", Integer, ForeignKey("users.id")) reg = {} decl.instrument_declarative(User, reg, Base.metadata) decl.instrument_declarative(Address, reg, Base.metadata) Base.metadata.create_all() u1 = User(name="u1", addresses=[Address(email="one"), Address(email="two")]) sess = create_session() sess.add(u1) sess.flush() sess.expunge_all() eq_(sess.query(User).all(), [User(name="u1", addresses=[Address(email="one"), Address(email="two")])])
def execute(self, class_, tablename, metadata, reflected, tableargs, inherits, polymorphic_identity, polymorphic_on, **kw): class_.__tablename__ = tablename if tableargs is not None: class_.__table_args__ = tableargs if reflected: if not hasattr(metadata, '_reflected_registry'): metadata._reflected_registry = {} metadata._reflected_registry[class_] = dict( inherits=inherits, polymorphic_on=polymorphic_on, polymorphic_identity=polymorphic_identity, ) # if this table is reflected, don't instrument now but # manually map later return True # we associate the _decl_registry with the metadata object # to make sure it's unique per metadata. A bit of a hack.. if not hasattr(metadata, '_decl_registry'): metadata._decl_registry = {} try: instrument_declarative(class_, metadata._decl_registry, metadata) except sqlalchemy.exc.InvalidRequestError: # XXX scary - catching too many errors # allows re-grokking of classes that were already # instrument. Better would be to un-instrument classes # after tests, but how to uninstrument? pass return True
def register(): if ignore_reattach: if '_decl_class_registry' in ModelClass.__dict__: assert ModelClass._decl_class_registry == Base._decl_class_registry, "Tried to attach to a different Base" return instrument_declarative(ModelClass, Base._decl_class_registry, Base.metadata)
def attach_model_to_base(ModelClass:type, Base:type, ignore_reattach:bool=True): """Dynamically add a model to chosen SQLAlchemy Base class. More flexibility is gained by not inheriting from SQLAlchemy declarative base and instead plugging in models during the configuration time more. Directly inheritng from SQLAlchemy Base class has non-undoable side effects. All models automatically pollute SQLAlchemy namespace and may e.g. cause problems with conflicting table names. This also allows @declared_attr to access Pyramid registry. Example how to use Pyramid registry in SQLAlchemy's declared attributes:: class SamplePluggableModel: '''Demostrate pluggable model which gets a referred class from Pyramid config.''' id = Column(Integer, primary_key=True) def __init__(self, **kwargs): # Default constructor self.__dict__.update(kwargs) @declared_attr def owner(cls): '''Refer to the configured user model.''' from websauna.system.user.utils import get_user_class config = cls.metadata.pyramid_config User = get_user_class(config.registry) return relationship(User, backref="referral_programs") @declared_attr def owner_id(cls): '''Refer to user.id column''' from websauna.system.user.utils import get_user_class config = cls.metadata.pyramid_config User = get_user_class(config.registry) return Column(Integer, ForeignKey('{}.id'.format(User.__tablename__))) Then you need to call in your Initializer:: from example import models from websauna.system.model.meta import Base attach_model_to_base(models.SamplePluggableModel, Base) :param ModelClass: SQLAlchemy model class :param Base: SQLAlchemy declarative Base for which model should belong to :param ignore_reattach: Do nothing if ``ModelClass`` is already attached to base. Base registry is effectively global. ``attach_model_to_base()`` may be called several times within the same process during unit tests runs. Complain only if we try to attach a different base. """ if ignore_reattach: if '_decl_class_registry' in ModelClass.__dict__: assert ModelClass._decl_class_registry == Base._decl_class_registry, "Tried to attach to a different Base" return instrument_declarative(ModelClass, Base._decl_class_registry, Base.metadata)
def reflectTables(metadata): """Reflect tables into ORM. """ if getattr(metadata, '_reflected_completed', False): # XXX thread safety? return if not getattr(metadata, '_reflected_registry', {}): # nothing to reflect return # first reflect database-defined schemas into metadata engine = Engine() for class_ in metadata._reflected_registry.keys(): _reflectTableForClass(class_, metadata, engine) # reflect any remaining tables. This will not reload tables already loaded # (XXX is this necessary?) metadata.reflect(bind=engine) if not hasattr(metadata, '_decl_registry'): metadata._decl_registry = {} # XXX should sort by the inheritance tree for class_ in sorted(metadata._reflected_registry.keys(), key=lambda a: getattr(a, 'megrok.rdb.directive.inherits', 0)): class_args = metadata._reflected_registry[class_] polymorphic_on = class_args['polymorphic_on'] polymorphic_identity = class_args['polymorphic_identity'] inherits = class_args['inherits'] mapper_args = getattr(class_, '__mapper_args__', {}) if polymorphic_on: tablename, column = polymorphic_on mapper_args['polymorphic_on'] = getattr(metadata.tables[tablename].c, column) if polymorphic_identity: mapper_args['polymorphic_identity'] = polymorphic_identity if inherits: mapper_args['inherits'] = inherits if mapper_args: class_.__mapper_args__ = mapper_args instrument_declarative(class_, metadata._decl_registry, metadata) # XXX thread safety? metadata._reflected_completed = True
def test_difficult_class(self): """test no getattr() errors with a customized class""" # metaclass to mock the way zope.interface breaks getattr() class BrokenMeta(type): def __getattribute__(self, attr): if attr == "xyzzy": raise AttributeError, "xyzzy" else: return object.__getattribute__(self, attr) # even though this class has an xyzzy attribute, getattr(cls,"xyzzy") # fails class BrokenParent(object): __metaclass__ = BrokenMeta xyzzy = "magic" # _as_declarative() inspects obj.__class__.__bases__ class User(BrokenParent, fixtures.ComparableEntity): __tablename__ = "users" id = Column("id", Integer, primary_key=True, test_needs_autoincrement=True) name = Column("name", String(50)) decl.instrument_declarative(User, {}, Base.metadata)
title = schema.Column(types.Unicode(128)) address_visit_address = schema.Column(types.UnicodeText()) address_visit_postal = schema.Column(types.Unicode(16)) address_visit_city = schema.Column(types.Unicode(64)) address_postal_address = schema.Column(types.UnicodeText()) address_postal_postal = schema.Column(types.Unicode(16)) address_postal_city = schema.Column(types.Unicode(64)) email = schema.Column(types.String(128)) phone = schema.Column(types.String(32)) activity = schema.Column(types.Unicode(64)) submitter_name = schema.Column(types.Unicode(64)) submitter_function = schema.Column(types.Unicode(64)) department = schema.Column(types.Unicode(64)) location = schema.Column(types.Unicode(64)) submit_date = schema.Column(types.Date(), default=functions.now()) employees = schema.Column(Enum([None, "40h", "max25", "over25"])) absentee_percentage = schema.Column(types.Numeric(precision=5, scale=2)) accidents = schema.Column(types.Integer()) incapacitated_workers = schema.Column(types.Integer()) arbo_expert = schema.Column(types.Unicode(128)) works_council_approval = schema.Column(types.Date()) _instrumented = False if not _instrumented: from sqlalchemy.ext import declarative from euphorie.client import model declarative.instrument_declarative(DutchCompany, model.metadata._decl_registry, model.metadata) declarative.instrument_declarative(OdLink, model.metadata._decl_registry, model.metadata) _instrumented = True
planning_end = schema.Column(types.Date()) reference = schema.Column(types.Text()) risk = orm.relation(Risk, backref=orm.backref( "action_plans", order_by=id, cascade="all, delete, delete-orphan")) _instrumented = False if not _instrumented: metadata._decl_registry = {} for cls in [SurveyTreeItem, SurveySession, Module, Risk, ActionPlan, Account, AccountChangeRequest, Company]: declarative.instrument_declarative(cls, metadata._decl_registry, metadata) _instrumented = True schema.Index('tree_session_path', SurveyTreeItem.session_id, SurveyTreeItem.path) schema.Index('tree_zodb_path', SurveyTreeItem.session_id, SurveyTreeItem.profile_index, SurveyTreeItem.zodb_path) parent = orm.aliased(SurveyTreeItem) # XXX This can be optimized by doing short-circuit on parent.type!=module SKIPPED_PARENTS = \ sql.exists().where(sql.and_( parent.session_id == SurveyTreeItem.session_id,
ondelete="CASCADE"), nullable=False, index=True) account = orm.relation(model.Account, backref=orm.backref( "logins", cascade="all, delete, delete-orphan")) time = schema.Column(types.DateTime(timezone=False), server_default=sql.text('CURRENT_TIMESTAMP'), nullable=False, index=True) _instrumented = False if not _instrumented: for cls in [LoginStatistics]: instrument_declarative(cls, model.metadata._decl_registry, model.metadata) _instrumented = True node = orm.aliased(model.SurveyTreeItem) SKIPPED_MODULE = \ sql.exists().where( sql.and_( model.SurveyTreeItem.type == "module", node.session_id == model.SurveyTreeItem.session_id, node.skip_children == True ) ) UNANSWERED_RISKS_FILTER = \ sql.and_(model.SurveyTreeItem.type == "risk", sql.exists(sql.select([model.Risk.sql_risk_id]).where(sql.and_(
def configure(cls, *klasses): registry = {} for c in BaseMeta.classes: instrument_declarative(c, registry, cls.metadata)
def attach_model_to_base(ModelClass: type, Base: type, ignore_reattach: bool = True): """Dynamically add a model to chosen SQLAlchemy Base class. More flexibility is gained by not inheriting from SQLAlchemy declarative base and instead plugging in models during the configuration time more. Directly inheriting from SQLAlchemy Base class has non-undoable side effects. All models automatically pollute SQLAlchemy namespace and may e.g. cause problems with conflicting table names. This also allows @declared_attr to access Pyramid registry. Example how to use Pyramid registry in SQLAlchemy's declared attributes:: class SamplePluggableModel: '''Demostrate pluggable model which gets a referred class from Pyramid config.''' id = Column(Integer, primary_key=True) def __init__(self, **kwargs): # Default constructor self.__dict__.update(kwargs) @declared_attr def owner(cls): '''Refer to the configured user model.''' from websauna.system.user.utils import get_user_class config = cls.metadata.pyramid_config User = get_user_class(config.registry) return relationship(User, backref="referral_programs") @declared_attr def owner_id(cls): '''Refer to user.id column''' from websauna.system.user.utils import get_user_class config = cls.metadata.pyramid_config User = get_user_class(config.registry) return Column(Integer, ForeignKey('{}.id'.format(User.__tablename__))) Then you need to call in your Initializer:: from example import models from websauna.system.model.meta import Base attach_model_to_base(models.SamplePluggableModel, Base) :param ModelClass: SQLAlchemy model class :param Base: SQLAlchemy declarative Base for which model should belong to :param ignore_reattach: Do nothing if ``ModelClass`` is already attached to base. Base registry is effectively global. ``attach_model_to_base()`` may be called several times within the same process during unit tests runs. Complain only if we try to attach a different base. """ if ignore_reattach: if '_decl_class_registry' in ModelClass.__dict__: assert ModelClass._decl_class_registry == Base._decl_class_registry, "Tried to attach to a different Base" return instrument_declarative(ModelClass, Base._decl_class_registry, Base.metadata) # TODO: We now hardcode this event listener here. # from sqlalchemy.orm.instrumentation import _instrumentation_factory # _instrumentation_factory.dispatch.class_instrument(ModelClass) # The correct approach is through class_instrument() event firing, # but could not figure out yet how to make it happen with all bits flying around from .json import init_for_json init_for_json(ModelClass)
account_id = schema.Column( types.Integer(), schema.ForeignKey(model.Account.id, onupdate="CASCADE", ondelete="CASCADE"), nullable=False, index=True, ) account = orm.relation(model.Account, backref=orm.backref("logins", cascade="all, delete, delete-orphan")) time = schema.Column( types.DateTime(timezone=False), server_default=sql.text("CURRENT_TIMESTAMP"), nullable=False, index=True ) _instrumented = False if not _instrumented: for cls in [LoginStatistics]: instrument_declarative(cls, model.metadata._decl_registry, model.metadata) _instrumented = True node = orm.aliased(model.SurveyTreeItem) SKIPPED_MODULE = sql.exists().where( sql.and_( model.SurveyTreeItem.type == "module", node.session_id == model.SurveyTreeItem.session_id, node.skip_children == True, ) ) UNANSWERED_RISKS_FILTER = sql.and_( model.SurveyTreeItem.type == "risk", sql.exists( sql.select([model.Risk.sql_risk_id]).where(
def configure(cls, *klasses): registry = {} for bmc in BaseMeta.classes: instrument_declarative(bmc, registry, cls.metadata)
address_postal_postal = schema.Column(types.Unicode(16)) address_postal_city = schema.Column(types.Unicode(64)) email = schema.Column(types.String(128)) phone = schema.Column(types.String(32)) activity = schema.Column(types.Unicode(64)) submitter_name = schema.Column(types.Unicode(64)) submitter_function = schema.Column(types.Unicode(64)) department = schema.Column(types.Unicode(64)) location = schema.Column(types.Unicode(64)) submit_date = schema.Column(types.Date(), default=functions.now()) employees = schema.Column(Enum([None, "40h", "max25", "over25"])) absentee_percentage = schema.Column(types.Numeric(precision=5, scale=2)) accidents = schema.Column(types.Integer()) incapacitated_workers = schema.Column(types.Integer()) arbo_expert = schema.Column(types.Unicode(128)) works_council_approval = schema.Column(types.Date()) _instrumented = False if not _instrumented: from euphorie.client import model from sqlalchemy.ext import declarative declarative.instrument_declarative( DutchCompany, model.metadata._decl_registry, model.metadata ) declarative.instrument_declarative( OdLink, model.metadata._decl_registry, model.metadata ) _instrumented = True