1. Marc Abramowitz
  2. sqlalchemy

Commits

Mike Bayer  committed 207c3fe

doc updates

  • Participants
  • Parent commits c359033
  • Branches default

Comments (0)

Files changed (5)

File doc/build/orm/session.rst

View file
 
     session = Session(bind=engine)
     
-...or directly with a :class:`.Connection`.  This is useful in some situations, 
-such as within a test fixture that maintains an external transaction::
+...or directly with a :class:`.Connection`::
 
-    from sqlalchemy.orm import sessionmaker
-    from sqlalchemy import create_engine
-    from unittest import TestCase
-    
-    # global application scope.  create Session class, engine
-    Session = sessionmaker()
+    conn = engine.connect()
+    session = Session(bind=conn)
 
-    engine = create_engine('postgresql://...')
-
-    class SomeTest(TestCase):
-        def setUp(self):
-            # connect to the database
-            self.connection = engine.connect()
-
-            # begin a non-ORM transaction
-            self.trans = connection.begin()
-    
-            # bind an individual Session to the connection
-            self.session = Session(bind=self.connection)
-    
-        def test_something(self):
-            # use the session in tests.   
-            
-            self.session.add(Foo())
-            self.session.commit()
-    
-        def tearDown(self):
-            # rollback - everything that happened with the
-            # Session above (including calls to commit()) 
-            # is rolled back.
-            self.trans.rollback()
-            self.session.close()
-            
+While the rationale for the above example may not be apparent, the typical
+usage is in a test fixture that maintains an external transaction - see
+:ref:`session_external_transaction` below for a full example.
 
 Using the Session
 ==================
 
     connection = session.connection(MyMappedClass)
 
+.. _session_external_transaction:
+
 Joining a Session into an External Transaction
 ===============================================
 
-If a :class:`~sqlalchemy.engine.base.Connection` is being used which is
-already in a transactional state (i.e. has a
-:class:`~sqlalchemy.engine.base.Transaction`), a
-:class:`~sqlalchemy.orm.session.Session` can be made to participate within
-that transaction by just binding the :class:`~sqlalchemy.orm.session.Session`
-to that :class:`~sqlalchemy.engine.base.Connection`::
+If a :class:`.Connection` is being used which is already in a transactional
+state (i.e. has a :class:`.Transaction` established), a :class:`.Session` can
+be made to participate within that transaction by just binding the
+:class:`.Session` to that :class:`.Connection`. The usual rationale for this
+is a test suite that allows ORM code to work freely with a :class:`.Session`,
+including the ability to call :meth:`.Session.commit`, where afterwards the
+entire database interaction is rolled back::
 
+    from sqlalchemy.orm import sessionmaker
+    from sqlalchemy import create_engine
+    from unittest import TestCase
+    
+    # global application scope.  create Session class, engine
     Session = sessionmaker()
 
-    # non-ORM connection + transaction
-    conn = engine.connect()
-    trans = conn.begin()
+    engine = create_engine('postgresql://...')
 
-    # create a Session, bind to the connection
-    session = Session(bind=conn)
+    class SomeTest(TestCase):
+        def setUp(self):
+            # connect to the database
+            self.connection = engine.connect()
 
-    # ... work with session
-
-    session.commit() # commit the session
-    session.close()  # close it out, prohibit further actions
-
-    trans.commit() # commit the actual transaction
-
-Note that above, we issue a ``commit()`` both on the
-:class:`~sqlalchemy.orm.session.Session` as well as the
-:class:`~sqlalchemy.engine.base.Transaction`. This is an example of where we
-take advantage of :class:`~sqlalchemy.engine.base.Connection`'s ability to
-maintain *subtransactions*, or nested begin/commit pairs. The
-:class:`~sqlalchemy.orm.session.Session` is used exactly as though it were
-managing the transaction on its own; its
-:func:`~sqlalchemy.orm.session.Session.commit` method issues its
-:func:`~sqlalchemy.orm.session.Session.flush`, and commits the subtransaction.
-The subsequent transaction the :class:`~sqlalchemy.orm.session.Session` starts
-after commit will not begin until it's next used. Above we issue a
-:func:`~sqlalchemy.orm.session.Session.close` to prevent this from occurring.
-Finally, the actual transaction is committed using ``Transaction.commit()``.
-
-When using the ``threadlocal`` engine context, the process above is
-simplified; the :class:`~sqlalchemy.orm.session.Session` uses the same
-connection/transaction as everyone else in the current thread, whether or not
-you explicitly bind it::
-
-    engine = create_engine('postgresql://mydb', strategy="threadlocal")
-    engine.begin()
-
-    session = Session()  # session takes place in the transaction like everyone else
-
-    # ... go nuts
-
-    engine.commit() # commit the transaction
+            # begin a non-ORM transaction
+            self.trans = connection.begin()
+    
+            # bind an individual Session to the connection
+            self.session = Session(bind=self.connection)
+    
+        def test_something(self):
+            # use the session in tests.   
+            
+            self.session.add(Foo())
+            self.session.commit()
+    
+        def tearDown(self):
+            # rollback - everything that happened with the
+            # Session above (including calls to commit()) 
+            # is rolled back.
+            self.trans.rollback()
+            self.session.close()
+            
+Above, we issue :meth:`.Session.commit` as well as
+:meth:`.Transaction.rollback`. This is an example of where we take advantage
+of the :class:`.Connection` object's ability to maintain *subtransactions*, or
+nested begin/commit-or-rollback pairs where only the outermost begin/commit
+pair actually commits the transaction, or if the outermost block rolls back,
+everything is rolled back.
 
 The :class:`.Session` object and :func:`.sessionmaker` function
 ================================================================
 .. autoclass:: sqlalchemy.orm.scoping.ScopedSession
    :members:
 
