def __init__(cls, name, bases, dict_): # Only process further subclasses of the base classes (Entity et al.), # not the base classes themselves. We don't want the base entities to # be registered in an entity collection, nor to have a table name and # so on. if not is_entity(cls): return # create the entity descriptor desc = cls._descriptor = EntityDescriptor(cls) # Determine whether this entity is a *direct* subclass of its base # entity entity_base = None for base in cls.__bases__: if isinstance(base, EntityMeta): if not is_entity(base): entity_base = base if entity_base: # If so, copy the base entity properties ('Property' instances). # We use inspect.getmembers (instead of __dict__) so that we also # get the properties from the parents of the base_class if any. base_props = inspect.getmembers(entity_base, lambda a: isinstance(a, Property)) base_props = [(name, copy(attr)) for name, attr in base_props] else: base_props = [] # Process attributes (using the assignment syntax), looking for # 'Property' instances and attaching them to this entity. properties = [(name, attr) for name, attr in cls.__dict__.iteritems() if isinstance(attr, Property)] sorted_props = sorted(base_props + properties, key=lambda i: i[1]._counter) for name, prop in sorted_props: prop.attach(cls, name) # Process mutators. Needed before _install_autosetup_triggers so that # we know of the metadata process_mutators(cls) # setup misc options here (like tablename etc.) desc.setup_options() # create trigger proxies # TODO: support entity_name... It makes sense only for autoloaded # tables for now, and would make more sense if we support "external" # tables if desc.autosetup: _install_autosetup_triggers(cls)
def instrument_class(cls): """ Instrument a class as an Entity. This is usually done automatically through the EntityMeta metaclass. """ # Create the entity descriptor desc = cls._descriptor = EntityDescriptor(cls) # Process mutators # We *do* want mutators to be processed for base/abstract classes # (so that statements like using_options_defaults work). process_mutators(cls) # We do not want to do any more processing for base/abstract classes # (Entity et al.). if not is_entity(cls) or is_abstract_entity(cls): return cls.table = None cls.mapper = None # Copy the properties ('Property' instances) of the entity base class(es). # We use getmembers (instead of __dict__) so that we also get the # properties from the parents of the base class if any. base_props = [] for base in cls.__bases__: if isinstance(base, EntityMeta) and \ (not is_entity(base) or is_abstract_entity(base)): base_props += [(name, deepcopy(attr)) for name, attr in getmembers(base, lambda a: isinstance(a, Property))] # Process attributes (using the assignment syntax), looking for # 'Property' instances and attaching them to this entity. properties = [(name, attr) for name, attr in cls.__dict__.iteritems() if isinstance(attr, Property)] sorted_props = sorted(base_props + properties, key=lambda i: i[1]._counter) for name, prop in sorted_props: prop.attach(cls, name) # setup misc options here (like tablename etc.) desc.setup_options() # create trigger proxies # TODO: support entity_name... It makes sense only for autoloaded # tables for now, and would make more sense if we support "external" # tables if desc.autosetup: _install_autosetup_triggers(cls)