Changeset 267

Show
Ignore:
Timestamp:
11/14/07 10:57:14 (6 years ago)
Author:
ged
Message:
  • cleanup class attributes (in the attributes-based syntax) after the
    property is attached to its entity, so that SQLAlchemy is not confused.
    Only caused problem in the case of single inheritance and when omitting
    some values. See SA ticket #866.
  • some PEP8 fixes
Location:
elixir/trunk
Files:
12 modified

Legend:

Unmodified
Added
Removed
  • elixir/trunk/elixir/__init__.py

    r263 r267  
    33 
    44A declarative layer on top of the `SQLAlchemy library 
    5 <http://www.sqlalchemy.org/>`_. It is a fairly thin wrapper, which provides  
    6 the ability to create simple Python classes that map directly to relational  
     5<http://www.sqlalchemy.org/>`_. It is a fairly thin wrapper, which provides 
     6the ability to create simple Python classes that map directly to relational 
    77database tables (this pattern is often referred to as the Active Record design 
    8 pattern), providing many of the benefits of traditional databases  
     8pattern), providing many of the benefits of traditional databases 
    99without losing the convenience of Python objects.  
    1010 
    11 Elixir is intended to replace the ActiveMapper SQLAlchemy extension, and the  
     11Elixir is intended to replace the ActiveMapper SQLAlchemy extension, and the 
    1212TurboEntity project but does not intend to replace SQLAlchemy's core features, 
    13 and instead focuses on providing a simpler syntax for defining model objects  
    14 when you do not need the full expressiveness of SQLAlchemy's manual mapper  
     13and instead focuses on providing a simpler syntax for defining model objects 
     14when you do not need the full expressiveness of SQLAlchemy's manual mapper 
    1515definitions. 
    1616''' 
     
    9292entities = list() 
    9393 
     94 
    9495def create_all(*args, **kwargs): 
    9596    '''Create the necessary tables for all declared entities''' 
    9697    for md in metadatas: 
    9798        md.create_all(*args, **kwargs) 
     99 
    98100 
    99101def drop_all(*args, **kwargs): 
     
    118120        create_all(*args, **kwargs) 
    119121 
     122 
    120123def cleanup_all(drop_tables=False, *args, **kwargs): 
    121124    '''Clear all mappers, clear the session, and clear all metadatas.  
  • elixir/trunk/elixir/entity.py

    r265 r267  
    3333    # Not on sqlalchemy version 0.4 
    3434    ScopedSession = type(None) 
    35      
     35 
     36 
    3637def _do_mapping(session, cls, *args, **kwargs): 
    3738    if session is None: 
     
    5152            def __getattr__(s, key): 
    5253                return getattr(session.registry().query(cls), key) 
     54 
    5355            def __call__(s): 
    5456                return session.registry().query(cls) 
     
    252254                return 
    253255            elif self.inheritance == 'concrete': 
    254                # copy all columns from parent table 
    255                for col in self.parent._descriptor.columns: 
     256                # copy all columns from parent table 
     257                for col in self.parent._descriptor.columns: 
    256258                    self.add_column(col.copy()) 
    257                #FIXME: copy constraints. But those are not as simple to copy 
    258                #since the source column must be changed 
     259                #FIXME: copy constraints. But those are not as simple to copy 
     260                #since the source column must be changed 
    259261 
    260262        if self.polymorphic and self.inheritance in ('single', 'multi') and \ 
     
    524526 
    525527    def columns(self): 
    526         #FIXME: this would be more correct but it breaks inheritance, so I'll use the 
    527         # old test for now. 
     528        #FIXME: this would be more correct but it breaks inheritance, so I'll  
     529        # use the old test for now. 
    528530#        if self.entity.table: 
    529531        if self.autoload:  
     
    567569        return "<TriggerProxy (%s)>" % (self.class_.__name__) 
    568570 
     571 
    569572class TriggerAttribute(object): 
     573 
    570574    def __init__(self, attrname): 
    571575        self.attrname = attrname 
     
    581585def _is_entity(class_): 
    582586    return isinstance(class_, EntityMeta) 
     587 
    583588 
    584589class EntityMeta(type): 
     
    733738            method() 
    734739 
     740 
    735741def cleanup_entities(entities): 
    736742    """ 
  • elixir/trunk/elixir/events.py

    r177 r267  
    77    'after_delete' 
    88] 
     9 
    910 
    1011def create_decorator(event_name): 
  • elixir/trunk/elixir/ext/associable.py

    r263 r267  
    1414 
    1515Polymorphic associations lower the amount of many-to-many tables by setting up 
    16 a table that allows relations to any other table in the database, and relates it 
    17 to the associable table. In some implementations, this layout does not enforce 
    18 referential integrity with database foreign key constraints, this implementation 
    19 uses an additional many-to-many table with foreign key constraints to avoid 
    20 this problem. 
     16a table that allows relations to any other table in the database, and relates  
     17it to the associable table. In some implementations, this layout does not  
     18enforce referential integrity with database foreign key constraints, this  
     19implementation uses an additional many-to-many table with foreign key  
     20constraints to avoid this problem. 
    2121 
    2222.. note: 
     
    116116__doc_all__ = ['associable'] 
    117117 
     118 
    118119def associable(assoc_entity, plural_name=None, lazy=True): 
    119120    ''' 
     
    130131 
    131132    class GenericAssoc(object): 
     133     
    132134        def __init__(self, tablename): 
    133135            self.type = tablename 
     
    136138    class Associable(object): 
    137139        """An associable Elixir Statement object""" 
     140         
    138141        def __init__(self, entity, name=None, uselist=True, lazy=True): 
    139142            self.entity = entity 
     
    152155 
    153156            if not hasattr(assoc_entity, '_assoc_table'): 
    154                 association_table = sa.Table("%s" % able_name, assoc_entity._descriptor.metadata, 
     157                metadata = assoc_entity._descriptor.metadata 
     158                association_table = sa.Table("%s" % able_name, metadata, 
    155159                    sa.Column('id', sa.Integer, primary_key=True), 
    156160                    sa.Column('type', sa.String(40), nullable=False), 
    157161                ) 
    158                  
    159                 association_to_table = sa.Table("%s_to_%s" % (able_name, interface_name), assoc_entity._descriptor.metadata, 
    160                     sa.Column('assoc_id', sa.Integer, sa.ForeignKey(association_table.c.id, ondelete="CASCADE"), primary_key=True), 
     162                tablename =  "%s_to_%s" % (able_name, interface_name) 
     163                association_to_table = sa.Table(tablename, metadata, 
     164                    sa.Column('assoc_id', sa.Integer,  
     165                              sa.ForeignKey(association_table.c.id,  
     166                                            ondelete="CASCADE"),  
     167                              primary_key=True), 
    161168                    #FIXME: this assumes a single id col 
    162                     sa.Column('%s_id' % interface_name, sa.Integer, sa.ForeignKey(assoc_entity.table.c.id, ondelete="RESTRICT"), primary_key=True), 
     169                    sa.Column('%s_id' % interface_name, sa.Integer,  
     170                              sa.ForeignKey(assoc_entity.table.c.id,  
     171                                            ondelete="RESTRICT"),  
     172                              primary_key=True), 
    163173                ) 
    164174 
     
    212222            # add helper methods 
    213223            def select_by(cls, **kwargs): 
    214                 return cls.query.join([attr_name, 'targets']).filter_by(**kwargs).all() 
     224                return cls.query.join([attr_name, 'targets']) \ 
     225                                .filter_by(**kwargs).all() 
    215226            setattr(entity, 'select_by_%s' % self.name, classmethod(select_by)) 
    216227             
    217228            def select(cls, *args, **kwargs): 
    218                 return cls.query.join([attr_name, 'targets']).filter(*args, **kwargs).all() 
     229                return cls.query.join([attr_name, 'targets']) \ 
     230                                .filter(*args, **kwargs).all() 
    219231            setattr(entity, 'select_%s' % self.name, classmethod(select)) 
    220232 
  • elixir/trunk/elixir/ext/encrypted.py

    r264 r267  
    3434__doc_all__ = [] 
    3535 
     36 
    3637# 
    3738# encryption and decryption functions 
     
    5253 
    5354class ActsAsEncrypted(object):     
     55 
    5456    def __init__(self, entity, for_fields=[], with_secret='abcdef'): 
    5557         
  • elixir/trunk/elixir/ext/versioned.py

    r263 r267  
    9090         
    9191    def after_insert(self, mapper, connection, instance): 
    92         colvalues = dict([(key, getattr(instance, key)) for key in instance.c.keys()]) 
     92        colvalues = dict([(key, getattr(instance, key))  
     93                          for key in instance.c.keys()]) 
    9394        instance.__class__.__history_table__.insert().execute(colvalues) 
    9495        return EXT_PASS 
    9596     
    9697    def before_update(self, mapper, connection, instance): 
    97         colvalues = dict([(key, getattr(instance, key)) for key in instance.c.keys()]) 
     98        colvalues = dict([(key, getattr(instance, key))  
     99                          for key in instance.c.keys()]) 
    98100        history = instance.__class__.__history_table__ 
    99101         
     
    237239            return differences 
    238240         
    239         entity.versions      = property(get_versions) 
    240         entity.get_as_of     = get_as_of 
    241         entity.revert_to     = revert_to 
    242         entity.revert        = revert 
    243         entity.compare_with  = compare_with 
     241        entity.versions = property(get_versions) 
     242        entity.get_as_of = get_as_of 
     243        entity.revert_to = revert_to 
     244        entity.revert = revert 
     245        entity.compare_with = compare_with 
    244246        Version.compare_with = compare_with 
    245247 
  • elixir/trunk/elixir/fields.py

    r243 r267  
    200200 
    201201        if self.synonym: 
    202             self.entity._descriptor.add_property(self.synonym, synonym(self.name)) 
     202            self.entity._descriptor.add_property(self.synonym,  
     203                                                 synonym(self.name)) 
    203204 
    204205 
  • elixir/trunk/elixir/options.py

    r265 r267  
    181181] 
    182182 
     183 
    183184def using_options_handler(entity, *args, **kwargs): 
    184185    for kwarg in kwargs: 
  • elixir/trunk/elixir/properties.py

    r248 r267  
    114114        entity._descriptor.builders.append(self) 
    115115 
     116        # delete the original attribute so that it doesn't interfere with 
     117        # SQLAlchemy. 
     118        if hasattr(entity, name): 
     119            delattr(entity, name) 
     120 
    116121    def __repr__(self): 
    117122        return "Property(%s, %s)" % (self.name, self.entity) 
  • elixir/trunk/elixir/relationships.py

    r265 r267  
    778778                constraints.append( 
    779779                    ForeignKeyConstraint(fk_colnames, fk_refcols, 
    780                                          name=fk_name, onupdate=onupdate, ondelete=ondelete)) 
     780                                         name=fk_name, onupdate=onupdate,  
     781                                         ondelete=ondelete)) 
    781782 
    782783            args = columns + constraints 
  • elixir/trunk/elixir/statements.py

    r224 r267  
    3535        self.handler(entity, *args, **kwargs) 
    3636 
     37 
    3738#TODO: move this to the super class (to be created here) of EntityMeta 
    3839def process_mutators(entity): 
     
    4647 
    4748class Statement(ClassMutator): 
     49 
    4850    def process(self, entity, *args, **kwargs): 
    4951        builder = self.handler(entity, *args, **kwargs) 
     
    5153 
    5254class PropertyStatement(ClassMutator): 
     55 
    5356    def process(self, entity, name, *args, **kwargs): 
    5457        prop = self.handler(*args, **kwargs) 
  • elixir/trunk/tests/test_inherit.py

    r234 r267  
    6565        }) 
    6666 
     67    # this is related to SA ticket 866  
     68    # http://www.sqlalchemy.org/trac/ticket/866 
     69    # the problam was caused by the fact that the attribute-based syntax left 
     70    # the class-attributes in place after initialization (in Elixir 0.4). 
     71    def test_missing_value(self): 
     72        class A(Entity): 
     73            pass 
     74 
     75        class B(A):  
     76            name = Field(Unicode(30)) 
     77            other = Field(Unicode) 
     78 
     79        setup_all() 
     80        create_all() 
     81 
     82        b1 = B(name="b1") # no value for other 
     83 
     84        session.flush() 
     85 
    6786    def test_polymorphic_singletable_inheritance(self): 
    6887        do_tst('single', True, True, { 
     
    98117        }) 
    99118 
     119