+.. autoclass:: sqlalchemy.util.ScopedRegistry
+    :members:
+    
+.. autoclass:: sqlalchemy.util.ThreadLocalRegistry
+
 .. _session_partitioning:
 
 Partitioning Strategies

File lib/sqlalchemy/engine/base.py

View file
 class Transaction(object):
     """Represent a Transaction in progress.
 
+    The object provides :meth:`.rollback` and :meth:`.commit`
+    methods in order to control transaction boundaries.  It 
+    also implements a context manager interface so that 
+    the Python ``with`` statement can be used with the 
+    :meth:`.Connection.begin` method.
+    
     The Transaction object is **not** threadsafe.
 
     .. index::
     """
 
     def __init__(self, connection, parent):
+        """The constructor for :class:`.Transaction` is private
+        and is called from within the :class:`.Connection.begin` 
+        implementation.
+        
+        """
         self.connection = connection
         self._parent = parent or self
         self.is_active = True
 
     def close(self):
-        """Close this transaction.
+        """Close this :class:`.Transaction`.
 
         If this transaction is the base transaction in a begin/commit
         nesting, the transaction will rollback().  Otherwise, the
 
         This is used to cancel a Transaction without affecting the scope of
         an enclosing transaction.
+        
         """
         if not self._parent.is_active:
             return
             self.rollback()
 
     def rollback(self):
+        """Roll back this :class:`.Transaction`.
+        
+        """
         if not self._parent.is_active:
             return
         self._do_rollback()
         self._parent.rollback()
 
     def commit(self):
+        """Commit this :class:`.Transaction`."""
+        
         if not self._parent.is_active:
             raise exc.InvalidRequestError("This transaction is inactive")
         self._do_commit()

File lib/sqlalchemy/orm/__init__.py

View file
 
 
 def scoped_session(session_factory, scopefunc=None):
-    """Provides thread-local management of Sessions.
+    """Provides thread-local or scoped management of :class:`.Session` objects.
 
     This is a front-end function to
-    :class:`~sqlalchemy.orm.scoping.ScopedSession`.
+    :class:`.ScopedSession`.
 
     :param session_factory: a callable function that produces
       :class:`Session` instances, such as :func:`sessionmaker`.
 
-    :param scopefunc: optional, TODO
+    :param scopefunc: Optional "scope" function which would be
+      passed to the :class:`.ScopedRegistry`.  If None, the
+      :class:`.ThreadLocalRegistry` is used by default.
 
-    :returns: an :class:`~sqlalchemy.orm.scoping.ScopedSession` instance
+    :returns: an :class:`.ScopedSession` instance
 
     Usage::
 

File lib/sqlalchemy/orm/scoping.py

View file
 
     Usage::
 
-      Session = scoped_session(sessionmaker(autoflush=True))
+      Session = scoped_session(sessionmaker())
 
-      ... use session normally.
+    ... use Session normally.
+      
+    The internal registry is accessible as well,
+    and by default is an instance of :class:`.ThreadLocalRegistry`.
+      
 
     """
 
         class when called.
 
         e.g.::
+        
             Session = scoped_session(sessionmaker())
 
             class MyClass(object):

File lib/sqlalchemy/util.py

View file
 
 class ScopedRegistry(object):
     """A Registry that can store one or multiple instances of a single
-    class on a per-thread scoped basis, or on a customized scope.
+    class on the basis of a "scope" function.
+    
+    The object implements ``__call__`` as the "getter", so by
+    calling ``myregistry()`` the contained object is returned
+    for the current scope.
 
-    createfunc
+    :param createfunc:
       a callable that returns a new object to be placed in the registry
 
-    scopefunc
+    :param scopefunc:
       a callable that will return a key to store/retrieve an object.
     """
 
     def __init__(self, createfunc, scopefunc):
+        """Construct a new :class:`.ScopedRegistry`.
+        
+        :param createfunc:  A creation function that will generate
+          a new value for the current scope, if none is present.
+          
+        :param scopefunc:  A function that returns a hashable
+          token representing the current scope (such as, current
+          thread identifier).
+        
+        """
         self.createfunc = createfunc
         self.scopefunc = scopefunc
         self.registry = {}
             return self.registry.setdefault(key, self.createfunc())
 
     def has(self):
+        """Return True if an object is present in the current scope."""
+        
         return self.scopefunc() in self.registry
 
     def set(self, obj):
+        """Set the value forthe current scope."""
+        
         self.registry[self.scopefunc()] = obj
 
     def clear(self):
+        """Clear the current scope, if any."""
+        
         try:
             del self.registry[self.scopefunc()]
         except KeyError:
             pass
 
 class ThreadLocalRegistry(ScopedRegistry):
+    """A :class:`.ScopedRegistry` that uses a ``threading.local()`` 
+    variable for storage.
+    
+    """
     def __init__(self, createfunc):
         self.createfunc = createfunc
         self.registry = threading.local()