summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-09-10 21:14:09 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-09-10 21:14:09 -0400
commit9a4a565212fcc9db33b925addecfcc8560ba5445 (patch)
tree7e392ba861661540d788b7cb2160116e168c49cd
parent43b8346b3c14a5742080ff66ce03bb05e5891c50 (diff)
downloadsqlalchemy-9a4a565212fcc9db33b925addecfcc8560ba5445.tar.gz
updates
-rw-r--r--doc/build/orm/session.rst20
-rw-r--r--lib/sqlalchemy/orm/scoping.py33
-rw-r--r--lib/sqlalchemy/orm/session.py11
3 files changed, 47 insertions, 17 deletions
diff --git a/doc/build/orm/session.rst b/doc/build/orm/session.rst
index 039744221..c0ebe2362 100644
--- a/doc/build/orm/session.rst
+++ b/doc/build/orm/session.rst
@@ -48,6 +48,8 @@ usually, you'd re-associate detached objects another :class:`.Session` when you
want to work with them again, so that they can resume their normal task of
representing database state.
+.. _session_getting:
+
Getting a Session
=================
@@ -222,7 +224,7 @@ Session Frequently Asked Questions
example's sake! In reality, the :class:`.sessionmaker` would be somewhere
at the module level. The calls to instantiate :class:`.Session`
would then be placed at the point in the application where database
- conversations begin (see :ref:`session_faq_whentocreate`).
+ conversations begin.
* When do I construct a :class:`.Session`, when do I commit it, and when do I close it ?
@@ -237,8 +239,8 @@ Session Frequently Asked Questions
begin a new transaction if it is used again, subsequent to the previous
transaction ending; from this it follows that the :class:`.Session`
is capable of having a lifespan across many transactions, though only
- one at a time. We refer to these two concepts as *transaction scope*
- and *session scope*.
+ one at a time. We refer to these two concepts as **transaction scope**
+ and **session scope**.
The implication here is that the SQLAlchemy ORM is encouraging the
developer to establish these two scopes in his or her application,
@@ -282,7 +284,7 @@ Session Frequently Asked Questions
pattern which establishes one as soon as it is needed. The request
then proceeds, with some system in place where application logic can access
the current :class:`.Session` in a manner associated with how the actual
- requset object is accessed. As the request ends, the :class:`.Session`
+ request object is accessed. As the request ends, the :class:`.Session`
is torn down as well, usually through the usage of event hooks provided
by the web framework. The transaction used by the :class:`.Session`
may also be committed at this point, or alternatively the application may
@@ -303,8 +305,8 @@ Session Frequently Asked Questions
In those situations where integration libraries are not available,
SQLAlchemy includes its own "helper" class known as
- :class:`.scoped_session`. This object actually is used as the basis
- of some integration packages, and provides both a quick way
+ :class:`.scoped_session`. A tutorial on the usage of this object
+ is at :ref:`unitofwork_contextual`. It provides both a quick way
to associate a :class:`.Session` with the current thread, as well as
patterns to associate :class:`.Session` objects with other kinds of
scopes.
@@ -316,7 +318,7 @@ Session Frequently Asked Questions
a series of operations for some period of time, which can be committed
at the end. Some examples:
- * A background daemon which spawns off child forks for example
+ * A background daemon which spawns off child forks
would want to create a :class:`.Session` local to each child
process work with that :class:`.Session` through the life of the "job"
that the fork is handling, then tear it down when the job is completed.
@@ -1727,7 +1729,7 @@ This simple correspondence of web request and thread means that to associate a
:class:`.Session` with a thread implies it is also associated with the web request
running within that thread, and vice versa, provided that the :class:`.Session` is
created only after the web request begins and torn down just before the web request ends.
-So it is a very common practice to use :class:`.scoped_session` as a quick way
+So it is a common practice to use :class:`.scoped_session` as a quick way
to integrate the :class:`.Session` with a web application. The sequence
diagram below illustrates this flow::
@@ -1792,7 +1794,7 @@ one of many options on how to "scope" a :class:`.Session`. A custom scope can
based on any existing system of getting at "the current thing we are working with".
Suppose a web framework defines a library function ``get_current_request()``. An application
-build on this framework can call this function at any time, and the result will be
+built using this framework can call this function at any time, and the result will be
some kind of ``Request`` object that represents the current request being processed.
If the ``Request`` object is hashable, then this function can be easily integrated with
:class:`.scoped_session` to associate the :class:`.Session` with the request. Below we illustrate
diff --git a/lib/sqlalchemy/orm/scoping.py b/lib/sqlalchemy/orm/scoping.py
index fff17ee14..e827bc5b8 100644
--- a/lib/sqlalchemy/orm/scoping.py
+++ b/lib/sqlalchemy/orm/scoping.py
@@ -42,26 +42,45 @@ class scoped_session(object):
else:
self.registry = ThreadLocalRegistry(session_factory)
- def __call__(self, **kwargs):
- """Return the current :class:`.Session`."""
- if kwargs:
- scope = kwargs.pop('scope', False)
+ def __call__(self, **kw):
+ """Return the current :class:`.Session`, creating it
+ using the session factory if not present.
+
+ :param \**kw: Keyword arguments will be passed to the
+ session factory callable, if an existing :class:`.Session`
+ is not present. If the :class:`.Session` is present and
+ keyword arguments have been passed, :class:`.InvalidRequestError`
+ is raised.
+
+ """
+ if kw:
+ scope = kw.pop('scope', False)
if scope is not None:
if self.registry.has():
raise sa_exc.InvalidRequestError(
"Scoped session is already present; "
"no new arguments may be specified.")
else:
- sess = self.session_factory(**kwargs)
+ sess = self.session_factory(**kw)
self.registry.set(sess)
return sess
else:
- return self.session_factory(**kwargs)
+ return self.session_factory(**kw)
else:
return self.registry()
def remove(self):
- """Dispose of the current contextual session."""
+ """Dispose of the current :class:`.Session`, if present.
+
+ This will first call :meth:`.Session.close` method
+ on the current :class:`.Session`, which releases any existing
+ transactional/connection resources still being held; transactions
+ specifically are rolled back. The :class:`.Session` is then
+ discarded. Upon next usage within the same scope,
+ the :class:`.scoped_session` will produce a new
+ :class:`.Session` object.
+
+ """
if self.registry.has():
self.registry().close()
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 96a6983f8..e0f79cd8a 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -2041,11 +2041,20 @@ class sessionmaker(_SessionClassMethods):
with an existing :class:`.sessionmaker` factory before it is first
used::
+ # application starts
Session = sessionmaker()
- Session.configure(bind=create_engine('sqlite:///foo.db'))
+
+ # ... later
+ engine = create_engine('sqlite:///foo.db')
+ Session.configure(bind=engine)
sess = Session()
+ .. seealso:
+
+ :ref:`session_getting` - introductory text on creating
+ sessions using :class:`.sessionmaker`.
+
"""
def __init__(self, bind=None, class_=Session, autoflush=True,