]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
docstring stuff
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 5 Aug 2007 20:19:26 +0000 (20:19 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 5 Aug 2007 20:19:26 +0000 (20:19 +0000)
doc/build/gen_docstrings.py
lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/dynamic.py
lib/sqlalchemy/orm/session.py
lib/sqlalchemy/orm/shard.py
test/orm/unitofwork.py

index b917469d904a39ccafc96acb64c00bdefd177107..28e8c1dc88220d65f1216e4ce2aba2c6c56f5d24 100644 (file)
@@ -38,14 +38,12 @@ def make_all_docs():
         make_doc(obj=orm.interfaces),
         make_doc(obj=orm.mapperlib, classes=[orm.mapperlib.MapperExtension, orm.mapperlib.Mapper]),
         make_doc(obj=orm.properties),
-        make_doc(obj=orm.query, classes=[orm.query.Query, orm.query.QueryContext, orm.query.SelectionContext]),
-        make_doc(obj=orm.session, classes=[orm.session.Session, orm.session.SessionTransaction]),
+        make_doc(obj=orm.query, classes=[orm.query.Query]),
+        make_doc(obj=orm.session, classes=[orm.session.Session]),
         make_doc(obj=orm.shard),
         make_doc(obj=exceptions),
-        make_doc(obj=assignmapper),
         make_doc(obj=associationproxy, classes=[associationproxy.AssociationProxy]),
         make_doc(obj=orderinglist, classes=[orderinglist.OrderingList]),
-        make_doc(obj=sessioncontext),
         make_doc(obj=sqlsoup),
     ] + [make_doc(getattr(__import__('sqlalchemy.databases.%s' % m).databases, m)) for m in databases.__all__]
     return objects
index 2c1a4ffc4b4cba1240348d81711a80a781be171e..871580660f138e1278cebb7166ea5936596ac748 100644 (file)
@@ -21,24 +21,55 @@ from sqlalchemy.orm.query import Query
 from sqlalchemy.orm.util import polymorphic_union
 from sqlalchemy.orm.session import Session as _Session
 from sqlalchemy.orm.session import object_session, attribute_manager, sessionmaker
-from sqlalchemy.orm.scoping import ScopedSession as scoped_session
+from sqlalchemy.orm.scoping import ScopedSession
 
 __all__ = [ 'relation', 'column_property', 'composite', 'backref', 'eagerload',
             'eagerload_all', 'lazyload', 'noload', 'deferred', 'defer',
             'undefer', 'undefer_group', 'extension', 'mapper', 'clear_mappers',
             'compile_mappers', 'class_mapper', 'object_mapper', 'sessionmaker',
-            'scoped_session', 'dynamic_loader', 'MapperExtension', 'Query', 'polymorphic_union',
+            'scoped_session', 'dynamic_loader', 'MapperExtension', 'polymorphic_union',
             'create_session', 'synonym', 'contains_alias',
             'contains_eager', 'EXT_CONTINUE', 'EXT_STOP', 'EXT_PASS',
             'object_session', 'PropComparator' ]
 
+def scoped_session(session_factory, scopefunc=None):
+  """Provides thread-local management of Sessions.
+
+  Usage::
+
+    Session = scoped_session(sessionmaker(autoflush=True))
+
+  To instantiate a Session object which is part of the scoped
+  context, instantiate normally::
+  
+    session = Session()
+    
+  Most session methods are available as classmethods from
+  the scoped session::
+  
+    Session.commit()
+    Session.close()
+    
+  To map classes so that new instances are saved in the current
+  Session automatically, as well as to provide session-aware
+  class attributes such as "query", use the `mapper` classmethod
+  from the scoped session::
+    
+    mapper = Session.mapper
+    mapper(Class, table, ...)
+
+  """
+  
+  return ScopedSession(session_factory, scopefunc=scopefunc)
+  
 def create_session(bind=None, **kwargs):
     """create a new [sqlalchemy.orm.session#Session].
     
     The session by default does not begin a transaction, and requires that
     flush() be called explicitly in order to persist results to the database.
     
-    It is recommended to use the sessionmaker() function instead of create_session().
+    It is recommended to use the [sqlalchemy.orm#sessionmaker()] function 
+    instead of create_session().
     """
     kwargs.setdefault('autoflush', False)
     kwargs.setdefault('transactional', False)
