1# orm/session.py
2# Copyright (C) 2005-2019 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: http://www.opensource.org/licenses/mit-license.php
7"""Provides the Session class and related utilities."""
8
9
10import itertools
11import sys
12import weakref
13
14from . import attributes
15from . import exc
16from . import identity
17from . import loading
18from . import persistence
19from . import query
20from . import state as statelib
21from .base import _class_to_mapper
22from .base import _none_set
23from .base import _state_mapper
24from .base import instance_str
25from .base import object_mapper
26from .base import object_state
27from .base import state_str
28from .deprecated_interfaces import SessionExtension
29from .unitofwork import UOWTransaction
30from .. import engine
31from .. import exc as sa_exc
32from .. import sql
33from .. import util
34from ..inspection import inspect
35from ..sql import expression
36from ..sql import util as sql_util
37
38__all__ = ["Session", "SessionTransaction", "SessionExtension", "sessionmaker"]
39
40_sessions = weakref.WeakValueDictionary()
41"""Weak-referencing dictionary of :class:`.Session` objects.
42"""
43
44
45def _state_session(state):
46    """Given an :class:`.InstanceState`, return the :class:`.Session`
47        associated, if any.
48    """
49    if state.session_id:
50        try:
51            return _sessions[state.session_id]
52        except KeyError:
53            pass
54    return None
55
56
57class _SessionClassMethods(object):
58    """Class-level methods for :class:`.Session`, :class:`.sessionmaker`."""
59
60    @classmethod
61    def close_all(cls):
62        """Close *all* sessions in memory."""
63
64        for sess in _sessions.values():
65            sess.close()
66
67    @classmethod
68    @util.dependencies("sqlalchemy.orm.util")
69    def identity_key(cls, orm_util, *args, **kwargs):
70        """Return an identity key.
71
72        This is an alias of :func:`.util.identity_key`.
73
74        """
75        return orm_util.identity_key(*args, **kwargs)
76
77    @classmethod
78    def object_session(cls, instance):
79        """Return the :class:`.Session` to which an object belongs.
80
81        This is an alias of :func:`.object_session`.
82
83        """
84
85        return object_session(instance)
86
87
88ACTIVE = util.symbol("ACTIVE")
89PREPARED = util.symbol("PREPARED")
90COMMITTED = util.symbol("COMMITTED")
91DEACTIVE = util.symbol("DEACTIVE")
92CLOSED = util.symbol("CLOSED")
93
94
95class SessionTransaction(object):
96    """A :class:`.Session`-level transaction.
97
98    :class:`.SessionTransaction` is a mostly behind-the-scenes object
99    not normally referenced directly by application code.   It coordinates
100    among multiple :class:`.Connection` objects, maintaining a database
101    transaction for each one individually, committing or rolling them
102    back all at once.   It also provides optional two-phase commit behavior
103    which can augment this coordination operation.
104
105    The :attr:`.Session.transaction` attribute of :class:`.Session`
106    refers to the current :class:`.SessionTransaction` object in use, if any.
107    The :attr:`.SessionTransaction.parent` attribute refers to the parent
108    :class:`.SessionTransaction` in the stack of :class:`.SessionTransaction`
109    objects.  If this attribute is ``None``, then this is the top of the stack.
110    If non-``None``, then this :class:`.SessionTransaction` refers either
111    to a so-called "subtransaction" or a "nested" transaction.  A
112    "subtransaction" is a scoping concept that demarcates an inner portion
113    of the outermost "real" transaction.  A nested transaction, which
114    is indicated when the :attr:`.SessionTransaction.nested`
115    attribute is also True, indicates that this :class:`.SessionTransaction`
116    corresponds to a SAVEPOINT.
117
118    **Life Cycle**
119
120    A :class:`.SessionTransaction` is associated with a :class:`.Session`
121    in its default mode of ``autocommit=False`` immediately, associated
122    with no database connections.  As the :class:`.Session` is called upon
123    to emit SQL on behalf of various :class:`.Engine` or :class:`.Connection`
124    objects, a corresponding :class:`.Connection` and associated
125    :class:`.Transaction` is added to a collection within the
126    :class:`.SessionTransaction` object, becoming one of the
127    connection/transaction pairs maintained by the
128    :class:`.SessionTransaction`.  The start of a :class:`.SessionTransaction`
129    can be tracked using the :meth:`.SessionEvents.after_transaction_create`
130    event.
131
132    The lifespan of the :class:`.SessionTransaction` ends when the
133    :meth:`.Session.commit`, :meth:`.Session.rollback` or
134    :meth:`.Session.close` methods are called.  At this point, the
135    :class:`.SessionTransaction` removes its association with its parent
136    :class:`.Session`.   A :class:`.Session` that is in ``autocommit=False``
137    mode will create a new :class:`.SessionTransaction` to replace it
138    immediately, whereas a :class:`.Session` that's in ``autocommit=True``
139    mode will remain without a :class:`.SessionTransaction` until the
140    :meth:`.Session.begin` method is called.  The end of a
141    :class:`.SessionTransaction` can be tracked using the
142    :meth:`.SessionEvents.after_transaction_end` event.
143
144    **Nesting and Subtransactions**
145
146    Another detail of :class:`.SessionTransaction` behavior is that it is
147    capable of "nesting".  This means that the :meth:`.Session.begin` method
148    can be called while an existing :class:`.SessionTransaction` is already
149    present, producing a new :class:`.SessionTransaction` that temporarily
150    replaces the parent :class:`.SessionTransaction`.   When a
151    :class:`.SessionTransaction` is produced as nested, it assigns itself to
152    the :attr:`.Session.transaction` attribute, and it additionally will assign
153    the previous :class:`.SessionTransaction` to its :attr:`.Session.parent`
154    attribute.  The behavior is effectively a
155    stack, where :attr:`.Session.transaction` refers to the current head of
156    the stack, and the :attr:`.SessionTransaction.parent` attribute allows
157    traversal up the stack until :attr:`.SessionTransaction.parent` is
158    ``None``, indicating the top of the stack.
159
160    When the scope of :class:`.SessionTransaction` is ended via
161    :meth:`.Session.commit` or :meth:`.Session.rollback`, it restores its
162    parent :class:`.SessionTransaction` back onto the
163    :attr:`.Session.transaction` attribute.
164
165    The purpose of this stack is to allow nesting of
166    :meth:`.Session.rollback` or :meth:`.Session.commit` calls in context
167    with various flavors of :meth:`.Session.begin`. This nesting behavior
168    applies to when :meth:`.Session.begin_nested` is used to emit a
169    SAVEPOINT transaction, and is also used to produce a so-called
170    "subtransaction" which allows a block of code to use a
171    begin/rollback/commit sequence regardless of whether or not its enclosing
172    code block has begun a transaction.  The :meth:`.flush` method, whether
173    called explicitly or via autoflush, is the primary consumer of the
174    "subtransaction" feature, in that it wishes to guarantee that it works
175    within in a transaction block regardless of whether or not the
176    :class:`.Session` is in transactional mode when the method is called.
177
178    Note that the flush process that occurs within the "autoflush" feature
179    as well as when the :meth:`.Session.flush` method is used **always**
180    creates a :class:`.SessionTransaction` object.   This object is normally
181    a subtransaction, unless the :class:`.Session` is in autocommit mode
182    and no transaction exists at all, in which case it's the outermost
183    transaction.   Any event-handling logic or other inspection logic
184    needs to take into account whether a :class:`.SessionTransaction`
185    is the outermost transaction, a subtransaction, or a "nested" / SAVEPOINT
186    transaction.
187
188    .. seealso::
189
190        :meth:`.Session.rollback`
191
192        :meth:`.Session.commit`
193
194        :meth:`.Session.begin`
195
196        :meth:`.Session.begin_nested`
197
198        :attr:`.Session.is_active`
199
200        :meth:`.SessionEvents.after_transaction_create`
201
202        :meth:`.SessionEvents.after_transaction_end`
203
204        :meth:`.SessionEvents.after_commit`
205
206        :meth:`.SessionEvents.after_rollback`
207
208        :meth:`.SessionEvents.after_soft_rollback`
209
210    """
211
212    _rollback_exception = None
213
214    def __init__(self, session, parent=None, nested=False):
215        self.session = session
216        self._connections = {}
217        self._parent = parent
218        self.nested = nested
219        self._state = ACTIVE
220        if not parent and nested:
221            raise sa_exc.InvalidRequestError(
222                "Can't start a SAVEPOINT transaction when no existing "
223                "transaction is in progress"
224            )
225
226        if self.session._enable_transaction_accounting:
227            self._take_snapshot()
228
229        self.session.dispatch.after_transaction_create(self.session, self)
230
231    @property
232    def parent(self):
233        """The parent :class:`.SessionTransaction` of this
234        :class:`.SessionTransaction`.
235
236        If this attribute is ``None``, indicates this
237        :class:`.SessionTransaction` is at the top of the stack, and
238        corresponds to a real "COMMIT"/"ROLLBACK"
239        block.  If non-``None``, then this is either a "subtransaction"
240        or a "nested" / SAVEPOINT transaction.  If the
241        :attr:`.SessionTransaction.nested` attribute is ``True``, then
242        this is a SAVEPOINT, and if ``False``, indicates this a subtransaction.
243
244        .. versionadded:: 1.0.16 - use ._parent for previous versions
245
246        """
247        return self._parent
248
249    nested = False
250    """Indicates if this is a nested, or SAVEPOINT, transaction.
251
252    When :attr:`.SessionTransaction.nested` is True, it is expected
253    that :attr:`.SessionTransaction.parent` will be True as well.
254
255    """
256
257    @property
258    def is_active(self):
259        return self.session is not None and self._state is ACTIVE
260
261    def _assert_active(
262        self,
263        prepared_ok=False,
264        rollback_ok=False,
265        deactive_ok=False,
266        closed_msg="This transaction is closed",
267    ):
268        if self._state is COMMITTED:
269            raise sa_exc.InvalidRequestError(
270                "This session is in 'committed' state; no further "
271                "SQL can be emitted within this transaction."
272            )
273        elif self._state is PREPARED:
274            if not prepared_ok:
275                raise sa_exc.InvalidRequestError(
276                    "This session is in 'prepared' state; no further "
277                    "SQL can be emitted within this transaction."
278                )
279        elif self._state is DEACTIVE:
280            if not deactive_ok and not rollback_ok:
281                if self._rollback_exception:
282                    raise sa_exc.InvalidRequestError(
283                        "This Session's transaction has been rolled back "
284                        "due to a previous exception during flush."
285                        " To begin a new transaction with this Session, "
286                        "first issue Session.rollback()."
287                        " Original exception was: %s"
288                        % self._rollback_exception
289                    )
290                elif not deactive_ok:
291                    raise sa_exc.InvalidRequestError(
292                        "This session is in 'inactive' state, due to the "
293                        "SQL transaction being rolled back; no further "
294                        "SQL can be emitted within this transaction."
295                    )
296        elif self._state is CLOSED:
297            raise sa_exc.ResourceClosedError(closed_msg)
298
299    @property
300    def _is_transaction_boundary(self):
301        return self.nested or not self._parent
302
303    def connection(self, bindkey, execution_options=None, **kwargs):
304        self._assert_active()
305        bind = self.session.get_bind(bindkey, **kwargs)
306        return self._connection_for_bind(bind, execution_options)
307
308    def _begin(self, nested=False):
309        self._assert_active()
310        return SessionTransaction(self.session, self, nested=nested)
311
312    def _iterate_self_and_parents(self, upto=None):
313
314        current = self
315        result = ()
316        while current:
317            result += (current,)
318            if current._parent is upto:
319                break
320            elif current._parent is None:
321                raise sa_exc.InvalidRequestError(
322                    "Transaction %s is not on the active transaction list"
323                    % (upto)
324                )
325            else:
326                current = current._parent
327
328        return result
329
330    def _take_snapshot(self):
331        if not self._is_transaction_boundary:
332            self._new = self._parent._new
333            self._deleted = self._parent._deleted
334            self._dirty = self._parent._dirty
335            self._key_switches = self._parent._key_switches
336            return
337
338        if not self.session._flushing:
339            self.session.flush()
340
341        self._new = weakref.WeakKeyDictionary()
342        self._deleted = weakref.WeakKeyDictionary()
343        self._dirty = weakref.WeakKeyDictionary()
344        self._key_switches = weakref.WeakKeyDictionary()
345
346    def _restore_snapshot(self, dirty_only=False):
347        """Restore the restoration state taken before a transaction began.
348
349        Corresponds to a rollback.
350
351        """
352        assert self._is_transaction_boundary
353
354        to_expunge = set(self._new).union(self.session._new)
355        self.session._expunge_states(to_expunge, to_transient=True)
356
357        for s, (oldkey, newkey) in self._key_switches.items():
358            # we probably can do this conditionally based on
359            # if we expunged or not, but safe_discard does that anyway
360            self.session.identity_map.safe_discard(s)
361
362            # restore the old key
363            s.key = oldkey
364
365            # now restore the object, but only if we didn't expunge
366            if s not in to_expunge:
367                self.session.identity_map.replace(s)
368
369        for s in set(self._deleted).union(self.session._deleted):
370            self.session._update_impl(s, revert_deletion=True)
371
372        assert not self.session._deleted
373
374        for s in self.session.identity_map.all_states():
375            if not dirty_only or s.modified or s in self._dirty:
376                s._expire(s.dict, self.session.identity_map._modified)
377
378    def _remove_snapshot(self):
379        """Remove the restoration state taken before a transaction began.
380
381        Corresponds to a commit.
382
383        """
384        assert self._is_transaction_boundary
385
386        if not self.nested and self.session.expire_on_commit:
387            for s in self.session.identity_map.all_states():
388                s._expire(s.dict, self.session.identity_map._modified)
389
390            statelib.InstanceState._detach_states(
391                list(self._deleted), self.session
392            )
393            self._deleted.clear()
394        elif self.nested:
395            self._parent._new.update(self._new)
396            self._parent._dirty.update(self._dirty)
397            self._parent._deleted.update(self._deleted)
398            self._parent._key_switches.update(self._key_switches)
399
400    def _connection_for_bind(self, bind, execution_options):
401        self._assert_active()
402
403        if bind in self._connections:
404            if execution_options:
405                util.warn(
406                    "Connection is already established for the "
407                    "given bind; execution_options ignored"
408                )
409            return self._connections[bind][0]
410
411        if self._parent:
412            conn = self._parent._connection_for_bind(bind, execution_options)
413            if not self.nested:
414                return conn
415        else:
416            if isinstance(bind, engine.Connection):
417                conn = bind
418                if conn.engine in self._connections:
419                    raise sa_exc.InvalidRequestError(
420                        "Session already has a Connection associated for the "
421                        "given Connection's Engine"
422                    )
423            else:
424                conn = bind.contextual_connect()
425
426        if execution_options:
427            conn = conn.execution_options(**execution_options)
428
429        if self.session.twophase and self._parent is None:
430            transaction = conn.begin_twophase()
431        elif self.nested:
432            transaction = conn.begin_nested()
433        else:
434            transaction = conn.begin()
435
436        self._connections[conn] = self._connections[conn.engine] = (
437            conn,
438            transaction,
439            conn is not bind,
440        )
441        self.session.dispatch.after_begin(self.session, self, conn)
442        return conn
443
444    def prepare(self):
445        if self._parent is not None or not self.session.twophase:
446            raise sa_exc.InvalidRequestError(
447                "'twophase' mode not enabled, or not root transaction; "
448                "can't prepare."
449            )
450        self._prepare_impl()
451
452    def _prepare_impl(self):
453        self._assert_active()
454        if self._parent is None or self.nested:
455            self.session.dispatch.before_commit(self.session)
456
457        stx = self.session.transaction
458        if stx is not self:
459            for subtransaction in stx._iterate_self_and_parents(upto=self):
460                subtransaction.commit()
461
462        if not self.session._flushing:
463            for _flush_guard in range(100):
464                if self.session._is_clean():
465                    break
466                self.session.flush()
467            else:
468                raise exc.FlushError(
469                    "Over 100 subsequent flushes have occurred within "
470                    "session.commit() - is an after_flush() hook "
471                    "creating new objects?"
472                )
473
474        if self._parent is None and self.session.twophase:
475            try:
476                for t in set(self._connections.values()):
477                    t[1].prepare()
478            except:
479                with util.safe_reraise():
480                    self.rollback()
481
482        self._state = PREPARED
483
484    def commit(self):
485        self._assert_active(prepared_ok=True)
486        if self._state is not PREPARED:
487            self._prepare_impl()
488
489        if self._parent is None or self.nested:
490            for t in set(self._connections.values()):
491                t[1].commit()
492
493            self._state = COMMITTED
494            self.session.dispatch.after_commit(self.session)
495
496            if self.session._enable_transaction_accounting:
497                self._remove_snapshot()
498
499        self.close()
500        return self._parent
501
502    def rollback(self, _capture_exception=False):
503        self._assert_active(prepared_ok=True, rollback_ok=True)
504
505        stx = self.session.transaction
506        if stx is not self:
507            for subtransaction in stx._iterate_self_and_parents(upto=self):
508                subtransaction.close()
509
510        boundary = self
511        rollback_err = None
512        if self._state in (ACTIVE, PREPARED):
513            for transaction in self._iterate_self_and_parents():
514                if transaction._parent is None or transaction.nested:
515                    try:
516                        for t in set(transaction._connections.values()):
517                            t[1].rollback()
518
519                        transaction._state = DEACTIVE
520                        self.session.dispatch.after_rollback(self.session)
521                    except:
522                        rollback_err = sys.exc_info()
523                    finally:
524                        transaction._state = DEACTIVE
525                        if self.session._enable_transaction_accounting:
526                            transaction._restore_snapshot(
527                                dirty_only=transaction.nested
528                            )
529                    boundary = transaction
530                    break
531                else:
532                    transaction._state = DEACTIVE
533
534        sess = self.session
535
536        if (
537            not rollback_err
538            and sess._enable_transaction_accounting
539            and not sess._is_clean()
540        ):
541
542            # if items were added, deleted, or mutated
543            # here, we need to re-restore the snapshot
544            util.warn(
545                "Session's state has been changed on "
546                "a non-active transaction - this state "
547                "will be discarded."
548            )
549            boundary._restore_snapshot(dirty_only=boundary.nested)
550
551        self.close()
552
553        if self._parent and _capture_exception:
554            self._parent._rollback_exception = sys.exc_info()[1]
555
556        if rollback_err:
557            util.reraise(*rollback_err)
558
559        sess.dispatch.after_soft_rollback(sess, self)
560
561        return self._parent
562
563    def close(self, invalidate=False):
564        self.session.transaction = self._parent
565        if self._parent is None:
566            for connection, transaction, autoclose in set(
567                self._connections.values()
568            ):
569                if invalidate:
570                    connection.invalidate()
571                if autoclose:
572                    connection.close()
573                else:
574                    transaction.close()
575
576        self._state = CLOSED
577        self.session.dispatch.after_transaction_end(self.session, self)
578
579        if self._parent is None:
580            if not self.session.autocommit:
581                self.session.begin()
582        self.session = None
583        self._connections = None
584
585    def __enter__(self):
586        return self
587
588    def __exit__(self, type_, value, traceback):
589        self._assert_active(deactive_ok=True, prepared_ok=True)
590        if self.session.transaction is None:
591            return
592        if type_ is None:
593            try:
594                self.commit()
595            except:
596                with util.safe_reraise():
597                    self.rollback()
598        else:
599            self.rollback()
600
601
602class Session(_SessionClassMethods):
603    """Manages persistence operations for ORM-mapped objects.
604
605    The Session's usage paradigm is described at :doc:`/orm/session`.
606
607
608    """
609
610    public_methods = (
611        "__contains__",
612        "__iter__",
613        "add",
614        "add_all",
615        "begin",
616        "begin_nested",
617        "close",
618        "commit",
619        "connection",
620        "delete",
621        "execute",
622        "expire",
623        "expire_all",
624        "expunge",
625        "expunge_all",
626        "flush",
627        "get_bind",
628        "is_modified",
629        "bulk_save_objects",
630        "bulk_insert_mappings",
631        "bulk_update_mappings",
632        "merge",
633        "query",
634        "refresh",
635        "rollback",
636        "scalar",
637    )
638
639    def __init__(
640        self,
641        bind=None,
642        autoflush=True,
643        expire_on_commit=True,
644        _enable_transaction_accounting=True,
645        autocommit=False,
646        twophase=False,
647        weak_identity_map=True,
648        binds=None,
649        extension=None,
650        enable_baked_queries=True,
651        info=None,
652        query_cls=query.Query,
653    ):
654        r"""Construct a new Session.
655
656        See also the :class:`.sessionmaker` function which is used to
657        generate a :class:`.Session`-producing callable with a given
658        set of arguments.
659
660        :param autocommit:
661
662          .. warning::
663
664             The autocommit flag is **not for general use**, and if it is
665             used, queries should only be invoked within the span of a
666             :meth:`.Session.begin` / :meth:`.Session.commit` pair.  Executing
667             queries outside of a demarcated transaction is a legacy mode
668             of usage, and can in some cases lead to concurrent connection
669             checkouts.
670
671          Defaults to ``False``. When ``True``, the
672          :class:`.Session` does not keep a persistent transaction running,
673          and will acquire connections from the engine on an as-needed basis,
674          returning them immediately after their use. Flushes will begin and
675          commit (or possibly rollback) their own transaction if no
676          transaction is present. When using this mode, the
677          :meth:`.Session.begin` method is used to explicitly start
678          transactions.
679
680          .. seealso::
681
682            :ref:`session_autocommit`
683
684        :param autoflush: When ``True``, all query operations will issue a
685           :meth:`~.Session.flush` call to this ``Session`` before proceeding.
686           This is a convenience feature so that :meth:`~.Session.flush` need
687           not be called repeatedly in order for database queries to retrieve
688           results. It's typical that ``autoflush`` is used in conjunction
689           with ``autocommit=False``. In this scenario, explicit calls to
690           :meth:`~.Session.flush` are rarely needed; you usually only need to
691           call :meth:`~.Session.commit` (which flushes) to finalize changes.
692
693        :param bind: An optional :class:`.Engine` or :class:`.Connection` to
694           which this ``Session`` should be bound. When specified, all SQL
695           operations performed by this session will execute via this
696           connectable.
697
698        :param binds: A dictionary which may specify any number of
699           :class:`.Engine` or :class:`.Connection` objects as the source of
700           connectivity for SQL operations on a per-entity basis.   The keys
701           of the dictionary consist of any series of mapped classes,
702           arbitrary Python classes that are bases for mapped classes,
703           :class:`.Table` objects and :class:`.Mapper` objects.  The
704           values of the dictionary are then instances of :class:`.Engine`
705           or less commonly :class:`.Connection` objects.  Operations which
706           proceed relative to a particular mapped class will consult this
707           dictionary for the closest matching entity in order to determine
708           which :class:`.Engine` should be used for a particular SQL
709           operation.    The complete heuristics for resolution are
710           described at :meth:`.Session.get_bind`.  Usage looks like::
711
712            Session = sessionmaker(binds={
713                SomeMappedClass: create_engine('postgresql://engine1'),
714                SomeDeclarativeBase: create_engine('postgresql://engine2'),
715                some_mapper: create_engine('postgresql://engine3'),
716                some_table: create_engine('postgresql://engine4'),
717                })
718
719           .. seealso::
720
721                :ref:`session_partitioning`
722
723                :meth:`.Session.bind_mapper`
724
725                :meth:`.Session.bind_table`
726
727                :meth:`.Session.get_bind`
728
729
730        :param \class_: Specify an alternate class other than
731           ``sqlalchemy.orm.session.Session`` which should be used by the
732           returned class. This is the only argument that is local to the
733           :class:`.sessionmaker` function, and is not sent directly to the
734           constructor for ``Session``.
735
736        :param enable_baked_queries: defaults to ``True``.  A flag consumed
737           by the :mod:`sqlalchemy.ext.baked` extension to determine if
738           "baked queries" should be cached, as is the normal operation
739           of this extension.  When set to ``False``, all caching is disabled,
740           including baked queries defined by the calling application as
741           well as those used internally.  Setting this flag to ``False``
742           can significantly reduce memory use, however will also degrade
743           performance for those areas that make use of baked queries
744           (such as relationship loaders).   Additionally, baked query
745           logic in the calling application or potentially within the ORM
746           that may be malfunctioning due to cache key collisions or similar
747           can be flagged by observing if this flag resolves the issue.
748
749           .. versionadded:: 1.2
750
751        :param _enable_transaction_accounting:  Defaults to ``True``.  A
752           legacy-only flag which when ``False`` disables *all* 0.5-style
753           object accounting on transaction boundaries.
754
755           .. deprecated::  0.7
756
757                the :paramref:`.Session._enable_transaction_accounting`
758                parameter will be removed in a future release.
759
760        :param expire_on_commit:  Defaults to ``True``. When ``True``, all
761           instances will be fully expired after each :meth:`~.commit`,
762           so that all attribute/object access subsequent to a completed
763           transaction will load from the most recent database state.
764
765        :param extension: An optional
766           :class:`~.SessionExtension` instance, or a list
767           of such instances, which will receive pre- and post- commit and
768           flush events, as well as a post-rollback event.
769
770           .. deprecated:: 0.7
771
772                :class:`.SessionExtension` is deprecated in favor of the
773                :class:`.SessionEvents` listener interface.  The
774                :paramref:`.Session.extension` parameter will be
775                removed in a future release.
776
777        :param info: optional dictionary of arbitrary data to be associated
778           with this :class:`.Session`.  Is available via the
779           :attr:`.Session.info` attribute.  Note the dictionary is copied at
780           construction time so that modifications to the per-
781           :class:`.Session` dictionary will be local to that
782           :class:`.Session`.
783
784           .. versionadded:: 0.9.0
785
786        :param query_cls:  Class which should be used to create new Query
787          objects, as returned by the :meth:`~.Session.query` method.
788          Defaults to :class:`.Query`.
789
790        :param twophase:  When ``True``, all transactions will be started as
791            a "two phase" transaction, i.e. using the "two phase" semantics
792            of the database in use along with an XID.  During a
793            :meth:`~.commit`, after :meth:`~.flush` has been issued for all
794            attached databases, the :meth:`~.TwoPhaseTransaction.prepare`
795            method on each database's :class:`.TwoPhaseTransaction` will be
796            called. This allows each database to roll back the entire
797            transaction, before each transaction is committed.
798
799        :param weak_identity_map:  Defaults to ``True`` - when set to
800           ``False``, objects placed in the :class:`.Session` will be
801           strongly referenced until explicitly removed or the
802           :class:`.Session` is closed.
803
804           .. deprecated:: 1.0
805
806               The :paramref:`.Session.weak_identity_map` parameter as well as
807               the strong-referencing identity map are deprecated, and will be
808               removed in a future release.  For the use case where objects
809               present in a :class:`.Session` need to be automatically strong
810               referenced, see the recipe at
811               :ref:`session_referencing_behavior` for an event-based approach
812               to maintaining strong identity references.
813
814
815        """
816
817        if weak_identity_map:
818            self._identity_cls = identity.WeakInstanceDict
819        else:
820            util.warn_deprecated(
821                "weak_identity_map=False is deprecated.  "
822                "See the documentation on 'Session Referencing Behavior' "
823                "for an event-based approach to maintaining strong identity "
824                "references."
825            )
826
827            self._identity_cls = identity.StrongInstanceDict
828        self.identity_map = self._identity_cls()
829
830        self._new = {}  # InstanceState->object, strong refs object
831        self._deleted = {}  # same
832        self.bind = bind
833        self.__binds = {}
834        self._flushing = False
835        self._warn_on_events = False
836        self.transaction = None
837        self.hash_key = _new_sessionid()
838        self.autoflush = autoflush
839        self.autocommit = autocommit
840        self.expire_on_commit = expire_on_commit
841        self.enable_baked_queries = enable_baked_queries
842        self._enable_transaction_accounting = _enable_transaction_accounting
843        self.twophase = twophase
844        self._query_cls = query_cls
845        if info:
846            self.info.update(info)
847
848        if extension:
849            for ext in util.to_list(extension):
850                SessionExtension._adapt_listener(self, ext)
851
852        if binds is not None:
853            for key, bind in binds.items():
854                self._add_bind(key, bind)
855
856        if not self.autocommit:
857            self.begin()
858        _sessions[self.hash_key] = self
859
860    connection_callable = None
861
862    transaction = None
863    """The current active or inactive :class:`.SessionTransaction`."""
864
865    @util.memoized_property
866    def info(self):
867        """A user-modifiable dictionary.
868
869        The initial value of this dictionary can be populated using the
870        ``info`` argument to the :class:`.Session` constructor or
871        :class:`.sessionmaker` constructor or factory methods.  The dictionary
872        here is always local to this :class:`.Session` and can be modified
873        independently of all other :class:`.Session` objects.
874
875        .. versionadded:: 0.9.0
876
877        """
878        return {}
879
880    def begin(self, subtransactions=False, nested=False):
881        """Begin a transaction on this :class:`.Session`.
882
883        .. warning::
884
885            The :meth:`.Session.begin` method is part of a larger pattern
886            of use with the :class:`.Session` known as **autocommit mode**.
887            This is essentially a **legacy mode of use** and is
888            not necessary for new applications.    The :class:`.Session`
889            normally handles the work of "begin" transparently, which in
890            turn relies upon the Python DBAPI to transparently "begin"
891            transactions; there is **no need to explicitly begin transactions**
892            when using modern :class:`.Session` programming patterns.
893            In its default mode of ``autocommit=False``, the
894            :class:`.Session` does all of its work within
895            the context of a transaction, so as soon as you call
896            :meth:`.Session.commit`, the next transaction is implicitly
897            started when the next database operation is invoked.  See
898            :ref:`session_autocommit` for further background.
899
900        The method will raise an error if this :class:`.Session` is already
901        inside of a transaction, unless
902        :paramref:`~.Session.begin.subtransactions` or
903        :paramref:`~.Session.begin.nested` are specified.  A "subtransaction"
904        is essentially a code embedding pattern that does not affect the
905        transactional state of the database connection unless a rollback is
906        emitted, in which case the whole transaction is rolled back.  For
907        documentation on subtransactions, please see
908        :ref:`session_subtransactions`.
909
910        :param subtransactions: if True, indicates that this
911         :meth:`~.Session.begin` can create a "subtransaction".
912
913        :param nested: if True, begins a SAVEPOINT transaction and is
914         equivalent to calling :meth:`~.Session.begin_nested`. For
915         documentation on SAVEPOINT transactions, please see
916         :ref:`session_begin_nested`.
917
918        :return: the :class:`.SessionTransaction` object.  Note that
919         :class:`.SessionTransaction`
920         acts as a Python context manager, allowing :meth:`.Session.begin`
921         to be used in a "with" block.  See :ref:`session_autocommit` for
922         an example.
923
924        .. seealso::
925
926            :ref:`session_autocommit`
927
928            :meth:`.Session.begin_nested`
929
930
931        """
932        if self.transaction is not None:
933            if subtransactions or nested:
934                self.transaction = self.transaction._begin(nested=nested)
935            else:
936                raise sa_exc.InvalidRequestError(
937                    "A transaction is already begun.  Use "
938                    "subtransactions=True to allow subtransactions."
939                )
940        else:
941            self.transaction = SessionTransaction(self, nested=nested)
942        return self.transaction  # needed for __enter__/__exit__ hook
943
944    def begin_nested(self):
945        """Begin a "nested" transaction on this Session, e.g. SAVEPOINT.
946
947        The target database(s) and associated drivers must support SQL
948        SAVEPOINT for this method to function correctly.
949
950        For documentation on SAVEPOINT
951        transactions, please see :ref:`session_begin_nested`.
952
953        :return: the :class:`.SessionTransaction` object.  Note that
954         :class:`.SessionTransaction` acts as a context manager, allowing
955         :meth:`.Session.begin_nested` to be used in a "with" block.
956         See :ref:`session_begin_nested` for a usage example.
957
958        .. seealso::
959
960            :ref:`session_begin_nested`
961
962            :ref:`pysqlite_serializable` - special workarounds required
963            with the SQLite driver in order for SAVEPOINT to work
964            correctly.
965
966        """
967        return self.begin(nested=True)
968
969    def rollback(self):
970        """Rollback the current transaction in progress.
971
972        If no transaction is in progress, this method is a pass-through.
973
974        This method rolls back the current transaction or nested transaction
975        regardless of subtransactions being in effect.  All subtransactions up
976        to the first real transaction are closed.  Subtransactions occur when
977        :meth:`.begin` is called multiple times.
978
979        .. seealso::
980
981            :ref:`session_rollback`
982
983        """
984        if self.transaction is None:
985            pass
986        else:
987            self.transaction.rollback()
988
989    def commit(self):
990        """Flush pending changes and commit the current transaction.
991
992        If no transaction is in progress, this method raises an
993        :exc:`~sqlalchemy.exc.InvalidRequestError`.
994
995        By default, the :class:`.Session` also expires all database
996        loaded state on all ORM-managed attributes after transaction commit.
997        This so that subsequent operations load the most recent
998        data from the database.   This behavior can be disabled using
999        the ``expire_on_commit=False`` option to :class:`.sessionmaker` or
1000        the :class:`.Session` constructor.
1001
1002        If a subtransaction is in effect (which occurs when begin() is called
1003        multiple times), the subtransaction will be closed, and the next call
1004        to ``commit()`` will operate on the enclosing transaction.
1005
1006        When using the :class:`.Session` in its default mode of
1007        ``autocommit=False``, a new transaction will
1008        be begun immediately after the commit, but note that the newly begun
1009        transaction does *not* use any connection resources until the first
1010        SQL is actually emitted.
1011
1012        .. seealso::
1013
1014            :ref:`session_committing`
1015
1016        """
1017        if self.transaction is None:
1018            if not self.autocommit:
1019                self.begin()
1020            else:
1021                raise sa_exc.InvalidRequestError("No transaction is begun.")
1022
1023        self.transaction.commit()
1024
1025    def prepare(self):
1026        """Prepare the current transaction in progress for two phase commit.
1027
1028        If no transaction is in progress, this method raises an
1029        :exc:`~sqlalchemy.exc.InvalidRequestError`.
1030
1031        Only root transactions of two phase sessions can be prepared. If the
1032        current transaction is not such, an
1033        :exc:`~sqlalchemy.exc.InvalidRequestError` is raised.
1034
1035        """
1036        if self.transaction is None:
1037            if not self.autocommit:
1038                self.begin()
1039            else:
1040                raise sa_exc.InvalidRequestError("No transaction is begun.")
1041
1042        self.transaction.prepare()
1043
1044    def connection(
1045        self,
1046        mapper=None,
1047        clause=None,
1048        bind=None,
1049        close_with_result=False,
1050        execution_options=None,
1051        **kw
1052    ):
1053        r"""Return a :class:`.Connection` object corresponding to this
1054        :class:`.Session` object's transactional state.
1055
1056        If this :class:`.Session` is configured with ``autocommit=False``,
1057        either the :class:`.Connection` corresponding to the current
1058        transaction is returned, or if no transaction is in progress, a new
1059        one is begun and the :class:`.Connection` returned (note that no
1060        transactional state is established with the DBAPI until the first
1061        SQL statement is emitted).
1062
1063        Alternatively, if this :class:`.Session` is configured with
1064        ``autocommit=True``, an ad-hoc :class:`.Connection` is returned
1065        using :meth:`.Engine.contextual_connect` on the underlying
1066        :class:`.Engine`.
1067
1068        Ambiguity in multi-bind or unbound :class:`.Session` objects can be
1069        resolved through any of the optional keyword arguments.   This
1070        ultimately makes usage of the :meth:`.get_bind` method for resolution.
1071
1072        :param bind:
1073          Optional :class:`.Engine` to be used as the bind.  If
1074          this engine is already involved in an ongoing transaction,
1075          that connection will be used.  This argument takes precedence
1076          over ``mapper``, ``clause``.
1077
1078        :param mapper:
1079          Optional :func:`.mapper` mapped class, used to identify
1080          the appropriate bind.  This argument takes precedence over
1081          ``clause``.
1082
1083        :param clause:
1084            A :class:`.ClauseElement` (i.e. :func:`~.sql.expression.select`,
1085            :func:`~.sql.expression.text`,
1086            etc.) which will be used to locate a bind, if a bind
1087            cannot otherwise be identified.
1088
1089        :param close_with_result: Passed to :meth:`.Engine.connect`,
1090          indicating the :class:`.Connection` should be considered
1091          "single use", automatically closing when the first result set is
1092          closed.  This flag only has an effect if this :class:`.Session` is
1093          configured with ``autocommit=True`` and does not already have a
1094          transaction in progress.
1095
1096        :param execution_options: a dictionary of execution options that will
1097         be passed to :meth:`.Connection.execution_options`, **when the
1098         connection is first procured only**.   If the connection is already
1099         present within the :class:`.Session`, a warning is emitted and
1100         the arguments are ignored.
1101
1102         .. versionadded:: 0.9.9
1103
1104         .. seealso::
1105
1106            :ref:`session_transaction_isolation`
1107
1108        :param \**kw:
1109          Additional keyword arguments are sent to :meth:`get_bind()`,
1110          allowing additional arguments to be passed to custom
1111          implementations of :meth:`get_bind`.
1112
1113        """
1114        if bind is None:
1115            bind = self.get_bind(mapper, clause=clause, **kw)
1116
1117        return self._connection_for_bind(
1118            bind,
1119            close_with_result=close_with_result,
1120            execution_options=execution_options,
1121        )
1122
1123    def _connection_for_bind(self, engine, execution_options=None, **kw):
1124        if self.transaction is not None:
1125            return self.transaction._connection_for_bind(
1126                engine, execution_options
1127            )
1128        else:
1129            conn = engine.contextual_connect(**kw)
1130            if execution_options:
1131                conn = conn.execution_options(**execution_options)
1132            return conn
1133
1134    def execute(self, clause, params=None, mapper=None, bind=None, **kw):
1135        r"""Execute a SQL expression construct or string statement within
1136        the current transaction.
1137
1138        Returns a :class:`.ResultProxy` representing
1139        results of the statement execution, in the same manner as that of an
1140        :class:`.Engine` or
1141        :class:`.Connection`.
1142
1143        E.g.::
1144
1145            result = session.execute(
1146                        user_table.select().where(user_table.c.id == 5)
1147                    )
1148
1149        :meth:`~.Session.execute` accepts any executable clause construct,
1150        such as :func:`~.sql.expression.select`,
1151        :func:`~.sql.expression.insert`,
1152        :func:`~.sql.expression.update`,
1153        :func:`~.sql.expression.delete`, and
1154        :func:`~.sql.expression.text`.  Plain SQL strings can be passed
1155        as well, which in the case of :meth:`.Session.execute` only
1156        will be interpreted the same as if it were passed via a
1157        :func:`~.expression.text` construct.  That is, the following usage::
1158
1159            result = session.execute(
1160                        "SELECT * FROM user WHERE id=:param",
1161                        {"param":5}
1162                    )
1163
1164        is equivalent to::
1165
1166            from sqlalchemy import text
1167            result = session.execute(
1168                        text("SELECT * FROM user WHERE id=:param"),
1169                        {"param":5}
1170                    )
1171
1172        The second positional argument to :meth:`.Session.execute` is an
1173        optional parameter set.  Similar to that of
1174        :meth:`.Connection.execute`, whether this is passed as a single
1175        dictionary, or a list of dictionaries, determines whether the DBAPI
1176        cursor's ``execute()`` or ``executemany()`` is used to execute the
1177        statement.   An INSERT construct may be invoked for a single row::
1178
1179            result = session.execute(
1180                users.insert(), {"id": 7, "name": "somename"})
1181
1182        or for multiple rows::
1183
1184            result = session.execute(users.insert(), [
1185                                    {"id": 7, "name": "somename7"},
1186                                    {"id": 8, "name": "somename8"},
1187                                    {"id": 9, "name": "somename9"}
1188                                ])
1189
1190        The statement is executed within the current transactional context of
1191        this :class:`.Session`.   The :class:`.Connection` which is used
1192        to execute the statement can also be acquired directly by
1193        calling the :meth:`.Session.connection` method.  Both methods use
1194        a rule-based resolution scheme in order to determine the
1195        :class:`.Connection`, which in the average case is derived directly
1196        from the "bind" of the :class:`.Session` itself, and in other cases
1197        can be based on the :func:`.mapper`
1198        and :class:`.Table` objects passed to the method; see the
1199        documentation for :meth:`.Session.get_bind` for a full description of
1200        this scheme.
1201
1202        The :meth:`.Session.execute` method does *not* invoke autoflush.
1203
1204        The :class:`.ResultProxy` returned by the :meth:`.Session.execute`
1205        method is returned with the "close_with_result" flag set to true;
1206        the significance of this flag is that if this :class:`.Session` is
1207        autocommitting and does not have a transaction-dedicated
1208        :class:`.Connection` available, a temporary :class:`.Connection` is
1209        established for the statement execution, which is closed (meaning,
1210        returned to the connection pool) when the :class:`.ResultProxy` has
1211        consumed all available data. This applies *only* when the
1212        :class:`.Session` is configured with autocommit=True and no
1213        transaction has been started.
1214
1215        :param clause:
1216            An executable statement (i.e. an :class:`.Executable` expression
1217            such as :func:`.expression.select`) or string SQL statement
1218            to be executed.
1219
1220        :param params:
1221            Optional dictionary, or list of dictionaries, containing
1222            bound parameter values.   If a single dictionary, single-row
1223            execution occurs; if a list of dictionaries, an
1224            "executemany" will be invoked.  The keys in each dictionary
1225            must correspond to parameter names present in the statement.
1226
1227        :param mapper:
1228          Optional :func:`.mapper` or mapped class, used to identify
1229          the appropriate bind.  This argument takes precedence over
1230          ``clause`` when locating a bind.   See :meth:`.Session.get_bind`
1231          for more details.
1232
1233        :param bind:
1234          Optional :class:`.Engine` to be used as the bind.  If
1235          this engine is already involved in an ongoing transaction,
1236          that connection will be used.  This argument takes
1237          precedence over ``mapper`` and ``clause`` when locating
1238          a bind.
1239
1240        :param \**kw:
1241          Additional keyword arguments are sent to :meth:`.Session.get_bind()`
1242          to allow extensibility of "bind" schemes.
1243
1244        .. seealso::
1245
1246            :ref:`sqlexpression_toplevel` - Tutorial on using Core SQL
1247            constructs.
1248
1249            :ref:`connections_toplevel` - Further information on direct
1250            statement execution.
1251
1252            :meth:`.Connection.execute` - core level statement execution
1253            method, which is :meth:`.Session.execute` ultimately uses
1254            in order to execute the statement.
1255
1256        """
1257        clause = expression._literal_as_text(clause)
1258
1259        if bind is None:
1260            bind = self.get_bind(mapper, clause=clause, **kw)
1261
1262        return self._connection_for_bind(bind, close_with_result=True).execute(
1263            clause, params or {}
1264        )
1265
1266    def scalar(self, clause, params=None, mapper=None, bind=None, **kw):
1267        """Like :meth:`~.Session.execute` but return a scalar result."""
1268
1269        return self.execute(
1270            clause, params=params, mapper=mapper, bind=bind, **kw
1271        ).scalar()
1272
1273    def close(self):
1274        """Close this Session.
1275
1276        This clears all items and ends any transaction in progress.
1277
1278        If this session were created with ``autocommit=False``, a new
1279        transaction is immediately begun.  Note that this new transaction does
1280        not use any connection resources until they are first needed.
1281
1282        """
1283        self._close_impl(invalidate=False)
1284
1285    def invalidate(self):
1286        """Close this Session, using connection invalidation.
1287
1288        This is a variant of :meth:`.Session.close` that will additionally
1289        ensure that the :meth:`.Connection.invalidate` method will be called
1290        on all :class:`.Connection` objects.  This can be called when
1291        the database is known to be in a state where the connections are
1292        no longer safe to be used.
1293
1294        E.g.::
1295
1296            try:
1297                sess = Session()
1298                sess.add(User())
1299                sess.commit()
1300            except gevent.Timeout:
1301                sess.invalidate()
1302                raise
1303            except:
1304                sess.rollback()
1305                raise
1306
1307        This clears all items and ends any transaction in progress.
1308
1309        If this session were created with ``autocommit=False``, a new
1310        transaction is immediately begun.  Note that this new transaction does
1311        not use any connection resources until they are first needed.
1312
1313        .. versionadded:: 0.9.9
1314
1315        """
1316        self._close_impl(invalidate=True)
1317
1318    def _close_impl(self, invalidate):
1319        self.expunge_all()
1320        if self.transaction is not None:
1321            for transaction in self.transaction._iterate_self_and_parents():
1322                transaction.close(invalidate)
1323
1324    def expunge_all(self):
1325        """Remove all object instances from this ``Session``.
1326
1327        This is equivalent to calling ``expunge(obj)`` on all objects in this
1328        ``Session``.
1329
1330        """
1331
1332        all_states = self.identity_map.all_states() + list(self._new)
1333        self.identity_map = self._identity_cls()
1334        self._new = {}
1335        self._deleted = {}
1336
1337        statelib.InstanceState._detach_states(all_states, self)
1338
1339    def _add_bind(self, key, bind):
1340        try:
1341            insp = inspect(key)
1342        except sa_exc.NoInspectionAvailable:
1343            if not isinstance(key, type):
1344                raise sa_exc.ArgumentError(
1345                    "Not an acceptable bind target: %s" % key
1346                )
1347            else:
1348                self.__binds[key] = bind
1349        else:
1350            if insp.is_selectable:
1351                self.__binds[insp] = bind
1352            elif insp.is_mapper:
1353                self.__binds[insp.class_] = bind
1354                for selectable in insp._all_tables:
1355                    self.__binds[selectable] = bind
1356            else:
1357                raise sa_exc.ArgumentError(
1358                    "Not an acceptable bind target: %s" % key
1359                )
1360
1361    def bind_mapper(self, mapper, bind):
1362        """Associate a :class:`.Mapper` or arbitrary Python class with a
1363        "bind", e.g. an :class:`.Engine` or :class:`.Connection`.
1364
1365        The given entity is added to a lookup used by the
1366        :meth:`.Session.get_bind` method.
1367
1368        :param mapper: a :class:`.Mapper` object, or an instance of a mapped
1369         class, or any Python class that is the base of a set of mapped
1370         classes.
1371
1372        :param bind: an :class:`.Engine` or :class:`.Connection` object.
1373
1374        .. seealso::
1375
1376            :ref:`session_partitioning`
1377
1378            :paramref:`.Session.binds`
1379
1380            :meth:`.Session.bind_table`
1381
1382
1383        """
1384        self._add_bind(mapper, bind)
1385
1386    def bind_table(self, table, bind):
1387        """Associate a :class:`.Table` with a "bind", e.g. an :class:`.Engine`
1388        or :class:`.Connection`.
1389
1390        The given :class:`.Table` is added to a lookup used by the
1391        :meth:`.Session.get_bind` method.
1392
1393        :param table: a :class:`.Table` object, which is typically the target
1394         of an ORM mapping, or is present within a selectable that is
1395         mapped.
1396
1397        :param bind: an :class:`.Engine` or :class:`.Connection` object.
1398
1399        .. seealso::
1400
1401            :ref:`session_partitioning`
1402
1403            :paramref:`.Session.binds`
1404
1405            :meth:`.Session.bind_mapper`
1406
1407
1408        """
1409        self._add_bind(table, bind)
1410
1411    def get_bind(self, mapper=None, clause=None):
1412        """Return a "bind" to which this :class:`.Session` is bound.
1413
1414        The "bind" is usually an instance of :class:`.Engine`,
1415        except in the case where the :class:`.Session` has been
1416        explicitly bound directly to a :class:`.Connection`.
1417
1418        For a multiply-bound or unbound :class:`.Session`, the
1419        ``mapper`` or ``clause`` arguments are used to determine the
1420        appropriate bind to return.
1421
1422        Note that the "mapper" argument is usually present
1423        when :meth:`.Session.get_bind` is called via an ORM
1424        operation such as a :meth:`.Session.query`, each
1425        individual INSERT/UPDATE/DELETE operation within a
1426        :meth:`.Session.flush`, call, etc.
1427
1428        The order of resolution is:
1429
1430        1. if mapper given and session.binds is present,
1431           locate a bind based first on the mapper in use, then
1432           on the mapped class in use, then on any base classes that are
1433           present in the ``__mro__`` of the mapped class, from more specific
1434           superclasses to more general.
1435        2. if clause given and session.binds is present,
1436           locate a bind based on :class:`.Table` objects
1437           found in the given clause present in session.binds.
1438        3. if session.bind is present, return that.
1439        4. if clause given, attempt to return a bind
1440           linked to the :class:`.MetaData` ultimately
1441           associated with the clause.
1442        5. if mapper given, attempt to return a bind
1443           linked to the :class:`.MetaData` ultimately
1444           associated with the :class:`.Table` or other
1445           selectable to which the mapper is mapped.
1446        6. No bind can be found, :exc:`~sqlalchemy.exc.UnboundExecutionError`
1447           is raised.
1448
1449        Note that the :meth:`.Session.get_bind` method can be overridden on
1450        a user-defined subclass of :class:`.Session` to provide any kind
1451        of bind resolution scheme.  See the example at
1452        :ref:`session_custom_partitioning`.
1453
1454        :param mapper:
1455          Optional :func:`.mapper` mapped class or instance of
1456          :class:`.Mapper`.   The bind can be derived from a :class:`.Mapper`
1457          first by consulting the "binds" map associated with this
1458          :class:`.Session`, and secondly by consulting the :class:`.MetaData`
1459          associated with the :class:`.Table` to which the :class:`.Mapper`
1460          is mapped for a bind.
1461
1462        :param clause:
1463            A :class:`.ClauseElement` (i.e. :func:`~.sql.expression.select`,
1464            :func:`~.sql.expression.text`,
1465            etc.).  If the ``mapper`` argument is not present or could not
1466            produce a bind, the given expression construct will be searched
1467            for a bound element, typically a :class:`.Table` associated with
1468            bound :class:`.MetaData`.
1469
1470        .. seealso::
1471
1472             :ref:`session_partitioning`
1473
1474             :paramref:`.Session.binds`
1475
1476             :meth:`.Session.bind_mapper`
1477
1478             :meth:`.Session.bind_table`
1479
1480        """
1481
1482        if mapper is clause is None:
1483            if self.bind:
1484                return self.bind
1485            else:
1486                raise sa_exc.UnboundExecutionError(
1487                    "This session is not bound to a single Engine or "
1488                    "Connection, and no context was provided to locate "
1489                    "a binding."
1490                )
1491
1492        if mapper is not None:
1493            try:
1494                mapper = inspect(mapper)
1495            except sa_exc.NoInspectionAvailable:
1496                if isinstance(mapper, type):
1497                    raise exc.UnmappedClassError(mapper)
1498                else:
1499                    raise
1500
1501        if self.__binds:
1502            if mapper:
1503                for cls in mapper.class_.__mro__:
1504                    if cls in self.__binds:
1505                        return self.__binds[cls]
1506                if clause is None:
1507                    clause = mapper.mapped_table
1508
1509            if clause is not None:
1510                for t in sql_util.find_tables(clause, include_crud=True):
1511                    if t in self.__binds:
1512                        return self.__binds[t]
1513
1514        if self.bind:
1515            return self.bind
1516
1517        if isinstance(clause, sql.expression.ClauseElement) and clause.bind:
1518            return clause.bind
1519
1520        if mapper and mapper.mapped_table.bind:
1521            return mapper.mapped_table.bind
1522
1523        context = []
1524        if mapper is not None:
1525            context.append("mapper %s" % mapper)
1526        if clause is not None:
1527            context.append("SQL expression")
1528
1529        raise sa_exc.UnboundExecutionError(
1530            "Could not locate a bind configured on %s or this Session"
1531            % (", ".join(context))
1532        )
1533
1534    def query(self, *entities, **kwargs):
1535        """Return a new :class:`.Query` object corresponding to this
1536        :class:`.Session`."""
1537
1538        return self._query_cls(entities, self, **kwargs)
1539
1540    @property
1541    @util.contextmanager
1542    def no_autoflush(self):
1543        """Return a context manager that disables autoflush.
1544
1545        e.g.::
1546
1547            with session.no_autoflush:
1548
1549                some_object = SomeClass()
1550                session.add(some_object)
1551                # won't autoflush
1552                some_object.related_thing = session.query(SomeRelated).first()
1553
1554        Operations that proceed within the ``with:`` block
1555        will not be subject to flushes occurring upon query
1556        access.  This is useful when initializing a series
1557        of objects which involve existing database queries,
1558        where the uncompleted object should not yet be flushed.
1559
1560        """
1561        autoflush = self.autoflush
1562        self.autoflush = False
1563        try:
1564            yield self
1565        finally:
1566            self.autoflush = autoflush
1567
1568    def _autoflush(self):
1569        if self.autoflush and not self._flushing:
1570            try:
1571                self.flush()
1572            except sa_exc.StatementError as e:
1573                # note we are reraising StatementError as opposed to
1574                # raising FlushError with "chaining" to remain compatible
1575                # with code that catches StatementError, IntegrityError,
1576                # etc.
1577                e.add_detail(
1578                    "raised as a result of Query-invoked autoflush; "
1579                    "consider using a session.no_autoflush block if this "
1580                    "flush is occurring prematurely"
1581                )
1582                util.raise_from_cause(e)
1583
1584    def refresh(
1585        self,
1586        instance,
1587        attribute_names=None,
1588        with_for_update=None,
1589        lockmode=None,
1590    ):
1591        """Expire and refresh the attributes on the given instance.
1592
1593        A query will be issued to the database and all attributes will be
1594        refreshed with their current database value.
1595
1596        Lazy-loaded relational attributes will remain lazily loaded, so that
1597        the instance-wide refresh operation will be followed immediately by
1598        the lazy load of that attribute.
1599
1600        Eagerly-loaded relational attributes will eagerly load within the
1601        single refresh operation.
1602
1603        Note that a highly isolated transaction will return the same values as
1604        were previously read in that same transaction, regardless of changes
1605        in database state outside of that transaction - usage of
1606        :meth:`~Session.refresh` usually only makes sense if non-ORM SQL
1607        statement were emitted in the ongoing transaction, or if autocommit
1608        mode is turned on.
1609
1610        :param attribute_names: optional.  An iterable collection of
1611          string attribute names indicating a subset of attributes to
1612          be refreshed.
1613
1614        :param with_for_update: optional boolean ``True`` indicating FOR UPDATE
1615          should be used, or may be a dictionary containing flags to
1616          indicate a more specific set of FOR UPDATE flags for the SELECT;
1617          flags should match the parameters of :meth:`.Query.with_for_update`.
1618          Supersedes the :paramref:`.Session.refresh.lockmode` parameter.
1619
1620          .. versionadded:: 1.2
1621
1622        :param lockmode: Passed to the :class:`~sqlalchemy.orm.query.Query`
1623          as used by :meth:`~sqlalchemy.orm.query.Query.with_lockmode`.
1624          Superseded by :paramref:`.Session.refresh.with_for_update`.
1625
1626        .. seealso::
1627
1628            :ref:`session_expire` - introductory material
1629
1630            :meth:`.Session.expire`
1631
1632            :meth:`.Session.expire_all`
1633
1634        """
1635        try:
1636            state = attributes.instance_state(instance)
1637        except exc.NO_STATE:
1638            raise exc.UnmappedInstanceError(instance)
1639
1640        self._expire_state(state, attribute_names)
1641
1642        if with_for_update == {}:
1643            raise sa_exc.ArgumentError(
1644                "with_for_update should be the boolean value "
1645                "True, or a dictionary with options.  "
1646                "A blank dictionary is ambiguous."
1647            )
1648
1649        if lockmode:
1650            with_for_update = query.LockmodeArg.parse_legacy_query(lockmode)
1651        elif with_for_update is not None:
1652            if with_for_update is True:
1653                with_for_update = query.LockmodeArg()
1654            elif with_for_update:
1655                with_for_update = query.LockmodeArg(**with_for_update)
1656            else:
1657                with_for_update = None
1658
1659        if (
1660            loading.load_on_ident(
1661                self.query(object_mapper(instance)),
1662                state.key,
1663                refresh_state=state,
1664                with_for_update=with_for_update,
1665                only_load_props=attribute_names,
1666            )
1667            is None
1668        ):
1669            raise sa_exc.InvalidRequestError(
1670                "Could not refresh instance '%s'" % instance_str(instance)
1671            )
1672
1673    def expire_all(self):
1674        """Expires all persistent instances within this Session.
1675
1676        When any attributes on a persistent instance is next accessed,
1677        a query will be issued using the
1678        :class:`.Session` object's current transactional context in order to
1679        load all expired attributes for the given instance.   Note that
1680        a highly isolated transaction will return the same values as were
1681        previously read in that same transaction, regardless of changes
1682        in database state outside of that transaction.
1683
1684        To expire individual objects and individual attributes
1685        on those objects, use :meth:`Session.expire`.
1686
1687        The :class:`.Session` object's default behavior is to
1688        expire all state whenever the :meth:`Session.rollback`
1689        or :meth:`Session.commit` methods are called, so that new
1690        state can be loaded for the new transaction.   For this reason,
1691        calling :meth:`Session.expire_all` should not be needed when
1692        autocommit is ``False``, assuming the transaction is isolated.
1693
1694        .. seealso::
1695
1696            :ref:`session_expire` - introductory material
1697
1698            :meth:`.Session.expire`
1699
1700            :meth:`.Session.refresh`
1701
1702        """
1703        for state in self.identity_map.all_states():
1704            state._expire(state.dict, self.identity_map._modified)
1705
1706    def expire(self, instance, attribute_names=None):
1707        """Expire the attributes on an instance.
1708
1709        Marks the attributes of an instance as out of date. When an expired
1710        attribute is next accessed, a query will be issued to the
1711        :class:`.Session` object's current transactional context in order to
1712        load all expired attributes for the given instance.   Note that
1713        a highly isolated transaction will return the same values as were
1714        previously read in that same transaction, regardless of changes
1715        in database state outside of that transaction.
1716
1717        To expire all objects in the :class:`.Session` simultaneously,
1718        use :meth:`Session.expire_all`.
1719
1720        The :class:`.Session` object's default behavior is to
1721        expire all state whenever the :meth:`Session.rollback`
1722        or :meth:`Session.commit` methods are called, so that new
1723        state can be loaded for the new transaction.   For this reason,
1724        calling :meth:`Session.expire` only makes sense for the specific
1725        case that a non-ORM SQL statement was emitted in the current
1726        transaction.
1727
1728        :param instance: The instance to be refreshed.
1729        :param attribute_names: optional list of string attribute names
1730          indicating a subset of attributes to be expired.
1731
1732        .. seealso::
1733
1734            :ref:`session_expire` - introductory material
1735
1736            :meth:`.Session.expire`
1737
1738            :meth:`.Session.refresh`
1739
1740        """
1741        try:
1742            state = attributes.instance_state(instance)
1743        except exc.NO_STATE:
1744            raise exc.UnmappedInstanceError(instance)
1745        self._expire_state(state, attribute_names)
1746
1747    def _expire_state(self, state, attribute_names):
1748        self._validate_persistent(state)
1749        if attribute_names:
1750            state._expire_attributes(state.dict, attribute_names)
1751        else:
1752            # pre-fetch the full cascade since the expire is going to
1753            # remove associations
1754            cascaded = list(
1755                state.manager.mapper.cascade_iterator("refresh-expire", state)
1756            )
1757            self._conditional_expire(state)
1758            for o, m, st_, dct_ in cascaded:
1759                self._conditional_expire(st_)
1760
1761    def _conditional_expire(self, state):
1762        """Expire a state if persistent, else expunge if pending"""
1763
1764        if state.key:
1765            state._expire(state.dict, self.identity_map._modified)
1766        elif state in self._new:
1767            self._new.pop(state)
1768            state._detach(self)
1769
1770    @util.deprecated(
1771        "0.7",
1772        "The :meth:`.Session.prune` method is deprecated along with "
1773        ":paramref:`.Session.weak_identity_map`.  This method will be "
1774        "removed in a future release.",
1775    )
1776    def prune(self):
1777        """Remove unreferenced instances cached in the identity map.
1778
1779        Note that this method is only meaningful if "weak_identity_map" is set
1780        to False.  The default weak identity map is self-pruning.
1781
1782        Removes any object in this Session's identity map that is not
1783        referenced in user code, modified, new or scheduled for deletion.
1784        Returns the number of objects pruned.
1785
1786        """
1787        return self.identity_map.prune()
1788
1789    def expunge(self, instance):
1790        """Remove the `instance` from this ``Session``.
1791
1792        This will free all internal references to the instance.  Cascading
1793        will be applied according to the *expunge* cascade rule.
1794
1795        """
1796        try:
1797            state = attributes.instance_state(instance)
1798        except exc.NO_STATE:
1799            raise exc.UnmappedInstanceError(instance)
1800        if state.session_id is not self.hash_key:
1801            raise sa_exc.InvalidRequestError(
1802                "Instance %s is not present in this Session" % state_str(state)
1803            )
1804
1805        cascaded = list(
1806            state.manager.mapper.cascade_iterator("expunge", state)
1807        )
1808        self._expunge_states([state] + [st_ for o, m, st_, dct_ in cascaded])
1809
1810    def _expunge_states(self, states, to_transient=False):
1811        for state in states:
1812            if state in self._new:
1813                self._new.pop(state)
1814            elif self.identity_map.contains_state(state):
1815                self.identity_map.safe_discard(state)
1816                self._deleted.pop(state, None)
1817            elif self.transaction:
1818                # state is "detached" from being deleted, but still present
1819                # in the transaction snapshot
1820                self.transaction._deleted.pop(state, None)
1821        statelib.InstanceState._detach_states(
1822            states, self, to_transient=to_transient
1823        )
1824
1825    def _register_persistent(self, states):
1826        """Register all persistent objects from a flush.
1827
1828        This is used both for pending objects moving to the persistent
1829        state as well as already persistent objects.
1830
1831        """
1832
1833        pending_to_persistent = self.dispatch.pending_to_persistent or None
1834        for state in states:
1835            mapper = _state_mapper(state)
1836
1837            # prevent against last minute dereferences of the object
1838            obj = state.obj()
1839            if obj is not None:
1840
1841                instance_key = mapper._identity_key_from_state(state)
1842
1843                if (
1844                    _none_set.intersection(instance_key[1])
1845                    and not mapper.allow_partial_pks
1846                    or _none_set.issuperset(instance_key[1])
1847                ):
1848                    raise exc.FlushError(
1849                        "Instance %s has a NULL identity key.  If this is an "
1850                        "auto-generated value, check that the database table "
1851                        "allows generation of new primary key values, and "
1852                        "that the mapped Column object is configured to "
1853                        "expect these generated values.  Ensure also that "
1854                        "this flush() is not occurring at an inappropriate "
1855                        "time, such as within a load() event."
1856                        % state_str(state)
1857                    )
1858
1859                if state.key is None:
1860                    state.key = instance_key
1861                elif state.key != instance_key:
1862                    # primary key switch. use safe_discard() in case another
1863                    # state has already replaced this one in the identity
1864                    # map (see test/orm/test_naturalpks.py ReversePKsTest)
1865                    self.identity_map.safe_discard(state)
1866                    if state in self.transaction._key_switches:
1867                        orig_key = self.transaction._key_switches[state][0]
1868                    else:
1869                        orig_key = state.key
1870                    self.transaction._key_switches[state] = (
1871                        orig_key,
1872                        instance_key,
1873                    )
1874                    state.key = instance_key
1875
1876                # there can be an existing state in the identity map
1877                # that is replaced when the primary keys of two instances
1878                # are swapped; see test/orm/test_naturalpks.py -> test_reverse
1879                self.identity_map.replace(state)
1880                state._orphaned_outside_of_session = False
1881
1882        statelib.InstanceState._commit_all_states(
1883            ((state, state.dict) for state in states), self.identity_map
1884        )
1885
1886        self._register_altered(states)
1887
1888        if pending_to_persistent is not None:
1889            for state in states.intersection(self._new):
1890                pending_to_persistent(self, state.obj())
1891
1892        # remove from new last, might be the last strong ref
1893        for state in set(states).intersection(self._new):
1894            self._new.pop(state)
1895
1896    def _register_altered(self, states):
1897        if self._enable_transaction_accounting and self.transaction:
1898            for state in states:
1899                if state in self._new:
1900                    self.transaction._new[state] = True
1901                else:
1902                    self.transaction._dirty[state] = True
1903
1904    def _remove_newly_deleted(self, states):
1905        persistent_to_deleted = self.dispatch.persistent_to_deleted or None
1906        for state in states:
1907            if self._enable_transaction_accounting and self.transaction:
1908                self.transaction._deleted[state] = True
1909
1910            if persistent_to_deleted is not None:
1911                # get a strong reference before we pop out of
1912                # self._deleted
1913                obj = state.obj()
1914
1915            self.identity_map.safe_discard(state)
1916            self._deleted.pop(state, None)
1917            state._deleted = True
1918            # can't call state._detach() here, because this state
1919            # is still in the transaction snapshot and needs to be
1920            # tracked as part of that
1921            if persistent_to_deleted is not None:
1922                persistent_to_deleted(self, obj)
1923
1924    def add(self, instance, _warn=True):
1925        """Place an object in the ``Session``.
1926
1927        Its state will be persisted to the database on the next flush
1928        operation.
1929
1930        Repeated calls to ``add()`` will be ignored. The opposite of ``add()``
1931        is ``expunge()``.
1932
1933        """
1934        if _warn and self._warn_on_events:
1935            self._flush_warning("Session.add()")
1936
1937        try:
1938            state = attributes.instance_state(instance)
1939        except exc.NO_STATE:
1940            raise exc.UnmappedInstanceError(instance)
1941
1942        self._save_or_update_state(state)
1943
1944    def add_all(self, instances):
1945        """Add the given collection of instances to this ``Session``."""
1946
1947        if self._warn_on_events:
1948            self._flush_warning("Session.add_all()")
1949
1950        for instance in instances:
1951            self.add(instance, _warn=False)
1952
1953    def _save_or_update_state(self, state):
1954        state._orphaned_outside_of_session = False
1955        self._save_or_update_impl(state)
1956
1957        mapper = _state_mapper(state)
1958        for o, m, st_, dct_ in mapper.cascade_iterator(
1959            "save-update", state, halt_on=self._contains_state
1960        ):
1961            self._save_or_update_impl(st_)
1962
1963    def delete(self, instance):
1964        """Mark an instance as deleted.
1965
1966        The database delete operation occurs upon ``flush()``.
1967
1968        """
1969        if self._warn_on_events:
1970            self._flush_warning("Session.delete()")
1971
1972        try:
1973            state = attributes.instance_state(instance)
1974        except exc.NO_STATE:
1975            raise exc.UnmappedInstanceError(instance)
1976
1977        self._delete_impl(state, instance, head=True)
1978
1979    def _delete_impl(self, state, obj, head):
1980
1981        if state.key is None:
1982            if head:
1983                raise sa_exc.InvalidRequestError(
1984                    "Instance '%s' is not persisted" % state_str(state)
1985                )
1986            else:
1987                return
1988
1989        to_attach = self._before_attach(state, obj)
1990
1991        if state in self._deleted:
1992            return
1993
1994        self.identity_map.add(state)
1995
1996        if to_attach:
1997            self._after_attach(state, obj)
1998
1999        if head:
2000            # grab the cascades before adding the item to the deleted list
2001            # so that autoflush does not delete the item
2002            # the strong reference to the instance itself is significant here
2003            cascade_states = list(
2004                state.manager.mapper.cascade_iterator("delete", state)
2005            )
2006
2007        self._deleted[state] = obj
2008
2009        if head:
2010            for o, m, st_, dct_ in cascade_states:
2011                self._delete_impl(st_, o, False)
2012
2013    def merge(self, instance, load=True):
2014        """Copy the state of a given instance into a corresponding instance
2015        within this :class:`.Session`.
2016
2017        :meth:`.Session.merge` examines the primary key attributes of the
2018        source instance, and attempts to reconcile it with an instance of the
2019        same primary key in the session.   If not found locally, it attempts
2020        to load the object from the database based on primary key, and if
2021        none can be located, creates a new instance.  The state of each
2022        attribute on the source instance is then copied to the target
2023        instance.  The resulting target instance is then returned by the
2024        method; the original source instance is left unmodified, and
2025        un-associated with the :class:`.Session` if not already.
2026
2027        This operation cascades to associated instances if the association is
2028        mapped with ``cascade="merge"``.
2029
2030        See :ref:`unitofwork_merging` for a detailed discussion of merging.
2031
2032        .. versionchanged:: 1.1 - :meth:`.Session.merge` will now reconcile
2033           pending objects with overlapping primary keys in the same way
2034           as persistent.  See :ref:`change_3601` for discussion.
2035
2036        :param instance: Instance to be merged.
2037        :param load: Boolean, when False, :meth:`.merge` switches into
2038         a "high performance" mode which causes it to forego emitting history
2039         events as well as all database access.  This flag is used for
2040         cases such as transferring graphs of objects into a :class:`.Session`
2041         from a second level cache, or to transfer just-loaded objects
2042         into the :class:`.Session` owned by a worker thread or process
2043         without re-querying the database.
2044
2045         The ``load=False`` use case adds the caveat that the given
2046         object has to be in a "clean" state, that is, has no pending changes
2047         to be flushed - even if the incoming object is detached from any
2048         :class:`.Session`.   This is so that when
2049         the merge operation populates local attributes and
2050         cascades to related objects and
2051         collections, the values can be "stamped" onto the
2052         target object as is, without generating any history or attribute
2053         events, and without the need to reconcile the incoming data with
2054         any existing related objects or collections that might not
2055         be loaded.  The resulting objects from ``load=False`` are always
2056         produced as "clean", so it is only appropriate that the given objects
2057         should be "clean" as well, else this suggests a mis-use of the
2058         method.
2059
2060
2061        .. seealso::
2062
2063            :func:`.make_transient_to_detached` - provides for an alternative
2064            means of "merging" a single object into the :class:`.Session`
2065
2066        """
2067
2068        if self._warn_on_events:
2069            self._flush_warning("Session.merge()")
2070
2071        _recursive = {}
2072        _resolve_conflict_map = {}
2073
2074        if load:
2075            # flush current contents if we expect to load data
2076            self._autoflush()
2077
2078        object_mapper(instance)  # verify mapped
2079        autoflush = self.autoflush
2080        try:
2081            self.autoflush = False
2082            return self._merge(
2083                attributes.instance_state(instance),
2084                attributes.instance_dict(instance),
2085                load=load,
2086                _recursive=_recursive,
2087                _resolve_conflict_map=_resolve_conflict_map,
2088            )
2089        finally:
2090            self.autoflush = autoflush
2091
2092    def _merge(
2093        self,
2094        state,
2095        state_dict,
2096        load=True,
2097        _recursive=None,
2098        _resolve_conflict_map=None,
2099    ):
2100        mapper = _state_mapper(state)
2101        if state in _recursive:
2102            return _recursive[state]
2103
2104        new_instance = False
2105        key = state.key
2106
2107        if key is None:
2108            if not load:
2109                raise sa_exc.InvalidRequestError(
2110                    "merge() with load=False option does not support "
2111                    "objects transient (i.e. unpersisted) objects.  flush() "
2112                    "all changes on mapped instances before merging with "
2113                    "load=False."
2114                )
2115            key = mapper._identity_key_from_state(state)
2116            key_is_persistent = attributes.NEVER_SET not in key[1] and (
2117                not _none_set.intersection(key[1])
2118                or (
2119                    mapper.allow_partial_pks
2120                    and not _none_set.issuperset(key[1])
2121                )
2122            )
2123        else:
2124            key_is_persistent = True
2125
2126        if key in self.identity_map:
2127            try:
2128                merged = self.identity_map[key]
2129            except KeyError:
2130                # object was GC'ed right as we checked for it
2131                merged = None
2132        else:
2133            merged = None
2134
2135        if merged is None:
2136            if key_is_persistent and key in _resolve_conflict_map:
2137                merged = _resolve_conflict_map[key]
2138
2139            elif not load:
2140                if state.modified:
2141                    raise sa_exc.InvalidRequestError(
2142                        "merge() with load=False option does not support "
2143                        "objects marked as 'dirty'.  flush() all changes on "
2144                        "mapped instances before merging with load=False."
2145                    )
2146                merged = mapper.class_manager.new_instance()
2147                merged_state = attributes.instance_state(merged)
2148                merged_state.key = key
2149                self._update_impl(merged_state)
2150                new_instance = True
2151
2152            elif key_is_persistent:
2153                merged = self.query(mapper.class_).get(key[1])
2154
2155        if merged is None:
2156            merged = mapper.class_manager.new_instance()
2157            merged_state = attributes.instance_state(merged)
2158            merged_dict = attributes.instance_dict(merged)
2159            new_instance = True
2160            self._save_or_update_state(merged_state)
2161        else:
2162            merged_state = attributes.instance_state(merged)
2163            merged_dict = attributes.instance_dict(merged)
2164
2165        _recursive[state] = merged
2166        _resolve_conflict_map[key] = merged
2167
2168        # check that we didn't just pull the exact same
2169        # state out.
2170        if state is not merged_state:
2171            # version check if applicable
2172            if mapper.version_id_col is not None:
2173                existing_version = mapper._get_state_attr_by_column(
2174                    state,
2175                    state_dict,
2176                    mapper.version_id_col,
2177                    passive=attributes.PASSIVE_NO_INITIALIZE,
2178                )
2179
2180                merged_version = mapper._get_state_attr_by_column(
2181                    merged_state,
2182                    merged_dict,
2183                    mapper.version_id_col,
2184                    passive=attributes.PASSIVE_NO_INITIALIZE,
2185                )
2186
2187                if (
2188                    existing_version is not attributes.PASSIVE_NO_RESULT
2189                    and merged_version is not attributes.PASSIVE_NO_RESULT
2190                    and existing_version != merged_version
2191                ):
2192                    raise exc.StaleDataError(
2193                        "Version id '%s' on merged state %s "
2194                        "does not match existing version '%s'. "
2195                        "Leave the version attribute unset when "
2196                        "merging to update the most recent version."
2197                        % (
2198                            existing_version,
2199                            state_str(merged_state),
2200                            merged_version,
2201                        )
2202                    )
2203
2204            merged_state.load_path = state.load_path
2205            merged_state.load_options = state.load_options
2206
2207            # since we are copying load_options, we need to copy
2208            # the callables_ that would have been generated by those
2209            # load_options.
2210            # assumes that the callables we put in state.callables_
2211            # are not instance-specific (which they should not be)
2212            merged_state._copy_callables(state)
2213
2214            for prop in mapper.iterate_properties:
2215                prop.merge(
2216                    self,
2217                    state,
2218                    state_dict,
2219                    merged_state,
2220                    merged_dict,
2221                    load,
2222                    _recursive,
2223                    _resolve_conflict_map,
2224                )
2225
2226        if not load:
2227            # remove any history
2228            merged_state._commit_all(merged_dict, self.identity_map)
2229
2230        if new_instance:
2231            merged_state.manager.dispatch.load(merged_state, None)
2232        return merged
2233
2234    def _validate_persistent(self, state):
2235        if not self.identity_map.contains_state(state):
2236            raise sa_exc.InvalidRequestError(
2237                "Instance '%s' is not persistent within this Session"
2238                % state_str(state)
2239            )
2240
2241    def _save_impl(self, state):
2242        if state.key is not None:
2243            raise sa_exc.InvalidRequestError(
2244                "Object '%s' already has an identity - "
2245                "it can't be registered as pending" % state_str(state)
2246            )
2247
2248        obj = state.obj()
2249        to_attach = self._before_attach(state, obj)
2250        if state not in self._new:
2251            self._new[state] = obj
2252            state.insert_order = len(self._new)
2253        if to_attach:
2254            self._after_attach(state, obj)
2255
2256    def _update_impl(self, state, revert_deletion=False):
2257        if state.key is None:
2258            raise sa_exc.InvalidRequestError(
2259                "Instance '%s' is not persisted" % state_str(state)
2260            )
2261
2262        if state._deleted:
2263            if revert_deletion:
2264                if not state._attached:
2265                    return
2266                del state._deleted
2267            else:
2268                raise sa_exc.InvalidRequestError(
2269                    "Instance '%s' has been deleted.  "
2270                    "Use the make_transient() "
2271                    "function to send this object back "
2272                    "to the transient state." % state_str(state)
2273                )
2274
2275        obj = state.obj()
2276
2277        # check for late gc
2278        if obj is None:
2279            return
2280
2281        to_attach = self._before_attach(state, obj)
2282
2283        self._deleted.pop(state, None)
2284        if revert_deletion:
2285            self.identity_map.replace(state)
2286        else:
2287            self.identity_map.add(state)
2288
2289        if to_attach:
2290            self._after_attach(state, obj)
2291        elif revert_deletion:
2292            self.dispatch.deleted_to_persistent(self, obj)
2293
2294    def _save_or_update_impl(self, state):
2295        if state.key is None:
2296            self._save_impl(state)
2297        else:
2298            self._update_impl(state)
2299
2300    def enable_relationship_loading(self, obj):
2301        """Associate an object with this :class:`.Session` for related
2302        object loading.
2303
2304        .. warning::
2305
2306            :meth:`.enable_relationship_loading` exists to serve special
2307            use cases and is not recommended for general use.
2308
2309        Accesses of attributes mapped with :func:`.relationship`
2310        will attempt to load a value from the database using this
2311        :class:`.Session` as the source of connectivity.  The values
2312        will be loaded based on foreign key and primary key values
2313        present on this object - if not present, then those relationships
2314        will be unavailable.
2315
2316        The object will be attached to this session, but will
2317        **not** participate in any persistence operations; its state
2318        for almost all purposes will remain either "transient" or
2319        "detached", except for the case of relationship loading.
2320
2321        Also note that backrefs will often not work as expected.
2322        Altering a relationship-bound attribute on the target object
2323        may not fire off a backref event, if the effective value
2324        is what was already loaded from a foreign-key-holding value.
2325
2326        The :meth:`.Session.enable_relationship_loading` method is
2327        similar to the ``load_on_pending`` flag on :func:`.relationship`.
2328        Unlike that flag, :meth:`.Session.enable_relationship_loading` allows
2329        an object to remain transient while still being able to load
2330        related items.
2331
2332        To make a transient object associated with a :class:`.Session`
2333        via :meth:`.Session.enable_relationship_loading` pending, add
2334        it to the :class:`.Session` using :meth:`.Session.add` normally.
2335        If the object instead represents an existing identity in the database,
2336        it should be merged using :meth:`.Session.merge`.
2337
2338        :meth:`.Session.enable_relationship_loading` does not improve
2339        behavior when the ORM is used normally - object references should be
2340        constructed at the object level, not at the foreign key level, so
2341        that they are present in an ordinary way before flush()
2342        proceeds.  This method is not intended for general use.
2343
2344        .. seealso::
2345
2346            ``load_on_pending`` at :func:`.relationship` - this flag
2347            allows per-relationship loading of many-to-ones on items that
2348            are pending.
2349
2350            :func:`.make_transient_to_detached` - allows for an object to
2351            be added to a :class:`.Session` without SQL emitted, which then
2352            will unexpire attributes on access.
2353
2354        """
2355        state = attributes.instance_state(obj)
2356        to_attach = self._before_attach(state, obj)
2357        state._load_pending = True
2358        if to_attach:
2359            self._after_attach(state, obj)
2360
2361    def _before_attach(self, state, obj):
2362        if state.session_id == self.hash_key:
2363            return False
2364
2365        if state.session_id and state.session_id in _sessions:
2366            raise sa_exc.InvalidRequestError(
2367                "Object '%s' is already attached to session '%s' "
2368                "(this is '%s')"
2369                % (state_str(state), state.session_id, self.hash_key)
2370            )
2371
2372        self.dispatch.before_attach(self, obj)
2373
2374        return True
2375
2376    def _after_attach(self, state, obj):
2377        state.session_id = self.hash_key
2378        if state.modified and state._strong_obj is None:
2379            state._strong_obj = obj
2380        self.dispatch.after_attach(self, obj)
2381
2382        if state.key:
2383            self.dispatch.detached_to_persistent(self, obj)
2384        else:
2385            self.dispatch.transient_to_pending(self, obj)
2386
2387    def __contains__(self, instance):
2388        """Return True if the instance is associated with this session.
2389
2390        The instance may be pending or persistent within the Session for a
2391        result of True.
2392
2393        """
2394        try:
2395            state = attributes.instance_state(instance)
2396        except exc.NO_STATE:
2397            raise exc.UnmappedInstanceError(instance)
2398        return self._contains_state(state)
2399
2400    def __iter__(self):
2401        """Iterate over all pending or persistent instances within this
2402        Session.
2403
2404        """
2405        return iter(
2406            list(self._new.values()) + list(self.identity_map.values())
2407        )
2408
2409    def _contains_state(self, state):
2410        return state in self._new or self.identity_map.contains_state(state)
2411
2412    def flush(self, objects=None):
2413        """Flush all the object changes to the database.
2414
2415        Writes out all pending object creations, deletions and modifications
2416        to the database as INSERTs, DELETEs, UPDATEs, etc.  Operations are
2417        automatically ordered by the Session's unit of work dependency
2418        solver.
2419
2420        Database operations will be issued in the current transactional
2421        context and do not affect the state of the transaction, unless an
2422        error occurs, in which case the entire transaction is rolled back.
2423        You may flush() as often as you like within a transaction to move
2424        changes from Python to the database's transaction buffer.
2425
2426        For ``autocommit`` Sessions with no active manual transaction, flush()
2427        will create a transaction on the fly that surrounds the entire set of
2428        operations into the flush.
2429
2430        :param objects: Optional; restricts the flush operation to operate
2431          only on elements that are in the given collection.
2432
2433          This feature is for an extremely narrow set of use cases where
2434          particular objects may need to be operated upon before the
2435          full flush() occurs.  It is not intended for general use.
2436
2437        """
2438
2439        if self._flushing:
2440            raise sa_exc.InvalidRequestError("Session is already flushing")
2441
2442        if self._is_clean():
2443            return
2444        try:
2445            self._flushing = True
2446            self._flush(objects)
2447        finally:
2448            self._flushing = False
2449
2450    def _flush_warning(self, method):
2451        util.warn(
2452            "Usage of the '%s' operation is not currently supported "
2453            "within the execution stage of the flush process. "
2454            "Results may not be consistent.  Consider using alternative "
2455            "event listeners or connection-level operations instead." % method
2456        )
2457
2458    def _is_clean(self):
2459        return (
2460            not self.identity_map.check_modified()
2461            and not self._deleted
2462            and not self._new
2463        )
2464
2465    def _flush(self, objects=None):
2466
2467        dirty = self._dirty_states
2468        if not dirty and not self._deleted and not self._new:
2469            self.identity_map._modified.clear()
2470            return
2471
2472        flush_context = UOWTransaction(self)
2473
2474        if self.dispatch.before_flush:
2475            self.dispatch.before_flush(self, flush_context, objects)
2476            # re-establish "dirty states" in case the listeners
2477            # added
2478            dirty = self._dirty_states
2479
2480        deleted = set(self._deleted)
2481        new = set(self._new)
2482
2483        dirty = set(dirty).difference(deleted)
2484
2485        # create the set of all objects we want to operate upon
2486        if objects:
2487            # specific list passed in
2488            objset = set()
2489            for o in objects:
2490                try:
2491                    state = attributes.instance_state(o)
2492                except exc.NO_STATE:
2493                    raise exc.UnmappedInstanceError(o)
2494                objset.add(state)
2495        else:
2496            objset = None
2497
2498        # store objects whose fate has been decided
2499        processed = set()
2500
2501        # put all saves/updates into the flush context.  detect top-level
2502        # orphans and throw them into deleted.
2503        if objset:
2504            proc = new.union(dirty).intersection(objset).difference(deleted)
2505        else:
2506            proc = new.union(dirty).difference(deleted)
2507
2508        for state in proc:
2509            is_orphan = _state_mapper(state)._is_orphan(state)
2510
2511            is_persistent_orphan = is_orphan and state.has_identity
2512
2513            if (
2514                is_orphan
2515                and not is_persistent_orphan
2516                and state._orphaned_outside_of_session
2517            ):
2518                self._expunge_states([state])
2519            else:
2520                _reg = flush_context.register_object(
2521                    state, isdelete=is_persistent_orphan
2522                )
2523                assert _reg, "Failed to add object to the flush context!"
2524                processed.add(state)
2525
2526        # put all remaining deletes into the flush context.
2527        if objset:
2528            proc = deleted.intersection(objset).difference(processed)
2529        else:
2530            proc = deleted.difference(processed)
2531        for state in proc:
2532            _reg = flush_context.register_object(state, isdelete=True)
2533            assert _reg, "Failed to add object to the flush context!"
2534
2535        if not flush_context.has_work:
2536            return
2537
2538        flush_context.transaction = transaction = self.begin(
2539            subtransactions=True
2540        )
2541        try:
2542            self._warn_on_events = True
2543            try:
2544                flush_context.execute()
2545            finally:
2546                self._warn_on_events = False
2547
2548            self.dispatch.after_flush(self, flush_context)
2549
2550            flush_context.finalize_flush_changes()
2551
2552            if not objects and self.identity_map._modified:
2553                len_ = len(self.identity_map._modified)
2554
2555                statelib.InstanceState._commit_all_states(
2556                    [
2557                        (state, state.dict)
2558                        for state in self.identity_map._modified
2559                    ],
2560                    instance_dict=self.identity_map,
2561                )
2562                util.warn(
2563                    "Attribute history events accumulated on %d "
2564                    "previously clean instances "
2565                    "within inner-flush event handlers have been "
2566                    "reset, and will not result in database updates. "
2567                    "Consider using set_committed_value() within "
2568                    "inner-flush event handlers to avoid this warning." % len_
2569                )
2570
2571            # useful assertions:
2572            # if not objects:
2573            #    assert not self.identity_map._modified
2574            # else:
2575            #    assert self.identity_map._modified == \
2576            #            self.identity_map._modified.difference(objects)
2577
2578            self.dispatch.after_flush_postexec(self, flush_context)
2579
2580            transaction.commit()
2581
2582        except:
2583            with util.safe_reraise():
2584                transaction.rollback(_capture_exception=True)
2585
2586    def bulk_save_objects(
2587        self, objects, return_defaults=False, update_changed_only=True
2588    ):
2589        """Perform a bulk save of the given list of objects.
2590
2591        The bulk save feature allows mapped objects to be used as the
2592        source of simple INSERT and UPDATE operations which can be more easily
2593        grouped together into higher performing "executemany"
2594        operations; the extraction of data from the objects is also performed
2595        using a lower-latency process that ignores whether or not attributes
2596        have actually been modified in the case of UPDATEs, and also ignores
2597        SQL expressions.
2598
2599        The objects as given are not added to the session and no additional
2600        state is established on them, unless the ``return_defaults`` flag
2601        is also set, in which case primary key attributes and server-side
2602        default values will be populated.
2603
2604        .. versionadded:: 1.0.0
2605
2606        .. warning::
2607
2608            The bulk save feature allows for a lower-latency INSERT/UPDATE
2609            of rows at the expense of most other unit-of-work features.
2610            Features such as object management, relationship handling,
2611            and SQL clause support are **silently omitted** in favor of raw
2612            INSERT/UPDATES of records.
2613
2614            **Please read the list of caveats at** :ref:`bulk_operations`
2615            **before using this method, and fully test and confirm the
2616            functionality of all code developed using these systems.**
2617
2618        :param objects: a list of mapped object instances.  The mapped
2619         objects are persisted as is, and are **not** associated with the
2620         :class:`.Session` afterwards.
2621
2622         For each object, whether the object is sent as an INSERT or an
2623         UPDATE is dependent on the same rules used by the :class:`.Session`
2624         in traditional operation; if the object has the
2625         :attr:`.InstanceState.key`
2626         attribute set, then the object is assumed to be "detached" and
2627         will result in an UPDATE.  Otherwise, an INSERT is used.
2628
2629         In the case of an UPDATE, statements are grouped based on which
2630         attributes have changed, and are thus to be the subject of each
2631         SET clause.  If ``update_changed_only`` is False, then all
2632         attributes present within each object are applied to the UPDATE
2633         statement, which may help in allowing the statements to be grouped
2634         together into a larger executemany(), and will also reduce the
2635         overhead of checking history on attributes.
2636
2637        :param return_defaults: when True, rows that are missing values which
2638         generate defaults, namely integer primary key defaults and sequences,
2639         will be inserted **one at a time**, so that the primary key value
2640         is available.  In particular this will allow joined-inheritance
2641         and other multi-table mappings to insert correctly without the need
2642         to provide primary key values ahead of time; however,
2643         :paramref:`.Session.bulk_save_objects.return_defaults` **greatly
2644         reduces the performance gains** of the method overall.
2645
2646        :param update_changed_only: when True, UPDATE statements are rendered
2647         based on those attributes in each state that have logged changes.
2648         When False, all attributes present are rendered into the SET clause
2649         with the exception of primary key attributes.
2650
2651        .. seealso::
2652
2653            :ref:`bulk_operations`
2654
2655            :meth:`.Session.bulk_insert_mappings`
2656
2657            :meth:`.Session.bulk_update_mappings`
2658
2659        """
2660        for (mapper, isupdate), states in itertools.groupby(
2661            (attributes.instance_state(obj) for obj in objects),
2662            lambda state: (state.mapper, state.key is not None),
2663        ):
2664            self._bulk_save_mappings(
2665                mapper,
2666                states,
2667                isupdate,
2668                True,
2669                return_defaults,
2670                update_changed_only,
2671                False,
2672            )
2673
2674    def bulk_insert_mappings(
2675        self, mapper, mappings, return_defaults=False, render_nulls=False
2676    ):
2677        """Perform a bulk insert of the given list of mapping dictionaries.
2678
2679        The bulk insert feature allows plain Python dictionaries to be used as
2680        the source of simple INSERT operations which can be more easily
2681        grouped together into higher performing "executemany"
2682        operations.  Using dictionaries, there is no "history" or session
2683        state management features in use, reducing latency when inserting
2684        large numbers of simple rows.
2685
2686        The values within the dictionaries as given are typically passed
2687        without modification into Core :meth:`.Insert` constructs, after
2688        organizing the values within them across the tables to which
2689        the given mapper is mapped.
2690
2691        .. versionadded:: 1.0.0
2692
2693        .. warning::
2694
2695            The bulk insert feature allows for a lower-latency INSERT
2696            of rows at the expense of most other unit-of-work features.
2697            Features such as object management, relationship handling,
2698            and SQL clause support are **silently omitted** in favor of raw
2699            INSERT of records.
2700
2701            **Please read the list of caveats at** :ref:`bulk_operations`
2702            **before using this method, and fully test and confirm the
2703            functionality of all code developed using these systems.**
2704
2705        :param mapper: a mapped class, or the actual :class:`.Mapper` object,
2706         representing the single kind of object represented within the mapping
2707         list.
2708
2709        :param mappings: a list of dictionaries, each one containing the state
2710         of the mapped row to be inserted, in terms of the attribute names
2711         on the mapped class.   If the mapping refers to multiple tables,
2712         such as a joined-inheritance mapping, each dictionary must contain
2713         all keys to be populated into all tables.
2714
2715        :param return_defaults: when True, rows that are missing values which
2716         generate defaults, namely integer primary key defaults and sequences,
2717         will be inserted **one at a time**, so that the primary key value
2718         is available.  In particular this will allow joined-inheritance
2719         and other multi-table mappings to insert correctly without the need
2720         to provide primary
2721         key values ahead of time; however,
2722         :paramref:`.Session.bulk_insert_mappings.return_defaults`
2723         **greatly reduces the performance gains** of the method overall.
2724         If the rows
2725         to be inserted only refer to a single table, then there is no
2726         reason this flag should be set as the returned default information
2727         is not used.
2728
2729        :param render_nulls: When True, a value of ``None`` will result
2730         in a NULL value being included in the INSERT statement, rather
2731         than the column being omitted from the INSERT.   This allows all
2732         the rows being INSERTed to have the identical set of columns which
2733         allows the full set of rows to be batched to the DBAPI.  Normally,
2734         each column-set that contains a different combination of NULL values
2735         than the previous row must omit a different series of columns from
2736         the rendered INSERT statement, which means it must be emitted as a
2737         separate statement.   By passing this flag, the full set of rows
2738         are guaranteed to be batchable into one batch; the cost however is
2739         that server-side defaults which are invoked by an omitted column will
2740         be skipped, so care must be taken to ensure that these are not
2741         necessary.
2742
2743         .. warning::
2744
2745            When this flag is set, **server side default SQL values will
2746            not be invoked** for those columns that are inserted as NULL;
2747            the NULL value will be sent explicitly.   Care must be taken
2748            to ensure that no server-side default functions need to be
2749            invoked for the operation as a whole.
2750
2751         .. versionadded:: 1.1
2752
2753        .. seealso::
2754
2755            :ref:`bulk_operations`
2756
2757            :meth:`.Session.bulk_save_objects`
2758
2759            :meth:`.Session.bulk_update_mappings`
2760
2761        """
2762        self._bulk_save_mappings(
2763            mapper,
2764            mappings,
2765            False,
2766            False,
2767            return_defaults,
2768            False,
2769            render_nulls,
2770        )
2771
2772    def bulk_update_mappings(self, mapper, mappings):
2773        """Perform a bulk update of the given list of mapping dictionaries.
2774
2775        The bulk update feature allows plain Python dictionaries to be used as
2776        the source of simple UPDATE operations which can be more easily
2777        grouped together into higher performing "executemany"
2778        operations.  Using dictionaries, there is no "history" or session
2779        state management features in use, reducing latency when updating
2780        large numbers of simple rows.
2781
2782        .. versionadded:: 1.0.0
2783
2784        .. warning::
2785
2786            The bulk update feature allows for a lower-latency UPDATE
2787            of rows at the expense of most other unit-of-work features.
2788            Features such as object management, relationship handling,
2789            and SQL clause support are **silently omitted** in favor of raw
2790            UPDATES of records.
2791
2792            **Please read the list of caveats at** :ref:`bulk_operations`
2793            **before using this method, and fully test and confirm the
2794            functionality of all code developed using these systems.**
2795
2796        :param mapper: a mapped class, or the actual :class:`.Mapper` object,
2797         representing the single kind of object represented within the mapping
2798         list.
2799
2800        :param mappings: a list of dictionaries, each one containing the state
2801         of the mapped row to be updated, in terms of the attribute names
2802         on the mapped class.   If the mapping refers to multiple tables,
2803         such as a joined-inheritance mapping, each dictionary may contain
2804         keys corresponding to all tables.   All those keys which are present
2805         and are not part of the primary key are applied to the SET clause
2806         of the UPDATE statement; the primary key values, which are required,
2807         are applied to the WHERE clause.
2808
2809
2810        .. seealso::
2811
2812            :ref:`bulk_operations`
2813
2814            :meth:`.Session.bulk_insert_mappings`
2815
2816            :meth:`.Session.bulk_save_objects`
2817
2818        """
2819        self._bulk_save_mappings(
2820            mapper, mappings, True, False, False, False, False
2821        )
2822
2823    def _bulk_save_mappings(
2824        self,
2825        mapper,
2826        mappings,
2827        isupdate,
2828        isstates,
2829        return_defaults,
2830        update_changed_only,
2831        render_nulls,
2832    ):
2833        mapper = _class_to_mapper(mapper)
2834        self._flushing = True
2835
2836        transaction = self.begin(subtransactions=True)
2837        try:
2838            if isupdate:
2839                persistence._bulk_update(
2840                    mapper,
2841                    mappings,
2842                    transaction,
2843                    isstates,
2844                    update_changed_only,
2845                )
2846            else:
2847                persistence._bulk_insert(
2848                    mapper,
2849                    mappings,
2850                    transaction,
2851                    isstates,
2852                    return_defaults,
2853                    render_nulls,
2854                )
2855            transaction.commit()
2856
2857        except:
2858            with util.safe_reraise():
2859                transaction.rollback(_capture_exception=True)
2860        finally:
2861            self._flushing = False
2862
2863    def is_modified(self, instance, include_collections=True, passive=True):
2864        r"""Return ``True`` if the given instance has locally
2865        modified attributes.
2866
2867        This method retrieves the history for each instrumented
2868        attribute on the instance and performs a comparison of the current
2869        value to its previously committed value, if any.
2870
2871        It is in effect a more expensive and accurate
2872        version of checking for the given instance in the
2873        :attr:`.Session.dirty` collection; a full test for
2874        each attribute's net "dirty" status is performed.
2875
2876        E.g.::
2877
2878            return session.is_modified(someobject)
2879
2880        A few caveats to this method apply:
2881
2882        * Instances present in the :attr:`.Session.dirty` collection may
2883          report ``False`` when tested with this method.  This is because
2884          the object may have received change events via attribute mutation,
2885          thus placing it in :attr:`.Session.dirty`, but ultimately the state
2886          is the same as that loaded from the database, resulting in no net
2887          change here.
2888        * Scalar attributes may not have recorded the previously set
2889          value when a new value was applied, if the attribute was not loaded,
2890          or was expired, at the time the new value was received - in these
2891          cases, the attribute is assumed to have a change, even if there is
2892          ultimately no net change against its database value. SQLAlchemy in
2893          most cases does not need the "old" value when a set event occurs, so
2894          it skips the expense of a SQL call if the old value isn't present,
2895          based on the assumption that an UPDATE of the scalar value is
2896          usually needed, and in those few cases where it isn't, is less
2897          expensive on average than issuing a defensive SELECT.
2898
2899          The "old" value is fetched unconditionally upon set only if the
2900          attribute container has the ``active_history`` flag set to ``True``.
2901          This flag is set typically for primary key attributes and scalar
2902          object references that are not a simple many-to-one.  To set this
2903          flag for any arbitrary mapped column, use the ``active_history``
2904          argument with :func:`.column_property`.
2905
2906        :param instance: mapped instance to be tested for pending changes.
2907        :param include_collections: Indicates if multivalued collections
2908         should be included in the operation.  Setting this to ``False`` is a
2909         way to detect only local-column based properties (i.e. scalar columns
2910         or many-to-one foreign keys) that would result in an UPDATE for this
2911         instance upon flush.
2912        :param passive:
2913
2914         .. deprecated:: 0.8
2915             The ``passive`` flag is deprecated and will be removed
2916             in a future release.  The flag is no longer used and is ignored.
2917
2918        """
2919        state = object_state(instance)
2920
2921        if not state.modified:
2922            return False
2923
2924        dict_ = state.dict
2925
2926        for attr in state.manager.attributes:
2927            if (
2928                not include_collections
2929                and hasattr(attr.impl, "get_collection")
2930            ) or not hasattr(attr.impl, "get_history"):
2931                continue
2932
2933            (added, unchanged, deleted) = attr.impl.get_history(
2934                state, dict_, passive=attributes.NO_CHANGE
2935            )
2936
2937            if added or deleted:
2938                return True
2939        else:
2940            return False
2941
2942    @property
2943    def is_active(self):
2944        """True if this :class:`.Session` is in "transaction mode" and
2945        is not in "partial rollback" state.
2946
2947        The :class:`.Session` in its default mode of ``autocommit=False``
2948        is essentially always in "transaction mode", in that a
2949        :class:`.SessionTransaction` is associated with it as soon as
2950        it is instantiated.  This :class:`.SessionTransaction` is immediately
2951        replaced with a new one as soon as it is ended, due to a rollback,
2952        commit, or close operation.
2953
2954        "Transaction mode" does *not* indicate whether
2955        or not actual database connection resources are in use;  the
2956        :class:`.SessionTransaction` object coordinates among zero or more
2957        actual database transactions, and starts out with none, accumulating
2958        individual DBAPI connections as different data sources are used
2959        within its scope.   The best way to track when a particular
2960        :class:`.Session` has actually begun to use DBAPI resources is to
2961        implement a listener using the :meth:`.SessionEvents.after_begin`
2962        method, which will deliver both the :class:`.Session` as well as the
2963        target :class:`.Connection` to a user-defined event listener.
2964
2965        The "partial rollback" state refers to when an "inner" transaction,
2966        typically used during a flush, encounters an error and emits a
2967        rollback of the DBAPI connection.  At this point, the
2968        :class:`.Session` is in "partial rollback" and awaits for the user to
2969        call :meth:`.Session.rollback`, in order to close out the
2970        transaction stack.  It is in this "partial rollback" period that the
2971        :attr:`.is_active` flag returns False.  After the call to
2972        :meth:`.Session.rollback`, the :class:`.SessionTransaction` is
2973        replaced with a new one and :attr:`.is_active` returns ``True`` again.
2974
2975        When a :class:`.Session` is used in ``autocommit=True`` mode, the
2976        :class:`.SessionTransaction` is only instantiated within the scope
2977        of a flush call, or when :meth:`.Session.begin` is called.  So
2978        :attr:`.is_active` will always be ``False`` outside of a flush or
2979        :meth:`.Session.begin` block in this mode, and will be ``True``
2980        within the :meth:`.Session.begin` block as long as it doesn't enter
2981        "partial rollback" state.
2982
2983        From all the above, it follows that the only purpose to this flag is
2984        for application frameworks that wish to detect is a "rollback" is
2985        necessary within a generic error handling routine, for
2986        :class:`.Session` objects that would otherwise be in
2987        "partial rollback" mode.  In a typical integration case, this is also
2988        not necessary as it is standard practice to emit
2989        :meth:`.Session.rollback` unconditionally within the outermost
2990        exception catch.
2991
2992        To track the transactional state of a :class:`.Session` fully,
2993        use event listeners, primarily the :meth:`.SessionEvents.after_begin`,
2994        :meth:`.SessionEvents.after_commit`,
2995        :meth:`.SessionEvents.after_rollback` and related events.
2996
2997        """
2998        return self.transaction and self.transaction.is_active
2999
3000    identity_map = None
3001    """A mapping of object identities to objects themselves.
3002
3003    Iterating through ``Session.identity_map.values()`` provides
3004    access to the full set of persistent objects (i.e., those
3005    that have row identity) currently in the session.
3006
3007    .. seealso::
3008
3009        :func:`.identity_key` - helper function to produce the keys used
3010        in this dictionary.
3011
3012    """
3013
3014    @property
3015    def _dirty_states(self):
3016        """The set of all persistent states considered dirty.
3017
3018        This method returns all states that were modified including
3019        those that were possibly deleted.
3020
3021        """
3022        return self.identity_map._dirty_states()
3023
3024    @property
3025    def dirty(self):
3026        """The set of all persistent instances considered dirty.
3027
3028        E.g.::
3029
3030            some_mapped_object in session.dirty
3031
3032        Instances are considered dirty when they were modified but not
3033        deleted.
3034
3035        Note that this 'dirty' calculation is 'optimistic'; most
3036        attribute-setting or collection modification operations will
3037        mark an instance as 'dirty' and place it in this set, even if
3038        there is no net change to the attribute's value.  At flush
3039        time, the value of each attribute is compared to its
3040        previously saved value, and if there's no net change, no SQL
3041        operation will occur (this is a more expensive operation so
3042        it's only done at flush time).
3043
3044        To check if an instance has actionable net changes to its
3045        attributes, use the :meth:`.Session.is_modified` method.
3046
3047        """
3048        return util.IdentitySet(
3049            [
3050                state.obj()
3051                for state in self._dirty_states
3052                if state not in self._deleted
3053            ]
3054        )
3055
3056    @property
3057    def deleted(self):
3058        "The set of all instances marked as 'deleted' within this ``Session``"
3059
3060        return util.IdentitySet(list(self._deleted.values()))
3061
3062    @property
3063    def new(self):
3064        "The set of all instances marked as 'new' within this ``Session``."
3065
3066        return util.IdentitySet(list(self._new.values()))
3067
3068
3069class sessionmaker(_SessionClassMethods):
3070    """A configurable :class:`.Session` factory.
3071
3072    The :class:`.sessionmaker` factory generates new
3073    :class:`.Session` objects when called, creating them given
3074    the configurational arguments established here.
3075
3076    e.g.::
3077
3078        # global scope
3079        Session = sessionmaker(autoflush=False)
3080
3081        # later, in a local scope, create and use a session:
3082        sess = Session()
3083
3084    Any keyword arguments sent to the constructor itself will override the
3085    "configured" keywords::
3086
3087        Session = sessionmaker()
3088
3089        # bind an individual session to a connection
3090        sess = Session(bind=connection)
3091
3092    The class also includes a method :meth:`.configure`, which can
3093    be used to specify additional keyword arguments to the factory, which
3094    will take effect for subsequent :class:`.Session` objects generated.
3095    This is usually used to associate one or more :class:`.Engine` objects
3096    with an existing :class:`.sessionmaker` factory before it is first
3097    used::
3098
3099        # application starts
3100        Session = sessionmaker()
3101
3102        # ... later
3103        engine = create_engine('sqlite:///foo.db')
3104        Session.configure(bind=engine)
3105
3106        sess = Session()
3107
3108    .. seealso:
3109
3110        :ref:`session_getting` - introductory text on creating
3111        sessions using :class:`.sessionmaker`.
3112
3113    """
3114
3115    def __init__(
3116        self,
3117        bind=None,
3118        class_=Session,
3119        autoflush=True,
3120        autocommit=False,
3121        expire_on_commit=True,
3122        info=None,
3123        **kw
3124    ):
3125        r"""Construct a new :class:`.sessionmaker`.
3126
3127        All arguments here except for ``class_`` correspond to arguments
3128        accepted by :class:`.Session` directly.  See the
3129        :meth:`.Session.__init__` docstring for more details on parameters.
3130
3131        :param bind: a :class:`.Engine` or other :class:`.Connectable` with
3132         which newly created :class:`.Session` objects will be associated.
3133        :param class_: class to use in order to create new :class:`.Session`
3134         objects.  Defaults to :class:`.Session`.
3135        :param autoflush: The autoflush setting to use with newly created
3136         :class:`.Session` objects.
3137        :param autocommit: The autocommit setting to use with newly created
3138         :class:`.Session` objects.
3139        :param expire_on_commit=True: the expire_on_commit setting to use
3140         with newly created :class:`.Session` objects.
3141        :param info: optional dictionary of information that will be available
3142         via :attr:`.Session.info`.  Note this dictionary is *updated*, not
3143         replaced, when the ``info`` parameter is specified to the specific
3144         :class:`.Session` construction operation.
3145
3146         .. versionadded:: 0.9.0
3147
3148        :param \**kw: all other keyword arguments are passed to the
3149         constructor of newly created :class:`.Session` objects.
3150
3151        """
3152        kw["bind"] = bind
3153        kw["autoflush"] = autoflush
3154        kw["autocommit"] = autocommit
3155        kw["expire_on_commit"] = expire_on_commit
3156        if info is not None:
3157            kw["info"] = info
3158        self.kw = kw
3159        # make our own subclass of the given class, so that
3160        # events can be associated with it specifically.
3161        self.class_ = type(class_.__name__, (class_,), {})
3162
3163    def __call__(self, **local_kw):
3164        """Produce a new :class:`.Session` object using the configuration
3165        established in this :class:`.sessionmaker`.
3166
3167        In Python, the ``__call__`` method is invoked on an object when
3168        it is "called" in the same way as a function::
3169
3170            Session = sessionmaker()
3171            session = Session()  # invokes sessionmaker.__call__()
3172
3173        """
3174        for k, v in self.kw.items():
3175            if k == "info" and "info" in local_kw:
3176                d = v.copy()
3177                d.update(local_kw["info"])
3178                local_kw["info"] = d
3179            else:
3180                local_kw.setdefault(k, v)
3181        return self.class_(**local_kw)
3182
3183    def configure(self, **new_kw):
3184        """(Re)configure the arguments for this sessionmaker.
3185
3186        e.g.::
3187
3188            Session = sessionmaker()
3189
3190            Session.configure(bind=create_engine('sqlite://'))
3191        """
3192        self.kw.update(new_kw)
3193
3194    def __repr__(self):
3195        return "%s(class_=%r, %s)" % (
3196            self.__class__.__name__,
3197            self.class_.__name__,
3198            ", ".join("%s=%r" % (k, v) for k, v in self.kw.items()),
3199        )
3200
3201
3202def make_transient(instance):
3203    """Alter the state of the given instance so that it is :term:`transient`.
3204
3205    .. note::
3206
3207        :func:`.make_transient` is a special-case function for
3208        advanced use cases only.
3209
3210    The given mapped instance is assumed to be in the :term:`persistent` or
3211    :term:`detached` state.   The function will remove its association with any
3212    :class:`.Session` as well as its :attr:`.InstanceState.identity`. The
3213    effect is that the object will behave as though it were newly constructed,
3214    except retaining any attribute / collection values that were loaded at the
3215    time of the call.   The :attr:`.InstanceState.deleted` flag is also reset
3216    if this object had been deleted as a result of using
3217    :meth:`.Session.delete`.
3218
3219    .. warning::
3220
3221        :func:`.make_transient` does **not** "unexpire" or otherwise eagerly
3222        load ORM-mapped attributes that are not currently loaded at the time
3223        the function is called.   This includes attributes which:
3224
3225        * were expired via :meth:`.Session.expire`
3226
3227        * were expired as the natural effect of committing a session
3228          transaction, e.g. :meth:`.Session.commit`
3229
3230        * are normally :term:`lazy loaded` but are not currently loaded
3231
3232        * are "deferred" via :ref:`deferred` and are not yet loaded
3233
3234        * were not present in the query which loaded this object, such as that
3235          which is common in joined table inheritance and other scenarios.
3236
3237        After :func:`.make_transient` is called, unloaded attributes such
3238        as those above will normally resolve to the value ``None`` when
3239        accessed, or an empty collection for a collection-oriented attribute.
3240        As the object is transient and un-associated with any database
3241        identity, it will no longer retrieve these values.
3242
3243    .. seealso::
3244
3245        :func:`.make_transient_to_detached`
3246
3247    """
3248    state = attributes.instance_state(instance)
3249    s = _state_session(state)
3250    if s:
3251        s._expunge_states([state])
3252
3253    # remove expired state
3254    state.expired_attributes.clear()
3255
3256    # remove deferred callables
3257    if state.callables:
3258        del state.callables
3259
3260    if state.key:
3261        del state.key
3262    if state._deleted:
3263        del state._deleted
3264
3265
3266def make_transient_to_detached(instance):
3267    """Make the given transient instance :term:`detached`.
3268
3269    .. note::
3270
3271        :func:`.make_transient_to_detached` is a special-case function for
3272        advanced use cases only.
3273
3274    All attribute history on the given instance
3275    will be reset as though the instance were freshly loaded
3276    from a query.  Missing attributes will be marked as expired.
3277    The primary key attributes of the object, which are required, will be made
3278    into the "key" of the instance.
3279
3280    The object can then be added to a session, or merged
3281    possibly with the load=False flag, at which point it will look
3282    as if it were loaded that way, without emitting SQL.
3283
3284    This is a special use case function that differs from a normal
3285    call to :meth:`.Session.merge` in that a given persistent state
3286    can be manufactured without any SQL calls.
3287
3288    .. versionadded:: 0.9.5
3289
3290    .. seealso::
3291
3292        :func:`.make_transient`
3293
3294        :meth:`.Session.enable_relationship_loading`
3295
3296    """
3297    state = attributes.instance_state(instance)
3298    if state.session_id or state.key:
3299        raise sa_exc.InvalidRequestError("Given object must be transient")
3300    state.key = state.mapper._identity_key_from_state(state)
3301    if state._deleted:
3302        del state._deleted
3303    state._commit_all(state.dict)
3304    state._expire_attributes(state.dict, state.unloaded_expirable)
3305
3306
3307def object_session(instance):
3308    """Return the :class:`.Session` to which the given instance belongs.
3309
3310    This is essentially the same as the :attr:`.InstanceState.session`
3311    accessor.  See that attribute for details.
3312
3313    """
3314
3315    try:
3316        state = attributes.instance_state(instance)
3317    except exc.NO_STATE:
3318        raise exc.UnmappedInstanceError(instance)
3319    else:
3320        return _state_session(state)
3321
3322
3323_new_sessionid = util.counter()
3324