Changeset 185

Show
Ignore:
Timestamp:
08/18/07 18:00:17 (7 years ago)
Author:
cleverdevil
Message:

Patch from Mike Bayer:

The attached patch modifies Elixir's "Objectstore" implementation to work
for a SessionContext from versions 0.3 and 0.4, as well as the
0.4-onlyScopedSession object. Additionally, a new using_options() option
"session" is added, such that any user-defined SessionContext or
ScopedSession may be assigned to an Elixir class individually. So the
contextual "Session" which is to be used by Elixir can now be set at three
levels; globally using elixir.objectstore, per-module using module.session,
or per-class using using_options(session=somesess).


Three tests are added, two of which test using_options(session) against

both kinds of session, and a third which tests module-level usage of
ScopedSession.


At the very least, the new "Objectstore" class should be implemented which

establishes compatibility with ScopedSession which is featured in the Pylons
tutorial.


the patch also fixes a bug in versioned.py where an execute() statement
could be issued using unicode keywords, which is illegal for the **params
calling style.

Thanks, Mike!


Location:
elixir/trunk
Files:
5 modified

Legend:

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

    r183 r185  
    2424from elixir.options import using_options, using_table_options, \ 
    2525                           using_mapper_options, options_defaults 
    26 from elixir.entity import Entity, EntityMeta, EntityDescriptor 
     26from elixir.entity import Entity, EntityMeta, EntityDescriptor, Objectstore 
    2727from elixir.fields import has_field, with_fields, Field 
    2828from elixir.relationships import belongs_to, has_one, has_many, \ 
     
    5656    objectstore = sqlalchemy.objectstore 
    5757except AttributeError: 
    58     # thread local SessionContext 
    59     class Objectstore(object): 
    60  
    61         def __init__(self, *args, **kwargs): 
    62             self.context = SessionContext(*args, **kwargs) 
    63  
    64         def __getattr__(self, name): 
    65             return getattr(self.context.current, name) 
    66  
    67         session = property(lambda s:s.context.current) 
    68  
    69     objectstore = Objectstore(sqlalchemy.orm.create_session) 
     58    objectstore = Objectstore(SessionContext(sqlalchemy.orm.create_session)) 
    7059 
    7160metadatas = set() 
    7261 
    7362 
    74 def create_all(): 
     63def create_all(engine=None): 
    7564    'Create all necessary tables for all declared entities' 
    7665    for md in metadatas: 
    77         md.create_all() 
     66        md.create_all(bind=engine) 
    7867 
    7968 
    80 def drop_all(): 
     69def drop_all(engine=None): 
    8170    'Drop all tables for all declared entities' 
    8271    for md in metadatas: 
    83         md.drop_all() 
     72        md.drop_all(bind=engine) 
    8473 
    8574_delayed_descriptors = list() 
  • elixir/trunk/elixir/entity.py

    r183 r185  
    77from sqlalchemy.orm                 import deferred, Query, MapperExtension 
    88from sqlalchemy.ext.assignmapper    import assign_mapper 
     9from sqlalchemy.ext.sessioncontext  import SessionContext 
    910from sqlalchemy.util                import OrderedDict 
    1011import sqlalchemy 
     
    156157            return 
    157158         
    158         session = getattr(self.module, 'session', elixir.objectstore) 
     159        # look for a 'session' attribute assigned to the entity 
     160        # (or entity's base class) 
     161        session = getattr(self, 'session', None) 
     162        if session is None: 
     163            session = getattr(self.module, 'session', elixir.objectstore) 
     164        if not isinstance(session, Objectstore): 
     165            session = Objectstore(session) 
     166             
     167        self.objectstore = session 
    159168         
    160169        kwargs = self.mapper_options 
     
    213222            args = [self.entity.table] 
    214223 
    215         assign_mapper(session.context, self.entity, properties=properties,  
     224        self.objectstore.mapper(self.entity, properties=properties,  
    216225                      *args, **kwargs) 
    217226 
     
    496505 
    497506    def q(cls): 
    498         return Query(cls, session=elixir.objectstore.session) 
     507        return Query(cls, session=cls._descriptor.objectstore.session) 
    499508    q = property(q) 
    500509 
     
    544553 
    545554 
     555class Objectstore(object): 
     556    """a wrapper for a SQLAlchemy session-making object, such as  
     557    SessionContext or ScopedSession. 
     558     
     559    Uses the ``registry`` attribute present on both objects 
     560    (versions 0.3 and 0.4) in order to return the current 
     561    contextual session. 
     562    """ 
     563     
     564    def __init__(self, ctx): 
     565        self.context = ctx 
     566        self.is_ctx = isinstance(ctx, SessionContext) 
     567 
     568    def __getattr__(self, name): 
     569        return getattr(self.context.registry(), name) 
     570     
     571    def mapper(self, cls, *args, **kwargs): 
     572        if self.is_ctx: 
     573            assign_mapper(self.context, cls, *args, **kwargs) 
     574        else: 
     575            cls.mapper = self.context.mapper(cls, *args, **kwargs) 
     576         
     577    session = property(lambda s:s.context.registry()) 
     578 
  • elixir/trunk/elixir/ext/versioned.py

    r181 r185  
    4040''' 
    4141 
    42 from elixir                import Integer, objectstore, DateTime 
     42from elixir                import Integer, DateTime 
    4343from elixir.statements     import Statement 
    4444from elixir.fields         import Field 
     
    143143        # attach utility methods and properties to the entity 
    144144        def get_versions(self): 
    145             return objectstore.query(Version).select(get_history_where(self)) 
     145            return entity._descriptor.objectstore.query(Version).select(get_history_where(self)) 
    146146         
    147147        def get_as_of(self, dt): 
     
    152152            # otherwise, we need to look to the history table to get our 
    153153            # older version 
    154             items = objectstore.query(Version).select( 
     154            items = entity._descriptor.objectstore.query(Version).select( 
    155155                and_(get_history_where(self), Version.c.timestamp <= dt), 
    156156                order_by=desc(Version.c.timestamp), 
     
    168168             
    169169            entity.table.update(get_entity_where(self)).execute( 
    170                 **dict(old_version.items()) 
     170                dict(old_version.items()) 
    171171            ) 
    172172             
  • elixir/trunk/elixir/options.py

    r175 r185  
    137137        'metadata', 
    138138        'order_by', 
     139        'session', 
    139140    ) 
    140141     
  • elixir/trunk/tests/test_options.py

    r178 r185  
    77from sqlalchemy.exceptions import SQLError, ConcurrentModificationError  
    88from elixir import * 
    9  
    109 
    1110class TestOptions(object): 
     
    7776 
    7877 
    79  
     78class TestSessionOptions(object): 
     79    def setup(self): 
     80        metadata.bind = None 
     81 
     82    def teardown(self): 
     83        cleanup_all() 
     84 
     85    def test_session_context(self): 
     86        from sqlalchemy.ext.sessioncontext import SessionContext 
     87        from sqlalchemy.orm import create_session 
     88        from sqlalchemy import create_engine 
     89 
     90        engine = create_engine('sqlite:///') 
     91         
     92        ctx = SessionContext(lambda: create_session(bind=engine)) 
     93         
     94        class Person(Entity): 
     95            using_options(session=ctx) 
     96            has_field('firstname', Unicode(30)) 
     97            has_field('surname', Unicode(30)) 
     98 
     99        create_all(engine) 
     100 
     101        homer = Person(firstname="Homer", surname='Simpson') 
     102        bart = Person(firstname="Bart", surname='Simpson') 
     103        ctx.current.flush() 
     104         
     105        assert Person.query().session is ctx.current 
     106         
     107        assert Person.query().filter_by(firstname='Homer').one() is homer 
     108 
     109    def test_scoped_session(self): 
     110        try: 
     111            from sqlalchemy.orm import scoped_session, sessionmaker 
     112        except ImportError: 
     113            print "Not on version 0.4 of sqlalchemy" 
     114            return 
     115             
     116        from sqlalchemy import create_engine 
     117 
     118        engine = create_engine('sqlite:///') 
     119 
     120        Session = scoped_session(sessionmaker(bind=engine)) 
     121 
     122        class Person(Entity): 
     123            using_options(session=Session) 
     124            has_field('firstname', Unicode(30)) 
     125            has_field('surname', Unicode(30)) 
     126 
     127        create_all(engine) 
     128 
     129        homer = Person(firstname="Homer", surname='Simpson') 
     130        bart = Person(firstname="Bart", surname='Simpson') 
     131        Session.flush() 
     132 
     133        assert Person.query().session is Session() 
     134 
     135        assert Person.query().filter_by(firstname='Homer').one() is homer 
     136         
     137    def test_global_scoped_session(self): 
     138        try: 
     139            from sqlalchemy.orm import scoped_session, sessionmaker 
     140        except ImportError: 
     141            print "Not on version 0.4 of sqlalchemy" 
     142            return 
     143 
     144        from sqlalchemy import create_engine 
     145 
     146        global session 
     147         
     148        engine = create_engine('sqlite:///') 
     149         
     150        session = scoped_session(sessionmaker(bind=engine)) 
     151         
     152        class Person(Entity): 
     153            has_field('firstname', Unicode(30)) 
     154            has_field('surname', Unicode(30)) 
     155 
     156        create_all(engine) 
     157 
     158        homer = Person(firstname="Homer", surname='Simpson') 
     159        bart = Person(firstname="Bart", surname='Simpson') 
     160        session.flush() 
     161         
     162        assert Person.query().session is session() 
     163         
     164        assert Person.query().filter_by(firstname='Homer').one() is homer 
     165 
     166        del session 
     167         
    80168class TestTableOptions(object): 
    81169    def setup(self):