diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-09-10 20:40:42 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-09-10 20:40:42 -0400 |
| commit | 43b8346b3c14a5742080ff66ce03bb05e5891c50 (patch) | |
| tree | 0a9cb259fb792135e3266d294ea0ce5812aeeb94 /lib/sqlalchemy/orm/session.py | |
| parent | f2622c0c53e761759da89c784c5105d2a38dcab9 (diff) | |
| download | sqlalchemy-43b8346b3c14a5742080ff66ce03bb05e5891c50.tar.gz | |
- rework scoped_session and sessionmaker, [ticket:2500]
- rewrite tons of session docs
Diffstat (limited to 'lib/sqlalchemy/orm/session.py')
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 204 |
1 files changed, 123 insertions, 81 deletions
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index c6c7efffb..96a6983f8 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -24,81 +24,37 @@ from .events import SessionEvents statelib = util.importlater("sqlalchemy.orm", "state") import sys -__all__ = ['Session', 'SessionTransaction', 'SessionExtension'] +__all__ = ['Session', 'SessionTransaction', 'SessionExtension', 'sessionmaker'] -def sessionmaker(bind=None, class_=None, autoflush=True, autocommit=False, - expire_on_commit=True, **kwargs): - """Generate a custom-configured :class:`.Session` class. +class _SessionClassMethods(object): + """Class-level methods for :class:`.Session`, :class:`.sessionmaker`.""" - The returned object is a subclass of :class:`.Session`, which, - when instantiated with no arguments, uses the keyword arguments - configured here as its constructor arguments. - - It is intended that the :func:`.sessionmaker()` function be called - within the global scope of an application, and the returned class - be made available to the rest of the application as the single - class used to instantiate sessions. - - e.g.:: - - # global scope - Session = sessionmaker(autoflush=False) - - # later, in a local scope, create and use a session: - sess = Session() - - Any keyword arguments sent to the constructor itself will override the - "configured" keywords:: - - Session = sessionmaker() - - # bind an individual session to a connection - sess = Session(bind=connection) - - The class also includes a special classmethod ``configure()``, which - allows additional configurational options to take place after the custom - ``Session`` class has been generated. This is useful particularly for - defining the specific ``Engine`` (or engines) to which new instances of - ``Session`` should be bound:: - - Session = sessionmaker() - Session.configure(bind=create_engine('sqlite:///foo.db')) - - sess = Session() - - For options, see the constructor options for :class:`.Session`. - - """ - kwargs['bind'] = bind - kwargs['autoflush'] = autoflush - kwargs['autocommit'] = autocommit - kwargs['expire_on_commit'] = expire_on_commit - - if class_ is None: - class_ = Session + @classmethod + def close_all(cls): + """Close *all* sessions in memory.""" - class Sess(object): - def __init__(self, **local_kwargs): - for k in kwargs: - local_kwargs.setdefault(k, kwargs[k]) - super(Sess, self).__init__(**local_kwargs) + for sess in _sessions.values(): + sess.close() - @classmethod - def configure(self, **new_kwargs): - """(Re)configure the arguments for this sessionmaker. + @classmethod + def identity_key(cls, *args, **kwargs): + """Return an identity key. - e.g.:: + This is an alias of :func:`.util.identity_key`. - Session = sessionmaker() + """ + return orm_util.identity_key(*args, **kwargs) - Session.configure(bind=create_engine('sqlite://')) - """ - kwargs.update(new_kwargs) + @classmethod + def object_session(cls, instance): + """Return the :class:`.Session` to which an object belongs. + This is an alias of :func:`.object_session`. - return type("SessionMaker", (Sess, class_), {}) + """ + return object_session(instance) class SessionTransaction(object): """A :class:`.Session`-level transaction. @@ -446,7 +402,7 @@ class SessionTransaction(object): else: self.rollback() -class Session(object): +class Session(_SessionClassMethods): """Manages persistence operations for ORM-mapped objects. The Session's usage paradigm is described at :ref:`session_toplevel`. @@ -922,13 +878,6 @@ class Session(object): for transaction in self.transaction._iterate_parents(): transaction.close() - @classmethod - def close_all(cls): - """Close *all* sessions in memory.""" - - for sess in _sessions.values(): - sess.close() - def expunge_all(self): """Remove all object instances from this ``Session``. @@ -1573,15 +1522,6 @@ class Session(object): merged_state.manager.dispatch.load(merged_state, None) return merged - @classmethod - def identity_key(cls, *args, **kwargs): - return orm_util.identity_key(*args, **kwargs) - - @classmethod - def object_session(cls, instance): - """Return the ``Session`` to which an object belongs.""" - - return object_session(instance) def _validate_persistent(self, state): if not self.identity_map.contains_state(state): @@ -2071,6 +2011,108 @@ class Session(object): return util.IdentitySet(self._new.values()) +class sessionmaker(_SessionClassMethods): + """A configurable :class:`.Session` factory. + + The :class:`.sessionmaker` factory generates new + :class:`.Session` objects when called, creating them given + the configurational arguments established here. + + e.g.:: + + # global scope + Session = sessionmaker(autoflush=False) + + # later, in a local scope, create and use a session: + sess = Session() + + Any keyword arguments sent to the constructor itself will override the + "configured" keywords:: + + Session = sessionmaker() + + # bind an individual session to a connection + sess = Session(bind=connection) + + The class also includes a method :meth:`.configure`, which can + be used to specify additional keyword arguments to the factory, which + will take effect for subsequent :class:`.Session` objects generated. + This is usually used to associate one or more :class:`.Engine` objects + with an existing :class:`.sessionmaker` factory before it is first + used:: + + Session = sessionmaker() + Session.configure(bind=create_engine('sqlite:///foo.db')) + + sess = Session() + + """ + + def __init__(self, bind=None, class_=Session, autoflush=True, + autocommit=False, + expire_on_commit=True, **kw): + """Construct a new :class:`.sessionmaker`. + + All arguments here except for ``class_`` correspond to arguments + accepted by :class:`.Session` directly. See the + :meth:`.Session.__init__` docstring for more details on parameters. + + :param bind: a :class:`.Engine` or other :class:`.Connectable` with + which newly created :class:`.Session` objects will be associated. + :param class_: class to use in order to create new :class:`.Session` + objects. Defaults to :class:`.Session`. + :param autoflush: The autoflush setting to use with newly created + :class:`.Session` objects. + :param autocommit: The autocommit setting to use with newly created + :class:`.Session` objects. + :param expire_on_commit=True: the expire_on_commit setting to use + with newly created :class:`.Session` objects. + :param \**kw: all other keyword arguments are passed to the constructor + of newly created :class:`.Session` objects. + + """ + kw['bind'] = bind + kw['autoflush'] = autoflush + kw['autocommit'] = autocommit + kw['expire_on_commit'] = expire_on_commit + self.kw = kw + # make our own subclass of the given class, so that + # events can be associated with it specifically. + self.class_ = type(class_.__name__, (class_,), {}) + + def __call__(self, **local_kw): + """Produce a new :class:`.Session` object using the configuration + established in this :class:`.sessionmaker`. + + In Python, the ``__call__`` method is invoked on an object when + it is "called" in the same way as a function:: + + Session = sessionmaker() + session = Session() # invokes sessionmaker.__call__() + + """ + for k, v in self.kw.items(): + local_kw.setdefault(k, v) + return self.class_(**local_kw) + + def configure(self, **new_kw): + """(Re)configure the arguments for this sessionmaker. + + e.g.:: + + Session = sessionmaker() + + Session.configure(bind=create_engine('sqlite://')) + """ + self.kw.update(new_kw) + + def __repr__(self): + return "%s(class_=%r%s)" % ( + self.__class__.__name__, + self.class_.__name__, + ", ".join("%s=%r" % (k, v) for k, v in self.kw.items()) + ) + _sessions = weakref.WeakValueDictionary() def make_transient(instance): |