index d06b874c9878df3b990df4ec5e4d37eb8c321be4..dee2e28ce98e5d983a30bb7d9a17b9f552b83e02 100644 (file)
@@ -2,7 +2,8 @@
 a special AttributeHistory on the 'write' side."""
 
 from sqlalchemy import exceptions
-from sqlalchemy.orm import attributes, Query, object_session
+from sqlalchemy.orm import attributes, object_session
+from sqlalchemy.orm.query import Query
 from sqlalchemy.orm.mapper import has_identity
 
 class DynamicCollectionAttribute(attributes.InstrumentedAttribute):
index 80c1a5b0d1d753141fb49f5d2ecde6032403db41..1b0c1a9a2b933afdb3e02969214427af3a07d126 100644 (file)
@@ -159,11 +159,79 @@ class SessionTransaction(object):
             self.rollback()
 
 class Session(object):
-    """Encapsulates a set of objects being operated upon within an
-    object-relational operation.
+    """Encapsulates a set of objects being operated upon within an object-relational operation.
 
-    The Session object is **not** threadsafe.  For thread-management
-    of Sessions, see the ``sqlalchemy.ext.sessioncontext`` module.
+    The Session is the front end to SQLAlchemy's **Unit of Work** implementation. The concept
+    behind Unit of Work is to track modifications to a field of objects, and then be able to
+    flush those changes to the database in a single operation.
+    
+    SQLAlchemy's unit of work includes these functions:
+
+      * The ability to track in-memory changes on scalar- and collection-based object
+        attributes, such that database persistence operations can be assembled based on those
+        changes.
+
+      * The ability to organize individual SQL queries and population of newly generated
+      primary and foreign key-holding attributes during a persist operation
+      such that referential integrity is maintained at all times.  
+      
+      * The ability to maintain insert ordering against the order in which
+      new instances were added to the session.  
+      
+      * an Identity Map, which is a dictionary keying instances to their unique primary key
+        identity. This ensures that only one copy of a particular entity is ever present
+        within the session, even if repeated load operations for the same entity occur. This
+        allows many parts of an application to get a handle to a particular object without
+        any chance of modifications going to two different places.
+
+    When dealing with instances of mapped classes, an instance may be *attached* to a
+    particular Session, else it is *unattached* . An instance also may or may not correspond
+    to an actual row in the database. These conditions break up into four distinct states:
+
+      * *Transient* - a transient instance exists within memory only and is not associated with
+        any Session. It also has no database identity and does not have a corresponding record
+        in the database. When a new instance of a class is constructed, and no default session
+        context exists with which to automatically attach the new instance, it is a transient
+        instance. The instance can then be saved to a particular session in which case it
+        becomes a *pending* instance. If a default session context exists, new instances are
+        added to that Session by default and therefore become *pending* instances immediately.
+
+      * *Pending* - a pending instance is a Session-attached object that has not yet been
+        assigned a database identity. When the Session is flushed (i.e. changes are persisted to
+        the database), a pending instance becomes persistent.
+
+      * *Persistent* - a persistent instance has a database identity and a corresponding record
+        in the database, and is also associated with a particular Session. By "database
+        identity" we mean the object is associated with a table or relational concept in the
+        database combined with a particular primary key in that table. Objects that are loaded
+        by SQLAlchemy in the context of a particular session are automatically considered
+        persistent, as are formerly pending instances which have been subject to a session
+        `flush()`.
+
+      * *Detached* - a detached instance is an instance which has a database identity and
+        corresponding row in the database, but is not attached to any Session. This occurs when
+        an instance has been removed from a Session, either because the session itself was
+        cleared or closed, or the instance was explicitly removed from the Session. The object
+        can be re-attached to a session in which case it becomes Persistent again; any
+        un-persisted changes that exist on the instance, whether they occurred during its
+        previous persistent state or during its detached state will be detected and maintained
+        by the new session. Detached instances are useful when an application needs to represent
+        a long-running operation across multiple Sessions, needs to store an object in a
+        serialized state and then restore it later (such as within an HTTP "session" object), or
+        in some cases where code needs to load instances locally which will later be associated
+        with some other Session.
+
+    The session methods which control instance state include ``save()``, ``update()``,
+    ``save_or_update()``, ``delete()``, ``merge()``, and ``expunge()``.
+    
+    The Session object is **not** threadsafe, particularly during flush operations.  A session
+    which is only read from (i.e. is never flushed) can be used by concurrent threads if it's
+    acceptable that some object instances may be loaded twice.  
+    
+    The typical pattern to managing Sessions in a multi-threaded environment is either to use
+    mutexes to limit concurrent access to one thread at a time, or more commonly to establish
+    a unique session for every thread, using a threadlocal variable.  SQLAlchemy provides 
+    a thread-managed Session adapter, provided by the [sqlalchemy.orm#scoped_session()] function.
     """
 
     def __init__(self, bind=None, autoflush=True, transactional=False, twophase=False, echo_uow=False, weak_identity_map=False):
