# orm/session.py
# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
"""Provides the Session class and related utilities."""
import weakref
from itertools import chain
from sqlalchemy import util, sql, engine, log, exc as sa_exc
from sqlalchemy.sql import util as sql_util, expression
from sqlalchemy.orm import (
    SessionExtension, attributes, exc, query, unitofwork, util as mapperutil, state
    )
from sqlalchemy.orm.util import object_mapper as _object_mapper
from sqlalchemy.orm.util import class_mapper as _class_mapper
from sqlalchemy.orm.util import (
    _class_to_mapper, _state_mapper,
    )
from sqlalchemy.orm.mapper import Mapper, _none_set
from sqlalchemy.orm.unitofwork import UOWTransaction
from sqlalchemy.orm import identity
from sqlalchemy import event
from sqlalchemy.orm.events import SessionEvents
import sys
__all__ = ['Session', 'SessionTransaction', 'SessionExtension']
def sessionmaker(bind=None, class_=None, autoflush=True, autocommit=False,
                 expire_on_commit=True, **kwargs):
    """Generate a custom-configured :class:`.Session` class.
    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
    class Sess(object):
        def __init__(self, **local_kwargs):
            for k in kwargs:
                local_kwargs.setdefault(k, kwargs[k])
            super(Sess, self).__init__(**local_kwargs)
        @classmethod
        def configure(self, **new_kwargs):
            """(Re)configure the arguments for this sessionmaker.
            e.g.::
                Session = sessionmaker()
                Session.configure(bind=create_engine('sqlite://'))
            """
            kwargs.update(new_kwargs)
    return type("SessionMaker", (Sess, class_), {})
class SessionTransaction(object):
    """A :class:`.Session`-level transaction.
    :class:`.SessionTransaction` is a mostly behind-the-scenes object
    not normally referenced directly by application code.   It coordinates
    among multiple :class:`.Connection` objects, maintaining a database
    transaction for each one individually, committing or rolling them
    back all at once.   It also provides optional two-phase commit behavior
    which can augment this coordination operation.
    The :attr:`.Session.transaction` attribute of :class:`.Session` refers to the
    current :class:`.SessionTransaction` object in use, if any.
    A :class:`.SessionTransaction` is associated with a :class:`.Session`
    in its default mode of ``autocommit=False`` immediately, associated
    with no database connections.  As the :class:`.Session` is called upon
    to emit SQL on behalf of various :class:`.Engine` or :class:`.Connection`
    objects, a corresponding :class:`.Connection` and associated :class:`.Transaction`
    is added to a collection within the :class:`.SessionTransaction` object,
    becoming one of the connection/transaction pairs maintained by the
    :class:`.SessionTransaction`.
    The lifespan of the :class:`.SessionTransaction` ends when the
    :meth:`.Session.commit`, :meth:`.Session.rollback` or :meth:`.Session.close`
    methods are called.  At this point, the :class:`.SessionTransaction` removes
    its association with its parent :class:`.Session`.   A :class:`.Session`
    that is in ``autocommit=False`` mode will create a new
    :class:`.SessionTransaction` to replace it immediately, whereas a
    :class:`.Session` that's in ``autocommit=True``
    mode will remain without a :class:`.SessionTransaction` until the
    :meth:`.Session.begin` method is called.
    Another detail of :class:`.SessionTransaction` behavior is that it is
    capable of "nesting".  This means that the :meth:`.begin` method can
    be called while an existing :class:`.SessionTransaction` is already present,
    producing a new :class:`.SessionTransaction` that temporarily replaces
    the parent :class:`.SessionTransaction`.   When a :class:`.SessionTransaction`
    is produced as nested, it assigns itself to the :attr:`.Session.transaction`
    attribute.  When it is ended via :meth:`.Session.commit` or :meth:`.Session.rollback`,
    it restores its parent :class:`.SessionTransaction` back onto the
    :attr:`.Session.transaction` attribute.  The
    behavior is effectively a stack, where :attr:`.Session.transaction` refers
    to the current head of the stack.
    The purpose of this stack is to allow nesting of :meth:`.rollback` or
    :meth:`.commit` calls in context with various flavors of :meth:`.begin`.
    This nesting behavior applies to when :meth:`.Session.begin_nested`
    is used to emit a SAVEPOINT transaction, and is also used to produce
    a so-called "subtransaction" which allows a block of code to use a
    begin/rollback/commit sequence regardless of whether or not its enclosing
    code block has begun a transaction.  The :meth:`.flush` method, whether called
    explicitly or via autoflush, is the primary consumer of the "subtransaction"
    feature, in that it wishes to guarantee that it works within in a transaction block
    regardless of whether or not the :class:`.Session` is in transactional mode
    when the method is called.
    See also:
    :meth:`.Session.rollback`
    :meth:`.Session.commit`
    :meth:`.Session.begin`
    :meth:`.Session.begin_nested`
    :attr:`.Session.is_active`
    :meth:`.SessionEvents.after_commit`
    :meth:`.SessionEvents.after_rollback`
    :meth:`.SessionEvents.after_soft_rollback`
    """
    _rollback_exception = None
    def __init__(self, session, parent=None, nested=False):
        self.session = session
        self._connections = {}
        self._parent = parent
        self.nested = nested
        self._active = True
        self._prepared = False
        if not parent and nested:
            raise sa_exc.InvalidRequestError(
                "Can't start a SAVEPOINT transaction when no existing "
                "transaction is in progress")
        if self.session._enable_transaction_accounting:
            self._take_snapshot()
    @property
    def is_active(self):
        return self.session is not None and self._active
    def _assert_is_active(self):
        self._assert_is_open()
        if not self._active:
            if self._rollback_exception:
                raise sa_exc.InvalidRequestError(
                    "This Session's transaction has been rolled back "
                    "due to a previous exception during flush."
                    " To begin a new transaction with this Session, "
                    "first issue Session.rollback()."
                    " Original exception was: %s"
                    % self._rollback_exception
                )
            else:
                raise sa_exc.InvalidRequestError(
                    "This Session's transaction has been rolled back "
                    "by a nested rollback() call.  To begin a new "
                    "transaction, issue Session.rollback() first."
                    )
    def _assert_is_open(self, error_msg="The transaction is closed"):
        if self.session is None:
            raise sa_exc.ResourceClosedError(error_msg)
    @property
    def _is_transaction_boundary(self):
        return self.nested or not self._parent
    def connection(self, bindkey, **kwargs):
        self._assert_is_active()
        engine = self.session.get_bind(bindkey, **kwargs)
        return self._connection_for_bind(engine)
    def _begin(self, nested=False):
        self._assert_is_active()
        return SessionTransaction(
            self.session, self, nested=nested)
    def _iterate_parents(self, upto=None):
        if self._parent is upto:
            return (self,)
        else:
            if self._parent is None:
                raise sa_exc.InvalidRequestError(
                    "Transaction %s is not on the active transaction list" % (
                    upto))
            return (self,) + self._parent._iterate_parents(upto)
    def _take_snapshot(self):
        if not self._is_transaction_boundary:
            self._new = self._parent._new
            self._deleted = self._parent._deleted
            self._key_switches = self._parent._key_switches
            return
        if not self.session._flushing:
            self.session.flush()
        self._new = weakref.WeakKeyDictionary()
        self._deleted = weakref.WeakKeyDictionary()
        self._key_switches = weakref.WeakKeyDictionary()
    def _restore_snapshot(self):
        assert self._is_transaction_boundary
        for s in set(self._new).union(self.session._new):
            self.session._expunge_state(s)
            if s.key:
                del s.key
        for s, (oldkey, newkey) in self._key_switches.items():
            self.session.identity_map.discard(s)
            s.key = oldkey
            self.session.identity_map.replace(s)
        for s in set(self._deleted).union(self.session._deleted):
            if s.deleted:
                #assert s in self._deleted
                del s.deleted
            self.session._update_impl(s, discard_existing=True)
        assert not self.session._deleted
        for s in self.session.identity_map.all_states():
            s.expire(s.dict, self.session.identity_map._modified)
    def _remove_snapshot(self):
        assert self._is_transaction_boundary
        if not self.nested and self.session.expire_on_commit:
            for s in self.session.identity_map.all_states():
                s.expire(s.dict, self.session.identity_map._modified)
    def _connection_for_bind(self, bind):
        self._assert_is_active()
        if bind in self._connections:
            return self._connections[bind][0]
        if self._parent:
            conn = self._parent._connection_for_bind(bind)
            if not self.nested:
                return conn
        else:
            if isinstance(bind, engine.Connection):
                conn = bind
                if conn.engine in self._connections:
                    raise sa_exc.InvalidRequestError(
                        "Session already has a Connection associated for the "
                        "given Connection's Engine")
            else:
                conn = bind.contextual_connect()
        if self.session.twophase and self._parent is None:
            transaction = conn.begin_twophase()
        elif self.nested:
            transaction = conn.begin_nested()
        else:
            transaction = conn.begin()
        self._connections[conn] = self._connections[conn.engine] = \
          (conn, transaction, conn is not bind)
        self.session.dispatch.after_begin(self.session, self, conn)
        return conn
    def prepare(self):
        if self._parent is not None or not self.session.twophase:
            raise sa_exc.InvalidRequestError(
                "Only root two phase transactions of can be prepared")
        self._prepare_impl()
    def _prepare_impl(self):
        self._assert_is_active()
        if self._parent is None or self.nested:
            self.session.dispatch.before_commit(self.session)
        stx = self.session.transaction
        if stx is not self:
            for subtransaction in stx._iterate_parents(upto=self):
                subtransaction.commit()
        if not self.session._flushing:
            for _flush_guard in xrange(100):
                if self.session._is_clean():
                    break
                self.session.flush()
            else:
                raise exc.FlushError(
                        "Over 100 subsequent flushes have occurred within "
                        "session.commit() - is an after_flush() hook "
                        "creating new objects?")
        if self._parent is None and self.session.twophase:
            try:
                for t in set(self._connections.values()):
                    t[1].prepare()
            except:
                self.rollback()
                raise
        self._deactivate()
        self._prepared = True
    def commit(self):
        self._assert_is_open()
        if not self._prepared:
            self._prepare_impl()
        if self._parent is None or self.nested:
            for t in set(self._connections.values()):
                t[1].commit()
            self.session.dispatch.after_commit(self.session)
            if self.session._enable_transaction_accounting:
                self._remove_snapshot()
        self.close()
        return self._parent
    def rollback(self, _capture_exception=False):
        self._assert_is_open()
        stx = self.session.transaction
        if stx is not self:
            for subtransaction in stx._iterate_parents(upto=self):
                subtransaction.close()
        if self.is_active or self._prepared:
            for transaction in self._iterate_parents():
                if transaction._parent is None or transaction.nested:
                    transaction._rollback_impl()
                    transaction._deactivate()
                    break
                else:
                    transaction._deactivate()
        sess = self.session
        if self.session._enable_transaction_accounting and \
            not sess._is_clean():
            # if items were added, deleted, or mutated
            # here, we need to re-restore the snapshot
            util.warn(
                    "Session's state has been changed on "
                    "a non-active transaction - this state "
                    "will be discarded.")
            self._restore_snapshot()
        self.close()
        if self._parent and _capture_exception:
            self._parent._rollback_exception = sys.exc_info()[1]
        sess.dispatch.after_soft_rollback(sess, self)
        return self._parent
    def _rollback_impl(self):
        for t in set(self._connections.values()):
            t[1].rollback()
        if self.session._enable_transaction_accounting:
            self._restore_snapshot()
        self.session.dispatch.after_rollback(self.session)
    def _deactivate(self):
        self._active = False
    def close(self):
        self.session.transaction = self._parent
        if self._parent is None:
            for connection, transaction, autoclose in \
                set(self._connections.values()):
                if autoclose:
                    connection.close()
                else:
                    transaction.close()
            if not self.session.autocommit:
                self.session.begin()
        self._deactivate()
        self.session = None
        self._connections = None
    def __enter__(self):
        return self
    def __exit__(self, type, value, traceback):
        self._assert_is_open("Cannot end transaction context. The transaction "
                                    "was closed from within the context")
        if self.session.transaction is None:
            return
        if type is None:
            try:
                self.commit()
            except:
                self.rollback()
                raise
        else:
            self.rollback()
class Session(object):
    """Manages persistence operations for ORM-mapped objects.
    The Session's usage paradigm is described at :ref:`session_toplevel`.
    """
    public_methods = (
        '__contains__', '__iter__', 'add', 'add_all', 'begin', 'begin_nested',
        'close', 'commit', 'connection', 'delete', 'execute', 'expire',
        'expire_all', 'expunge', 'expunge_all', 'flush', 'get_bind',
        'is_modified',
        'merge', 'query', 'refresh', 'rollback',
        'scalar')
    def __init__(self, bind=None, autoflush=True, expire_on_commit=True,
                _enable_transaction_accounting=True,
                 autocommit=False, twophase=False,
                 weak_identity_map=True, binds=None, extension=None,
                 query_cls=query.Query):
        """Construct a new Session.
        See also the :func:`.sessionmaker` function which is used to
        generate a :class:`.Session`-producing callable with a given
        set of arguments.
        :param autocommit: Defaults to ``False``. When ``True``, the ``Session``
          does not keep a persistent transaction running, and will acquire
          connections from the engine on an as-needed basis, returning them
          immediately after their use. Flushes will begin and commit (or possibly
          rollback) their own transaction if no transaction is present. When using
          this mode, the `session.begin()` method may be used to begin a
          transaction explicitly.
          Leaving it on its default value of ``False`` means that the ``Session``
          will acquire a connection and begin a transaction the first time it is
          used, which it will maintain persistently until ``rollback()``,
          ``commit()``, or ``close()`` is called. When the transaction is released
          by any of these methods, the ``Session`` is ready for the next usage,
          which will again acquire and maintain a new connection/transaction.
        :param autoflush: When ``True``, all query operations will issue a
           ``flush()`` call to this ``Session`` before proceeding. This is a
           convenience feature so that ``flush()`` need not be called repeatedly
           in order for database queries to retrieve results. It's typical that
           ``autoflush`` is used in conjunction with ``autocommit=False``. In this
           scenario, explicit calls to ``flush()`` are rarely needed; you usually
           only need to call ``commit()`` (which flushes) to finalize changes.
        :param bind: An optional ``Engine`` or ``Connection`` to which this
           ``Session`` should be bound. When specified, all SQL operations
           performed by this session will execute via this connectable.
        :param binds: An optional dictionary which contains more granular "bind"
           information than the ``bind`` parameter provides. This dictionary can
           map individual ``Table`` instances as well as ``Mapper`` instances to
           individual ``Engine`` or ``Connection`` objects. Operations which
           proceed relative to a particular ``Mapper`` will consult this
           dictionary for the direct ``Mapper`` instance as well as the mapper's
           ``mapped_table`` attribute in order to locate an connectable to use.
           The full resolution is described in the ``get_bind()`` method of
           ``Session``. Usage looks like::
            Session = sessionmaker(binds={
                SomeMappedClass: create_engine('postgresql://engine1'),
                somemapper: create_engine('postgresql://engine2'),
                some_table: create_engine('postgresql://engine3'),
                })
          Also see the :meth:`.Session.bind_mapper` and :meth:`.Session.bind_table` methods.
        :param \class_: Specify an alternate class other than
           ``sqlalchemy.orm.session.Session`` which should be used by the returned
           class. This is the only argument that is local to the
           ``sessionmaker()`` function, and is not sent directly to the
           constructor for ``Session``.
        :param _enable_transaction_accounting:  Defaults to ``True``.  A
           legacy-only flag which when ``False`` disables *all* 0.5-style object
           accounting on transaction boundaries, including auto-expiry of
           instances on rollback and commit, maintenance of the "new" and
           "deleted" lists upon rollback, and autoflush of pending changes upon
           begin(), all of which are interdependent.
        :param expire_on_commit:  Defaults to ``True``. When ``True``, all
           instances will be fully expired after each ``commit()``, so that all
           attribute/object access subsequent to a completed transaction will load
           from the most recent database state.
        :param extension: An optional
           :class:`~.SessionExtension` instance, or a list
           of such instances, which will receive pre- and post- commit and flush
           events, as well as a post-rollback event. **Deprecated.**
           Please see :class:`.SessionEvents`.
        :param query_cls:  Class which should be used to create new Query objects,
           as returned by the ``query()`` method. Defaults to
           :class:`~sqlalchemy.orm.query.Query`.
        :param twophase:  When ``True``, all transactions will be started as
            a "two phase" transaction, i.e. using the "two phase" semantics
            of the database in use along with an XID.  During a ``commit()``,
            after ``flush()`` has been issued for all attached databases, the
            ``prepare()`` method on each database's ``TwoPhaseTransaction`` will
            be called. This allows each database to roll back the entire
            transaction, before each transaction is committed.
        :param weak_identity_map:  Defaults to ``True`` - when set to
           ``False``, objects placed in the :class:`.Session` will be
           strongly referenced until explicitly removed or the
           :class:`.Session` is closed.  **Deprecated** - this option
           is obsolete.
        """
        if weak_identity_map:
            self._identity_cls = identity.WeakInstanceDict
        else:
            util.warn_deprecated("weak_identity_map=False is deprecated.  "
                                    "This feature is not needed.")
            self._identity_cls = identity.StrongInstanceDict
        self.identity_map = self._identity_cls()
        self._new = {}   # InstanceState->object, strong refs object
        self._deleted = {}  # same
        self.bind = bind
        self.__binds = {}
        self._flushing = False
        self.transaction = None
        self.hash_key = _new_sessionid()
        self.autoflush = autoflush
        self.autocommit = autocommit
        self.expire_on_commit = expire_on_commit
        self._enable_transaction_accounting = _enable_transaction_accounting
        self.twophase = twophase
        self._query_cls = query_cls
        if extension:
            for ext in util.to_list(extension):
                SessionExtension._adapt_listener(self, ext)
        if binds is not None:
            for mapperortable, bind in binds.iteritems():
                if isinstance(mapperortable, (type, Mapper)):
                    self.bind_mapper(mapperortable, bind)
                else:
                    self.bind_table(mapperortable, bind)
        if not self.autocommit:
            self.begin()
        _sessions[self.hash_key] = self
    dispatch = event.dispatcher(SessionEvents)
    connection_callable = None
    transaction = None
    """The current active or inactive :class:`.SessionTransaction`."""
    def begin(self, subtransactions=False, nested=False):
        """Begin a transaction on this Session.
        If this Session is already within a transaction, either a plain
        transaction or nested transaction, an error is raised, unless
        ``subtransactions=True`` or ``nested=True`` is specified.
        The ``subtransactions=True`` flag indicates that this :meth:`~.Session.begin`
        can create a subtransaction if a transaction is already in progress.
        For documentation on subtransactions, please see :ref:`session_subtransactions`.
        The ``nested`` flag begins a SAVEPOINT transaction and is equivalent
        to calling :meth:`~.Session.begin_nested`. For documentation on SAVEPOINT
        transactions, please see :ref:`session_begin_nested`.
        """
        if self.transaction is not None:
            if subtransactions or nested:
                self.transaction = self.transaction._begin(
                                        nested=nested)
            else:
                raise sa_exc.InvalidRequestError(
                    "A transaction is already begun.  Use subtransactions=True "
                    "to allow subtransactions.")
        else:
            self.transaction = SessionTransaction(
                self, nested=nested)
        return self.transaction  # needed for __enter__/__exit__ hook
    def begin_nested(self):
        """Begin a `nested` transaction on this Session.
        The target database(s) must support SQL SAVEPOINTs or a
        SQLAlchemy-supported vendor implementation of the idea.
        For documentation on SAVEPOINT
        transactions, please see :ref:`session_begin_nested`.
        """
        return self.begin(nested=True)
    def rollback(self):
        """Rollback the current transaction in progress.
        If no transaction is in progress, this method is a pass-through.
        This method rolls back the current transaction or nested transaction
        regardless of subtransactions being in effect.  All subtransactions up
        to the first real transaction are closed.  Subtransactions occur when
        begin() is called multiple times.
        """
        if self.transaction is None:
            pass
        else:
            self.transaction.rollback()
    def commit(self):
        """Flush pending changes and commit the current transaction.
        If no transaction is in progress, this method raises an
        InvalidRequestError.
        By default, the :class:`.Session` also expires all database
        loaded state on all ORM-managed attributes after transaction commit.
        This so that subsequent operations load the most recent
        data from the database.   This behavior can be disabled using
        the ``expire_on_commit=False`` option to :func:`.sessionmaker` or
        the :class:`.Session` constructor.
        If a subtransaction is in effect (which occurs when begin() is called
        multiple times), the subtransaction will be closed, and the next call
        to ``commit()`` will operate on the enclosing transaction.
        For a session configured with autocommit=False, a new transaction will
        be begun immediately after the commit, but note that the newly begun
        transaction does *not* use any connection resources until the first
        SQL is actually emitted.
        """
        if self.transaction is None:
            if not self.autocommit:
                self.begin()
            else:
                raise sa_exc.InvalidRequestError("No transaction is begun.")
        self.transaction.commit()
    def prepare(self):
        """Prepare the current transaction in progress for two phase commit.
        If no transaction is in progress, this method raises an
        InvalidRequestError.
        Only root transactions of two phase sessions can be prepared. If the
        current transaction is not such, an InvalidRequestError is raised.
        """
        if self.transaction is None:
            if not self.autocommit:
                self.begin()
            else:
                raise sa_exc.InvalidRequestError("No transaction is begun.")
        self.transaction.prepare()
    def connection(self, mapper=None, clause=None,
                        bind=None,
                        close_with_result=False,
                        **kw):
        """Return a :class:`.Connection` object corresponding to this
        :class:`.Session` object's transactional state.
        If this :class:`.Session` is configured with ``autocommit=False``,
        either the :class:`.Connection` corresponding to the current transaction
        is returned, or if no transaction is in progress, a new one is begun
        and the :class:`.Connection` returned (note that no transactional state
        is established with the DBAPI until the first SQL statement is emitted).
        Alternatively, if this :class:`.Session` is configured with ``autocommit=True``,
        an ad-hoc :class:`.Connection` is returned using :meth:`.Engine.contextual_connect`
        on the underlying :class:`.Engine`.
        Ambiguity in multi-bind or unbound :class:`.Session` objects can be resolved through
        any of the optional keyword arguments.   This ultimately makes usage of the
        :meth:`.get_bind` method for resolution.
        :param bind:
          Optional :class:`.Engine` to be used as the bind.  If
          this engine is already involved in an ongoing transaction,
          that connection will be used.  This argument takes precedence
          over ``mapper``, ``clause``.
        :param mapper:
          Optional :func:`.mapper` mapped class, used to identify
          the appropriate bind.  This argument takes precedence over
          ``clause``.
        :param clause:
            A :class:`.ClauseElement` (i.e. :func:`~.sql.expression.select`,
            :func:`~.sql.expression.text`,
            etc.) which will be used to locate a bind, if a bind
            cannot otherwise be identified.
        :param close_with_result: Passed to :meth:`Engine.connect`, indicating
          the :class:`.Connection` should be considered "single use", automatically
          closing when the first result set is closed.  This flag only has
          an effect if this :class:`.Session` is configured with ``autocommit=True``
          and does not already have a  transaction in progress.
        :param \**kw:
          Additional keyword arguments are sent to :meth:`get_bind()`,
          allowing additional arguments to be passed to custom
          implementations of :meth:`get_bind`.
        """
        if bind is None:
            bind = self.get_bind(mapper, clause=clause, **kw)
        return self._connection_for_bind(bind,
                                        close_with_result=close_with_result)
    def _connection_for_bind(self, engine, **kwargs):
        if self.transaction is not None:
            return self.transaction._connection_for_bind(engine)
        else:
            return engine.contextual_connect(**kwargs)
    def execute(self, clause, params=None, mapper=None, bind=None, **kw):
        """Execute a SQL expression construct or string statement within
        the current transaction.
        Returns a :class:`.ResultProxy` representing
        results of the statement execution, in the same manner as that of an
        :class:`.Engine` or
        :class:`.Connection`.
        E.g.::
            result = session.execute(
                        user_table.select().where(user_table.c.id == 5)
                    )
        :meth:`~.Session.execute` accepts any executable clause construct, such
        as :func:`~.sql.expression.select`,
        :func:`~.sql.expression.insert`,
        :func:`~.sql.expression.update`,
        :func:`~.sql.expression.delete`, and
        :func:`~.sql.expression.text`.  Plain SQL strings can be passed
        as well, which in the case of :meth:`.Session.execute` only
        will be interpreted the same as if it were passed via a :func:`~.expression.text`
        construct.  That is, the following usage::
            result = session.execute(
                        "SELECT * FROM user WHERE id=:param",
                        {"param":5}
                    )
        is equivalent to::
            from sqlalchemy import text
            result = session.execute(
                        text("SELECT * FROM user WHERE id=:param"),
                        {"param":5}
                    )
        The second positional argument to :meth:`.Session.execute` is an
        optional parameter set.  Similar to that of :meth:`.Connection.execute`, whether this
        is passed as a single dictionary, or a list of dictionaries, determines
        whether the DBAPI cursor's ``execute()`` or ``executemany()`` is used to execute the
        statement.   An INSERT construct may be invoked for a single row::
            result = session.execute(users.insert(), {"id": 7, "name": "somename"})
        or for multiple rows::
            result = session.execute(users.insert(), [
                                    {"id": 7, "name": "somename7"},
                                    {"id": 8, "name": "somename8"},
                                    {"id": 9, "name": "somename9"}
                                ])
        The statement is executed within the current transactional context of
        this :class:`.Session`.   The :class:`.Connection` which is used
        to execute the statement can also be acquired directly by
        calling the :meth:`.Session.connection` method.  Both methods use
        a rule-based resolution scheme in order to determine the
        :class:`.Connection`, which in the average case is derived directly
        from the "bind" of the :class:`.Session` itself, and in other cases
        can be based on the :func:`.mapper`
        and :class:`.Table` objects passed to the method; see the documentation
        for :meth:`.Session.get_bind` for a full description of this scheme.
        The :meth:`.Session.execute` method does *not* invoke autoflush.
        The :class:`.ResultProxy` returned by the :meth:`.Session.execute`
        method is returned with the "close_with_result" flag set to true;
        the significance of this flag is that if this :class:`.Session` is
        autocommitting and does not have a transaction-dedicated :class:`.Connection`
        available, a temporary :class:`.Connection` is established for the
        statement execution, which is closed (meaning, returned to the connection
        pool) when the :class:`.ResultProxy` has consumed all available data.
        This applies *only* when the :class:`.Session` is configured with
        autocommit=True and no transaction has been started.
        :param clause:
            An executable statement (i.e. an :class:`.Executable` expression
            such as :func:`.expression.select`) or string SQL statement
            to be executed.
        :param params:
            Optional dictionary, or list of dictionaries, containing
            bound parameter values.   If a single dictionary, single-row
            execution occurs; if a list of dictionaries, an
            "executemany" will be invoked.  The keys in each dictionary
            must correspond to parameter names present in the statement.
        :param mapper:
          Optional :func:`.mapper` or mapped class, used to identify
          the appropriate bind.  This argument takes precedence over
          ``clause`` when locating a bind.   See :meth:`.Session.get_bind`
          for more details.
        :param bind:
          Optional :class:`.Engine` to be used as the bind.  If
          this engine is already involved in an ongoing transaction,
          that connection will be used.  This argument takes
          precedence over ``mapper`` and ``clause`` when locating
          a bind.
        :param \**kw:
          Additional keyword arguments are sent to :meth:`.Session.get_bind()`
          to allow extensibility of "bind" schemes.
        .. seealso::
            :ref:`sqlexpression_toplevel` - Tutorial on using Core SQL
            constructs.
            :ref:`connections_toplevel` - Further information on direct
            statement execution.
            :meth:`.Connection.execute` - core level statement execution
            method, which is :meth:`.Session.execute` ultimately uses
            in order to execute the statement.
        """
        clause = expression._literal_as_text(clause)
        if bind is None:
            bind = self.get_bind(mapper, clause=clause, **kw)
        return self._connection_for_bind(bind, close_with_result=True).execute(
            clause, params or {})
    def scalar(self, clause, params=None, mapper=None, bind=None, **kw):
        """Like :meth:`~.Session.execute` but return a scalar result."""
        return self.execute(clause, params=params, mapper=mapper, bind=bind, **kw).scalar()
    def close(self):
        """Close this Session.
        This clears all items and ends any transaction in progress.
        If this session were created with ``autocommit=False``, a new
        transaction is immediately begun.  Note that this new transaction does
        not use any connection resources until they are first needed.
        """
        self.expunge_all()
        if self.transaction is not None:
            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``.
        This is equivalent to calling ``expunge(obj)`` on all objects in this
        ``Session``.
        """
        for state in self.identity_map.all_states() + list(self._new):
            state.detach()
        self.identity_map = self._identity_cls()
        self._new = {}
        self._deleted = {}
    # TODO: need much more test coverage for bind_mapper() and similar !
    # TODO: + crystalize + document resolution order vis. bind_mapper/bind_table
    def bind_mapper(self, mapper, bind):
        """Bind operations for a mapper to a Connectable.
        mapper
          A mapper instance or mapped class
        bind
          Any Connectable: a ``Engine`` or ``Connection``.
        All subsequent operations involving this mapper will use the given
        `bind`.
        """
        if isinstance(mapper, type):
            mapper = _class_mapper(mapper)
        self.__binds[mapper.base_mapper] = bind
        for t in mapper._all_tables:
            self.__binds[t] = bind
    def bind_table(self, table, bind):
        """Bind operations on a Table to a Connectable.
        table
          A ``Table`` instance
        bind
          Any Connectable: a ``Engine`` or ``Connection``.
        All subsequent operations involving this ``Table`` will use the
        given `bind`.
        """
        self.__binds[table] = bind
    def get_bind(self, mapper=None, clause=None):
        """Return a "bind" to which this :class:`.Session` is bound.
        The "bind" is usually an instance of :class:`.Engine`,
        except in the case where the :class:`.Session` has been
        explicitly bound directly to a :class:`.Connection`.
        For a multiply-bound or unbound :class:`.Session`, the
        ``mapper`` or ``clause`` arguments are used to determine the
        appropriate bind to return.
        Note that the "mapper" argument is usually present
        when :meth:`.Session.get_bind` is called via an ORM
        operation such as a :meth:`.Session.query`, each
        individual INSERT/UPDATE/DELETE operation within a
        :meth:`.Session.flush`, call, etc.
        The order of resolution is:
        1. if mapper given and session.binds is present,
           locate a bind based on mapper.
        2. if clause given and session.binds is present,
           locate a bind based on :class:`.Table` objects
           found in the given clause present in session.binds.
        3. if session.bind is present, return that.
        4. if clause given, attempt to return a bind
           linked to the :class:`.MetaData` ultimately
           associated with the clause.
        5. if mapper given, attempt to return a bind
           linked to the :class:`.MetaData` ultimately
           associated with the :class:`.Table` or other
           selectable to which the mapper is mapped.
        6. No bind can be found, :class:`.UnboundExecutionError`
           is raised.
        :param mapper:
          Optional :func:`.mapper` mapped class or instance of
          :class:`.Mapper`.   The bind can be derived from a :class:`.Mapper`
          first by consulting the "binds" map associated with this
          :class:`.Session`, and secondly by consulting the :class:`.MetaData`
          associated with the :class:`.Table` to which the :class:`.Mapper`
          is mapped for a bind.
        :param clause:
            A :class:`.ClauseElement` (i.e. :func:`~.sql.expression.select`,
            :func:`~.sql.expression.text`,
            etc.).  If the ``mapper`` argument is not present or could not produce
            a bind, the given expression construct will be searched for a bound
            element, typically a :class:`.Table` associated with bound
            :class:`.MetaData`.
        """
        if mapper is clause is None:
            if self.bind:
                return self.bind
            else:
                raise sa_exc.UnboundExecutionError(
                    "This session is not bound to a single Engine or "
                    "Connection, and no context was provided to locate "
                    "a binding.")
        c_mapper = mapper is not None and _class_to_mapper(mapper) or None
        # manually bound?
        if self.__binds:
            if c_mapper:
                if c_mapper.base_mapper in self.__binds:
                    return self.__binds[c_mapper.base_mapper]
                elif c_mapper.mapped_table in self.__binds:
                    return self.__binds[c_mapper.mapped_table]
            if clause is not None:
                for t in sql_util.find_tables(clause, include_crud=True):
                    if t in self.__binds:
                        return self.__binds[t]
        if self.bind:
            return self.bind
        if isinstance(clause, sql.expression.ClauseElement) and clause.bind:
            return clause.bind
        if c_mapper and c_mapper.mapped_table.bind:
            return c_mapper.mapped_table.bind
        context = []
        if mapper is not None:
            context.append('mapper %s' % c_mapper)
        if clause is not None:
            context.append('SQL expression')
        raise sa_exc.UnboundExecutionError(
            "Could not locate a bind configured on %s or this Session" % (
            ', '.join(context)))
    def query(self, *entities, **kwargs):
        """Return a new ``Query`` object corresponding to this ``Session``."""
        return self._query_cls(entities, self, **kwargs)
    @property
    @util.contextmanager
    def no_autoflush(self):
        """Return a context manager that disables autoflush.
        e.g.::
            with session.no_autoflush:
                some_object = SomeClass()
                session.add(some_object)
                # won't autoflush
                some_object.related_thing = session.query(SomeRelated).first()
        Operations that proceed within the ``with:`` block
        will not be subject to flushes occurring upon query
        access.  This is useful when initializing a series
        of objects which involve existing database queries,
        where the uncompleted object should not yet be flushed.
        .. versionadded:: 0.7.6
        """
        autoflush = self.autoflush
        self.autoflush = False
        yield self
        self.autoflush = autoflush
    def _autoflush(self):
        if self.autoflush and not self._flushing:
            self.flush()
    def _finalize_loaded(self, states):


Answer:         for state, dict_ in states.items():