index 9d4396d2bb43fabaaa0ce1902d404c265d00a755..69d692167362d29455acbc7022774678b9f7edda 100644 (file)
@@ -1,5 +1,5 @@
 from sqlalchemy.orm.session import Session
-from sqlalchemy.orm import Query
+from sqlalchemy.orm.query import Query
 
 __all__ = ['ShardedSession', 'ShardedQuery']
 
index f065267f7d33efed3e270e1bc18dcf91dac78c86..e0b0a23d33032c8fc6b3fb70d84ba871b37ad5d4 100644 (file)
@@ -640,7 +640,7 @@ class DefaultTest(UnitOfWorkTest):
         
         Session.close()
         
-        l = Query(Hoho).select()
+        l = Hoho.query.all()
         
         (h1, h2, h3, h4, h5) = l
         
@@ -941,7 +941,7 @@ class SaveTest(UnitOfWorkTest):
 
         # select both
         #Session.close()
-        userlist = Query(m).select(users.c.user_id.in_(u.user_id, u2.user_id), order_by=[users.c.user_name])
+        userlist = User.query.filter(users.c.user_id.in_(u.user_id, u2.user_id)).order_by([users.c.user_name]).all()
         print repr(u.user_id), repr(userlist[0].user_id), repr(userlist[0].user_name)
         self.assert_(u.user_id == userlist[0].user_id and userlist[0].user_name == 'modifiedname')
         self.assert_(u2.user_id == userlist[1].user_id and userlist[1].user_name == 'savetester2')
@@ -1464,7 +1464,7 @@ class ManyToManyTest(UnitOfWorkTest):
             item.keywords = []
             for kname in [e['keyword'][1]['name'] for e in elem['keywords'][1]]:
                 try:
-                    k = Query(keywordmapper).select(keywords.c.name == kname)[0]
+                    k = Keyword.query.filter(keywords.c.name == kname)[0]
                 except IndexError:
                     k = Keyword()
                     k.name= kname
@@ -1474,7 +1474,7 @@ class ManyToManyTest(UnitOfWorkTest):
 
         Session.commit()
         Session.close()
-        l = Query(m).select(items.c.item_name.in_(*[e['item_name'] for e in data[1:]]), order_by=[items.c.item_name])
+        l = Item.query.filter(items.c.item_name.in_(*[e['item_name'] for e in data[1:]])).order_by(items.c.item_name).all()
         self.assert_result(l, *data)
 
     def testm2mmultitable(self):