1# orm/scoping.py
2# Copyright (C) 2005-2025 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: https://www.opensource.org/licenses/mit-license.php
7
8from __future__ import annotations
9
10from typing import Any
11from typing import Callable
12from typing import Dict
13from typing import Generic
14from typing import Iterable
15from typing import Iterator
16from typing import Optional
17from typing import overload
18from typing import Sequence
19from typing import Tuple
20from typing import Type
21from typing import TYPE_CHECKING
22from typing import TypeVar
23from typing import Union
24
25from .session import _S
26from .session import Session
27from .. import exc as sa_exc
28from .. import util
29from ..util import create_proxy_methods
30from ..util import ScopedRegistry
31from ..util import ThreadLocalRegistry
32from ..util import warn
33from ..util import warn_deprecated
34from ..util.typing import Protocol
35
36if TYPE_CHECKING:
37 from ._typing import _EntityType
38 from ._typing import _IdentityKeyType
39 from ._typing import OrmExecuteOptionsParameter
40 from .identity import IdentityMap
41 from .interfaces import ORMOption
42 from .mapper import Mapper
43 from .query import Query
44 from .query import RowReturningQuery
45 from .session import _BindArguments
46 from .session import _EntityBindKey
47 from .session import _PKIdentityArgument
48 from .session import _SessionBind
49 from .session import sessionmaker
50 from .session import SessionTransaction
51 from ..engine import Connection
52 from ..engine import CursorResult
53 from ..engine import Engine
54 from ..engine import Result
55 from ..engine import Row
56 from ..engine import RowMapping
57 from ..engine.interfaces import _CoreAnyExecuteParams
58 from ..engine.interfaces import _CoreSingleExecuteParams
59 from ..engine.interfaces import CoreExecuteOptionsParameter
60 from ..engine.result import ScalarResult
61 from ..sql._typing import _ColumnsClauseArgument
62 from ..sql._typing import _T0
63 from ..sql._typing import _T1
64 from ..sql._typing import _T2
65 from ..sql._typing import _T3
66 from ..sql._typing import _T4
67 from ..sql._typing import _T5
68 from ..sql._typing import _T6
69 from ..sql._typing import _T7
70 from ..sql._typing import _TypedColumnClauseArgument as _TCCA
71 from ..sql.base import Executable
72 from ..sql.dml import UpdateBase
73 from ..sql.elements import ClauseElement
74 from ..sql.roles import TypedColumnsClauseRole
75 from ..sql.selectable import ForUpdateParameter
76 from ..sql.selectable import TypedReturnsRows
77
78_T = TypeVar("_T", bound=Any)
79
80
81class QueryPropertyDescriptor(Protocol):
82 """Describes the type applied to a class-level
83 :meth:`_orm.scoped_session.query_property` attribute.
84
85 .. versionadded:: 2.0.5
86
87 """
88
89 def __get__(self, instance: Any, owner: Type[_T]) -> Query[_T]: ...
90
91
92_O = TypeVar("_O", bound=object)
93
94__all__ = ["scoped_session"]
95
96
97@create_proxy_methods(
98 Session,
99 ":class:`_orm.Session`",
100 ":class:`_orm.scoping.scoped_session`",
101 classmethods=["close_all", "object_session", "identity_key"],
102 methods=[
103 "__contains__",
104 "__iter__",
105 "add",
106 "add_all",
107 "begin",
108 "begin_nested",
109 "close",
110 "reset",
111 "commit",
112 "connection",
113 "delete",
114 "execute",
115 "expire",
116 "expire_all",
117 "expunge",
118 "expunge_all",
119 "flush",
120 "get",
121 "get_one",
122 "get_bind",
123 "is_modified",
124 "bulk_save_objects",
125 "bulk_insert_mappings",
126 "bulk_update_mappings",
127 "merge",
128 "query",
129 "refresh",
130 "rollback",
131 "scalar",
132 "scalars",
133 ],
134 attributes=[
135 "bind",
136 "dirty",
137 "deleted",
138 "new",
139 "identity_map",
140 "is_active",
141 "autoflush",
142 "no_autoflush",
143 "info",
144 ],
145)
146class scoped_session(Generic[_S]):
147 """Provides scoped management of :class:`.Session` objects.
148
149 See :ref:`unitofwork_contextual` for a tutorial.
150
151 .. note::
152
153 When using :ref:`asyncio_toplevel`, the async-compatible
154 :class:`_asyncio.async_scoped_session` class should be
155 used in place of :class:`.scoped_session`.
156
157 """
158
159 _support_async: bool = False
160
161 session_factory: sessionmaker[_S]
162 """The `session_factory` provided to `__init__` is stored in this
163 attribute and may be accessed at a later time. This can be useful when
164 a new non-scoped :class:`.Session` is needed."""
165
166 registry: ScopedRegistry[_S]
167
168 def __init__(
169 self,
170 session_factory: sessionmaker[_S],
171 scopefunc: Optional[Callable[[], Any]] = None,
172 ):
173 """Construct a new :class:`.scoped_session`.
174
175 :param session_factory: a factory to create new :class:`.Session`
176 instances. This is usually, but not necessarily, an instance
177 of :class:`.sessionmaker`.
178 :param scopefunc: optional function which defines
179 the current scope. If not passed, the :class:`.scoped_session`
180 object assumes "thread-local" scope, and will use
181 a Python ``threading.local()`` in order to maintain the current
182 :class:`.Session`. If passed, the function should return
183 a hashable token; this token will be used as the key in a
184 dictionary in order to store and retrieve the current
185 :class:`.Session`.
186
187 """
188 self.session_factory = session_factory
189
190 if scopefunc:
191 self.registry = ScopedRegistry(session_factory, scopefunc)
192 else:
193 self.registry = ThreadLocalRegistry(session_factory)
194
195 @property
196 def _proxied(self) -> _S:
197 return self.registry()
198
199 def __call__(self, **kw: Any) -> _S:
200 r"""Return the current :class:`.Session`, creating it
201 using the :attr:`.scoped_session.session_factory` if not present.
202
203 :param \**kw: Keyword arguments will be passed to the
204 :attr:`.scoped_session.session_factory` callable, if an existing
205 :class:`.Session` is not present. If the :class:`.Session` is present
206 and keyword arguments have been passed,
207 :exc:`~sqlalchemy.exc.InvalidRequestError` is raised.
208
209 """
210 if kw:
211 if self.registry.has():
212 raise sa_exc.InvalidRequestError(
213 "Scoped session is already present; "
214 "no new arguments may be specified."
215 )
216 else:
217 sess = self.session_factory(**kw)
218 self.registry.set(sess)
219 else:
220 sess = self.registry()
221 if not self._support_async and sess._is_asyncio:
222 warn_deprecated(
223 "Using `scoped_session` with asyncio is deprecated and "
224 "will raise an error in a future version. "
225 "Please use `async_scoped_session` instead.",
226 "1.4.23",
227 )
228 return sess
229
230 def configure(self, **kwargs: Any) -> None:
231 """reconfigure the :class:`.sessionmaker` used by this
232 :class:`.scoped_session`.
233
234 See :meth:`.sessionmaker.configure`.
235
236 """
237
238 if self.registry.has():
239 warn(
240 "At least one scoped session is already present. "
241 " configure() can not affect sessions that have "
242 "already been created."
243 )
244
245 self.session_factory.configure(**kwargs)
246
247 def remove(self) -> None:
248 """Dispose of the current :class:`.Session`, if present.
249
250 This will first call :meth:`.Session.close` method
251 on the current :class:`.Session`, which releases any existing
252 transactional/connection resources still being held; transactions
253 specifically are rolled back. The :class:`.Session` is then
254 discarded. Upon next usage within the same scope,
255 the :class:`.scoped_session` will produce a new
256 :class:`.Session` object.
257
258 """
259
260 if self.registry.has():
261 self.registry().close()
262 self.registry.clear()
263
264 def query_property(
265 self, query_cls: Optional[Type[Query[_T]]] = None
266 ) -> QueryPropertyDescriptor:
267 """return a class property which produces a legacy
268 :class:`_query.Query` object against the class and the current
269 :class:`.Session` when called.
270
271 .. legacy:: The :meth:`_orm.scoped_session.query_property` accessor
272 is specific to the legacy :class:`.Query` object and is not
273 considered to be part of :term:`2.0-style` ORM use.
274
275 e.g.::
276
277 from sqlalchemy.orm import QueryPropertyDescriptor
278 from sqlalchemy.orm import scoped_session
279 from sqlalchemy.orm import sessionmaker
280
281 Session = scoped_session(sessionmaker())
282
283
284 class MyClass:
285 query: QueryPropertyDescriptor = Session.query_property()
286
287
288 # after mappers are defined
289 result = MyClass.query.filter(MyClass.name == "foo").all()
290
291 Produces instances of the session's configured query class by
292 default. To override and use a custom implementation, provide
293 a ``query_cls`` callable. The callable will be invoked with
294 the class's mapper as a positional argument and a session
295 keyword argument.
296
297 There is no limit to the number of query properties placed on
298 a class.
299
300 """
301
302 class query:
303 def __get__(s, instance: Any, owner: Type[_O]) -> Query[_O]:
304 if query_cls:
305 # custom query class
306 return query_cls(owner, session=self.registry()) # type: ignore # noqa: E501
307 else:
308 # session's configured query class
309 return self.registry().query(owner)
310
311 return query()
312
313 # START PROXY METHODS scoped_session
314
315 # code within this block is **programmatically,
316 # statically generated** by tools/generate_proxy_methods.py
317
318 def __contains__(self, instance: object) -> bool:
319 r"""Return True if the instance is associated with this session.
320
321 .. container:: class_bases
322
323 Proxied for the :class:`_orm.Session` class on
324 behalf of the :class:`_orm.scoping.scoped_session` class.
325
326 The instance may be pending or persistent within the Session for a
327 result of True.
328
329
330 """ # noqa: E501
331
332 return self._proxied.__contains__(instance)
333
334 def __iter__(self) -> Iterator[object]:
335 r"""Iterate over all pending or persistent instances within this
336 Session.
337
338 .. container:: class_bases
339
340 Proxied for the :class:`_orm.Session` class on
341 behalf of the :class:`_orm.scoping.scoped_session` class.
342
343
344 """ # noqa: E501
345
346 return self._proxied.__iter__()
347
348 def add(self, instance: object, _warn: bool = True) -> None:
349 r"""Place an object into this :class:`_orm.Session`.
350
351 .. container:: class_bases
352
353 Proxied for the :class:`_orm.Session` class on
354 behalf of the :class:`_orm.scoping.scoped_session` class.
355
356 Objects that are in the :term:`transient` state when passed to the
357 :meth:`_orm.Session.add` method will move to the
358 :term:`pending` state, until the next flush, at which point they
359 will move to the :term:`persistent` state.
360
361 Objects that are in the :term:`detached` state when passed to the
362 :meth:`_orm.Session.add` method will move to the :term:`persistent`
363 state directly.
364
365 If the transaction used by the :class:`_orm.Session` is rolled back,
366 objects which were transient when they were passed to
367 :meth:`_orm.Session.add` will be moved back to the
368 :term:`transient` state, and will no longer be present within this
369 :class:`_orm.Session`.
370
371 .. seealso::
372
373 :meth:`_orm.Session.add_all`
374
375 :ref:`session_adding` - at :ref:`session_basics`
376
377
378 """ # noqa: E501
379
380 return self._proxied.add(instance, _warn=_warn)
381
382 def add_all(self, instances: Iterable[object]) -> None:
383 r"""Add the given collection of instances to this :class:`_orm.Session`.
384
385 .. container:: class_bases
386
387 Proxied for the :class:`_orm.Session` class on
388 behalf of the :class:`_orm.scoping.scoped_session` class.
389
390 See the documentation for :meth:`_orm.Session.add` for a general
391 behavioral description.
392
393 .. seealso::
394
395 :meth:`_orm.Session.add`
396
397 :ref:`session_adding` - at :ref:`session_basics`
398
399
400 """ # noqa: E501
401
402 return self._proxied.add_all(instances)
403
404 def begin(self, nested: bool = False) -> SessionTransaction:
405 r"""Begin a transaction, or nested transaction,
406 on this :class:`.Session`, if one is not already begun.
407
408 .. container:: class_bases
409
410 Proxied for the :class:`_orm.Session` class on
411 behalf of the :class:`_orm.scoping.scoped_session` class.
412
413 The :class:`_orm.Session` object features **autobegin** behavior,
414 so that normally it is not necessary to call the
415 :meth:`_orm.Session.begin`
416 method explicitly. However, it may be used in order to control
417 the scope of when the transactional state is begun.
418
419 When used to begin the outermost transaction, an error is raised
420 if this :class:`.Session` is already inside of a transaction.
421
422 :param nested: if True, begins a SAVEPOINT transaction and is
423 equivalent to calling :meth:`~.Session.begin_nested`. For
424 documentation on SAVEPOINT transactions, please see
425 :ref:`session_begin_nested`.
426
427 :return: the :class:`.SessionTransaction` object. Note that
428 :class:`.SessionTransaction`
429 acts as a Python context manager, allowing :meth:`.Session.begin`
430 to be used in a "with" block. See :ref:`session_explicit_begin` for
431 an example.
432
433 .. seealso::
434
435 :ref:`session_autobegin`
436
437 :ref:`unitofwork_transaction`
438
439 :meth:`.Session.begin_nested`
440
441
442
443 """ # noqa: E501
444
445 return self._proxied.begin(nested=nested)
446
447 def begin_nested(self) -> SessionTransaction:
448 r"""Begin a "nested" transaction on this Session, e.g. SAVEPOINT.
449
450 .. container:: class_bases
451
452 Proxied for the :class:`_orm.Session` class on
453 behalf of the :class:`_orm.scoping.scoped_session` class.
454
455 The target database(s) and associated drivers must support SQL
456 SAVEPOINT for this method to function correctly.
457
458 For documentation on SAVEPOINT
459 transactions, please see :ref:`session_begin_nested`.
460
461 :return: the :class:`.SessionTransaction` object. Note that
462 :class:`.SessionTransaction` acts as a context manager, allowing
463 :meth:`.Session.begin_nested` to be used in a "with" block.
464 See :ref:`session_begin_nested` for a usage example.
465
466 .. seealso::
467
468 :ref:`session_begin_nested`
469
470 :ref:`pysqlite_serializable` - special workarounds required
471 with the SQLite driver in order for SAVEPOINT to work
472 correctly. For asyncio use cases, see the section
473 :ref:`aiosqlite_serializable`.
474
475
476 """ # noqa: E501
477
478 return self._proxied.begin_nested()
479
480 def close(self) -> None:
481 r"""Close out the transactional resources and ORM objects used by this
482 :class:`_orm.Session`.
483
484 .. container:: class_bases
485
486 Proxied for the :class:`_orm.Session` class on
487 behalf of the :class:`_orm.scoping.scoped_session` class.
488
489 This expunges all ORM objects associated with this
490 :class:`_orm.Session`, ends any transaction in progress and
491 :term:`releases` any :class:`_engine.Connection` objects which this
492 :class:`_orm.Session` itself has checked out from associated
493 :class:`_engine.Engine` objects. The operation then leaves the
494 :class:`_orm.Session` in a state which it may be used again.
495
496 .. tip::
497
498 In the default running mode the :meth:`_orm.Session.close`
499 method **does not prevent the Session from being used again**.
500 The :class:`_orm.Session` itself does not actually have a
501 distinct "closed" state; it merely means
502 the :class:`_orm.Session` will release all database connections
503 and ORM objects.
504
505 Setting the parameter :paramref:`_orm.Session.close_resets_only`
506 to ``False`` will instead make the ``close`` final, meaning that
507 any further action on the session will be forbidden.
508
509 .. versionchanged:: 1.4 The :meth:`.Session.close` method does not
510 immediately create a new :class:`.SessionTransaction` object;
511 instead, the new :class:`.SessionTransaction` is created only if
512 the :class:`.Session` is used again for a database operation.
513
514 .. seealso::
515
516 :ref:`session_closing` - detail on the semantics of
517 :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`.
518
519 :meth:`_orm.Session.reset` - a similar method that behaves like
520 ``close()`` with the parameter
521 :paramref:`_orm.Session.close_resets_only` set to ``True``.
522
523
524 """ # noqa: E501
525
526 return self._proxied.close()
527
528 def reset(self) -> None:
529 r"""Close out the transactional resources and ORM objects used by this
530 :class:`_orm.Session`, resetting the session to its initial state.
531
532 .. container:: class_bases
533
534 Proxied for the :class:`_orm.Session` class on
535 behalf of the :class:`_orm.scoping.scoped_session` class.
536
537 This method provides for same "reset-only" behavior that the
538 :meth:`_orm.Session.close` method has provided historically, where the
539 state of the :class:`_orm.Session` is reset as though the object were
540 brand new, and ready to be used again.
541 This method may then be useful for :class:`_orm.Session` objects
542 which set :paramref:`_orm.Session.close_resets_only` to ``False``,
543 so that "reset only" behavior is still available.
544
545 .. versionadded:: 2.0.22
546
547 .. seealso::
548
549 :ref:`session_closing` - detail on the semantics of
550 :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`.
551
552 :meth:`_orm.Session.close` - a similar method will additionally
553 prevent re-use of the Session when the parameter
554 :paramref:`_orm.Session.close_resets_only` is set to ``False``.
555
556 """ # noqa: E501
557
558 return self._proxied.reset()
559
560 def commit(self) -> None:
561 r"""Flush pending changes and commit the current transaction.
562
563 .. container:: class_bases
564
565 Proxied for the :class:`_orm.Session` class on
566 behalf of the :class:`_orm.scoping.scoped_session` class.
567
568 When the COMMIT operation is complete, all objects are fully
569 :term:`expired`, erasing their internal contents, which will be
570 automatically re-loaded when the objects are next accessed. In the
571 interim, these objects are in an expired state and will not function if
572 they are :term:`detached` from the :class:`.Session`. Additionally,
573 this re-load operation is not supported when using asyncio-oriented
574 APIs. The :paramref:`.Session.expire_on_commit` parameter may be used
575 to disable this behavior.
576
577 When there is no transaction in place for the :class:`.Session`,
578 indicating that no operations were invoked on this :class:`.Session`
579 since the previous call to :meth:`.Session.commit`, the method will
580 begin and commit an internal-only "logical" transaction, that does not
581 normally affect the database unless pending flush changes were
582 detected, but will still invoke event handlers and object expiration
583 rules.
584
585 The outermost database transaction is committed unconditionally,
586 automatically releasing any SAVEPOINTs in effect.
587
588 .. seealso::
589
590 :ref:`session_committing`
591
592 :ref:`unitofwork_transaction`
593
594 :ref:`asyncio_orm_avoid_lazyloads`
595
596
597 """ # noqa: E501
598
599 return self._proxied.commit()
600
601 def connection(
602 self,
603 bind_arguments: Optional[_BindArguments] = None,
604 execution_options: Optional[CoreExecuteOptionsParameter] = None,
605 ) -> Connection:
606 r"""Return a :class:`_engine.Connection` object corresponding to this
607 :class:`.Session` object's transactional state.
608
609 .. container:: class_bases
610
611 Proxied for the :class:`_orm.Session` class on
612 behalf of the :class:`_orm.scoping.scoped_session` class.
613
614 Either the :class:`_engine.Connection` corresponding to the current
615 transaction is returned, or if no transaction is in progress, a new
616 one is begun and the :class:`_engine.Connection`
617 returned (note that no
618 transactional state is established with the DBAPI until the first
619 SQL statement is emitted).
620
621 Ambiguity in multi-bind or unbound :class:`.Session` objects can be
622 resolved through any of the optional keyword arguments. This
623 ultimately makes usage of the :meth:`.get_bind` method for resolution.
624
625 :param bind_arguments: dictionary of bind arguments. May include
626 "mapper", "bind", "clause", other custom arguments that are passed
627 to :meth:`.Session.get_bind`.
628
629 :param execution_options: a dictionary of execution options that will
630 be passed to :meth:`_engine.Connection.execution_options`, **when the
631 connection is first procured only**. If the connection is already
632 present within the :class:`.Session`, a warning is emitted and
633 the arguments are ignored.
634
635 .. seealso::
636
637 :ref:`session_transaction_isolation`
638
639
640 """ # noqa: E501
641
642 return self._proxied.connection(
643 bind_arguments=bind_arguments, execution_options=execution_options
644 )
645
646 def delete(self, instance: object) -> None:
647 r"""Mark an instance as deleted.
648
649 .. container:: class_bases
650
651 Proxied for the :class:`_orm.Session` class on
652 behalf of the :class:`_orm.scoping.scoped_session` class.
653
654 The object is assumed to be either :term:`persistent` or
655 :term:`detached` when passed; after the method is called, the
656 object will remain in the :term:`persistent` state until the next
657 flush proceeds. During this time, the object will also be a member
658 of the :attr:`_orm.Session.deleted` collection.
659
660 When the next flush proceeds, the object will move to the
661 :term:`deleted` state, indicating a ``DELETE`` statement was emitted
662 for its row within the current transaction. When the transaction
663 is successfully committed,
664 the deleted object is moved to the :term:`detached` state and is
665 no longer present within this :class:`_orm.Session`.
666
667 .. seealso::
668
669 :ref:`session_deleting` - at :ref:`session_basics`
670
671
672 """ # noqa: E501
673
674 return self._proxied.delete(instance)
675
676 @overload
677 def execute(
678 self,
679 statement: TypedReturnsRows[_T],
680 params: Optional[_CoreAnyExecuteParams] = None,
681 *,
682 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
683 bind_arguments: Optional[_BindArguments] = None,
684 _parent_execute_state: Optional[Any] = None,
685 _add_event: Optional[Any] = None,
686 ) -> Result[_T]: ...
687
688 @overload
689 def execute(
690 self,
691 statement: UpdateBase,
692 params: Optional[_CoreAnyExecuteParams] = None,
693 *,
694 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
695 bind_arguments: Optional[_BindArguments] = None,
696 _parent_execute_state: Optional[Any] = None,
697 _add_event: Optional[Any] = None,
698 ) -> CursorResult[Any]: ...
699
700 @overload
701 def execute(
702 self,
703 statement: Executable,
704 params: Optional[_CoreAnyExecuteParams] = None,
705 *,
706 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
707 bind_arguments: Optional[_BindArguments] = None,
708 _parent_execute_state: Optional[Any] = None,
709 _add_event: Optional[Any] = None,
710 ) -> Result[Any]: ...
711
712 def execute(
713 self,
714 statement: Executable,
715 params: Optional[_CoreAnyExecuteParams] = None,
716 *,
717 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
718 bind_arguments: Optional[_BindArguments] = None,
719 _parent_execute_state: Optional[Any] = None,
720 _add_event: Optional[Any] = None,
721 ) -> Result[Any]:
722 r"""Execute a SQL expression construct.
723
724 .. container:: class_bases
725
726 Proxied for the :class:`_orm.Session` class on
727 behalf of the :class:`_orm.scoping.scoped_session` class.
728
729 Returns a :class:`_engine.Result` object representing
730 results of the statement execution.
731
732 E.g.::
733
734 from sqlalchemy import select
735
736 result = session.execute(select(User).where(User.id == 5))
737
738 The API contract of :meth:`_orm.Session.execute` is similar to that
739 of :meth:`_engine.Connection.execute`, the :term:`2.0 style` version
740 of :class:`_engine.Connection`.
741
742 .. versionchanged:: 1.4 the :meth:`_orm.Session.execute` method is
743 now the primary point of ORM statement execution when using
744 :term:`2.0 style` ORM usage.
745
746 :param statement:
747 An executable statement (i.e. an :class:`.Executable` expression
748 such as :func:`_expression.select`).
749
750 :param params:
751 Optional dictionary, or list of dictionaries, containing
752 bound parameter values. If a single dictionary, single-row
753 execution occurs; if a list of dictionaries, an
754 "executemany" will be invoked. The keys in each dictionary
755 must correspond to parameter names present in the statement.
756
757 :param execution_options: optional dictionary of execution options,
758 which will be associated with the statement execution. This
759 dictionary can provide a subset of the options that are accepted
760 by :meth:`_engine.Connection.execution_options`, and may also
761 provide additional options understood only in an ORM context.
762
763 .. seealso::
764
765 :ref:`orm_queryguide_execution_options` - ORM-specific execution
766 options
767
768 :param bind_arguments: dictionary of additional arguments to determine
769 the bind. May include "mapper", "bind", or other custom arguments.
770 Contents of this dictionary are passed to the
771 :meth:`.Session.get_bind` method.
772
773 :return: a :class:`_engine.Result` object.
774
775
776
777 """ # noqa: E501
778
779 return self._proxied.execute(
780 statement,
781 params=params,
782 execution_options=execution_options,
783 bind_arguments=bind_arguments,
784 _parent_execute_state=_parent_execute_state,
785 _add_event=_add_event,
786 )
787
788 def expire(
789 self, instance: object, attribute_names: Optional[Iterable[str]] = None
790 ) -> None:
791 r"""Expire the attributes on an instance.
792
793 .. container:: class_bases
794
795 Proxied for the :class:`_orm.Session` class on
796 behalf of the :class:`_orm.scoping.scoped_session` class.
797
798 Marks the attributes of an instance as out of date. When an expired
799 attribute is next accessed, a query will be issued to the
800 :class:`.Session` object's current transactional context in order to
801 load all expired attributes for the given instance. Note that
802 a highly isolated transaction will return the same values as were
803 previously read in that same transaction, regardless of changes
804 in database state outside of that transaction.
805
806 To expire all objects in the :class:`.Session` simultaneously,
807 use :meth:`Session.expire_all`.
808
809 The :class:`.Session` object's default behavior is to
810 expire all state whenever the :meth:`Session.rollback`
811 or :meth:`Session.commit` methods are called, so that new
812 state can be loaded for the new transaction. For this reason,
813 calling :meth:`Session.expire` only makes sense for the specific
814 case that a non-ORM SQL statement was emitted in the current
815 transaction.
816
817 :param instance: The instance to be refreshed.
818 :param attribute_names: optional list of string attribute names
819 indicating a subset of attributes to be expired.
820
821 .. seealso::
822
823 :ref:`session_expire` - introductory material
824
825 :meth:`.Session.expire`
826
827 :meth:`.Session.refresh`
828
829 :meth:`_orm.Query.populate_existing`
830
831
832 """ # noqa: E501
833
834 return self._proxied.expire(instance, attribute_names=attribute_names)
835
836 def expire_all(self) -> None:
837 r"""Expires all persistent instances within this Session.
838
839 .. container:: class_bases
840
841 Proxied for the :class:`_orm.Session` class on
842 behalf of the :class:`_orm.scoping.scoped_session` class.
843
844 When any attributes on a persistent instance is next accessed,
845 a query will be issued using the
846 :class:`.Session` object's current transactional context in order to
847 load all expired attributes for the given instance. Note that
848 a highly isolated transaction will return the same values as were
849 previously read in that same transaction, regardless of changes
850 in database state outside of that transaction.
851
852 To expire individual objects and individual attributes
853 on those objects, use :meth:`Session.expire`.
854
855 The :class:`.Session` object's default behavior is to
856 expire all state whenever the :meth:`Session.rollback`
857 or :meth:`Session.commit` methods are called, so that new
858 state can be loaded for the new transaction. For this reason,
859 calling :meth:`Session.expire_all` is not usually needed,
860 assuming the transaction is isolated.
861
862 .. seealso::
863
864 :ref:`session_expire` - introductory material
865
866 :meth:`.Session.expire`
867
868 :meth:`.Session.refresh`
869
870 :meth:`_orm.Query.populate_existing`
871
872
873 """ # noqa: E501
874
875 return self._proxied.expire_all()
876
877 def expunge(self, instance: object) -> None:
878 r"""Remove the `instance` from this ``Session``.
879
880 .. container:: class_bases
881
882 Proxied for the :class:`_orm.Session` class on
883 behalf of the :class:`_orm.scoping.scoped_session` class.
884
885 This will free all internal references to the instance. Cascading
886 will be applied according to the *expunge* cascade rule.
887
888
889 """ # noqa: E501
890
891 return self._proxied.expunge(instance)
892
893 def expunge_all(self) -> None:
894 r"""Remove all object instances from this ``Session``.
895
896 .. container:: class_bases
897
898 Proxied for the :class:`_orm.Session` class on
899 behalf of the :class:`_orm.scoping.scoped_session` class.
900
901 This is equivalent to calling ``expunge(obj)`` on all objects in this
902 ``Session``.
903
904
905 """ # noqa: E501
906
907 return self._proxied.expunge_all()
908
909 def flush(self, objects: Optional[Sequence[Any]] = None) -> None:
910 r"""Flush all the object changes to the database.
911
912 .. container:: class_bases
913
914 Proxied for the :class:`_orm.Session` class on
915 behalf of the :class:`_orm.scoping.scoped_session` class.
916
917 Writes out all pending object creations, deletions and modifications
918 to the database as INSERTs, DELETEs, UPDATEs, etc. Operations are
919 automatically ordered by the Session's unit of work dependency
920 solver.
921
922 Database operations will be issued in the current transactional
923 context and do not affect the state of the transaction, unless an
924 error occurs, in which case the entire transaction is rolled back.
925 You may flush() as often as you like within a transaction to move
926 changes from Python to the database's transaction buffer.
927
928 :param objects: Optional; restricts the flush operation to operate
929 only on elements that are in the given collection.
930
931 This feature is for an extremely narrow set of use cases where
932 particular objects may need to be operated upon before the
933 full flush() occurs. It is not intended for general use.
934
935
936 """ # noqa: E501
937
938 return self._proxied.flush(objects=objects)
939
940 def get(
941 self,
942 entity: _EntityBindKey[_O],
943 ident: _PKIdentityArgument,
944 *,
945 options: Optional[Sequence[ORMOption]] = None,
946 populate_existing: bool = False,
947 with_for_update: ForUpdateParameter = None,
948 identity_token: Optional[Any] = None,
949 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
950 bind_arguments: Optional[_BindArguments] = None,
951 ) -> Optional[_O]:
952 r"""Return an instance based on the given primary key identifier,
953 or ``None`` if not found.
954
955 .. container:: class_bases
956
957 Proxied for the :class:`_orm.Session` class on
958 behalf of the :class:`_orm.scoping.scoped_session` class.
959
960 E.g.::
961
962 my_user = session.get(User, 5)
963
964 some_object = session.get(VersionedFoo, (5, 10))
965
966 some_object = session.get(VersionedFoo, {"id": 5, "version_id": 10})
967
968 .. versionadded:: 1.4 Added :meth:`_orm.Session.get`, which is moved
969 from the now legacy :meth:`_orm.Query.get` method.
970
971 :meth:`_orm.Session.get` is special in that it provides direct
972 access to the identity map of the :class:`.Session`.
973 If the given primary key identifier is present
974 in the local identity map, the object is returned
975 directly from this collection and no SQL is emitted,
976 unless the object has been marked fully expired.
977 If not present,
978 a SELECT is performed in order to locate the object.
979
980 :meth:`_orm.Session.get` also will perform a check if
981 the object is present in the identity map and
982 marked as expired - a SELECT
983 is emitted to refresh the object as well as to
984 ensure that the row is still present.
985 If not, :class:`~sqlalchemy.orm.exc.ObjectDeletedError` is raised.
986
987 :param entity: a mapped class or :class:`.Mapper` indicating the
988 type of entity to be loaded.
989
990 :param ident: A scalar, tuple, or dictionary representing the
991 primary key. For a composite (e.g. multiple column) primary key,
992 a tuple or dictionary should be passed.
993
994 For a single-column primary key, the scalar calling form is typically
995 the most expedient. If the primary key of a row is the value "5",
996 the call looks like::
997
998 my_object = session.get(SomeClass, 5)
999
1000 The tuple form contains primary key values typically in
1001 the order in which they correspond to the mapped
1002 :class:`_schema.Table`
1003 object's primary key columns, or if the
1004 :paramref:`_orm.Mapper.primary_key` configuration parameter were
1005 used, in
1006 the order used for that parameter. For example, if the primary key
1007 of a row is represented by the integer
1008 digits "5, 10" the call would look like::
1009
1010 my_object = session.get(SomeClass, (5, 10))
1011
1012 The dictionary form should include as keys the mapped attribute names
1013 corresponding to each element of the primary key. If the mapped class
1014 has the attributes ``id``, ``version_id`` as the attributes which
1015 store the object's primary key value, the call would look like::
1016
1017 my_object = session.get(SomeClass, {"id": 5, "version_id": 10})
1018
1019 :param options: optional sequence of loader options which will be
1020 applied to the query, if one is emitted.
1021
1022 :param populate_existing: causes the method to unconditionally emit
1023 a SQL query and refresh the object with the newly loaded data,
1024 regardless of whether or not the object is already present.
1025
1026 :param with_for_update: optional boolean ``True`` indicating FOR UPDATE
1027 should be used, or may be a dictionary containing flags to
1028 indicate a more specific set of FOR UPDATE flags for the SELECT;
1029 flags should match the parameters of
1030 :meth:`_query.Query.with_for_update`.
1031 Supersedes the :paramref:`.Session.refresh.lockmode` parameter.
1032
1033 :param execution_options: optional dictionary of execution options,
1034 which will be associated with the query execution if one is emitted.
1035 This dictionary can provide a subset of the options that are
1036 accepted by :meth:`_engine.Connection.execution_options`, and may
1037 also provide additional options understood only in an ORM context.
1038
1039 .. versionadded:: 1.4.29
1040
1041 .. seealso::
1042
1043 :ref:`orm_queryguide_execution_options` - ORM-specific execution
1044 options
1045
1046 :param bind_arguments: dictionary of additional arguments to determine
1047 the bind. May include "mapper", "bind", or other custom arguments.
1048 Contents of this dictionary are passed to the
1049 :meth:`.Session.get_bind` method.
1050
1051 .. versionadded: 2.0.0rc1
1052
1053 :return: The object instance, or ``None``.
1054
1055
1056 """ # noqa: E501
1057
1058 return self._proxied.get(
1059 entity,
1060 ident,
1061 options=options,
1062 populate_existing=populate_existing,
1063 with_for_update=with_for_update,
1064 identity_token=identity_token,
1065 execution_options=execution_options,
1066 bind_arguments=bind_arguments,
1067 )
1068
1069 def get_one(
1070 self,
1071 entity: _EntityBindKey[_O],
1072 ident: _PKIdentityArgument,
1073 *,
1074 options: Optional[Sequence[ORMOption]] = None,
1075 populate_existing: bool = False,
1076 with_for_update: ForUpdateParameter = None,
1077 identity_token: Optional[Any] = None,
1078 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1079 bind_arguments: Optional[_BindArguments] = None,
1080 ) -> _O:
1081 r"""Return exactly one instance based on the given primary key
1082 identifier, or raise an exception if not found.
1083
1084 .. container:: class_bases
1085
1086 Proxied for the :class:`_orm.Session` class on
1087 behalf of the :class:`_orm.scoping.scoped_session` class.
1088
1089 Raises :class:`_exc.NoResultFound` if the query selects no rows.
1090
1091 For a detailed documentation of the arguments see the
1092 method :meth:`.Session.get`.
1093
1094 .. versionadded:: 2.0.22
1095
1096 :return: The object instance.
1097
1098 .. seealso::
1099
1100 :meth:`.Session.get` - equivalent method that instead
1101 returns ``None`` if no row was found with the provided primary
1102 key
1103
1104
1105 """ # noqa: E501
1106
1107 return self._proxied.get_one(
1108 entity,
1109 ident,
1110 options=options,
1111 populate_existing=populate_existing,
1112 with_for_update=with_for_update,
1113 identity_token=identity_token,
1114 execution_options=execution_options,
1115 bind_arguments=bind_arguments,
1116 )
1117
1118 def get_bind(
1119 self,
1120 mapper: Optional[_EntityBindKey[_O]] = None,
1121 *,
1122 clause: Optional[ClauseElement] = None,
1123 bind: Optional[_SessionBind] = None,
1124 _sa_skip_events: Optional[bool] = None,
1125 _sa_skip_for_implicit_returning: bool = False,
1126 **kw: Any,
1127 ) -> Union[Engine, Connection]:
1128 r"""Return a "bind" to which this :class:`.Session` is bound.
1129
1130 .. container:: class_bases
1131
1132 Proxied for the :class:`_orm.Session` class on
1133 behalf of the :class:`_orm.scoping.scoped_session` class.
1134
1135 The "bind" is usually an instance of :class:`_engine.Engine`,
1136 except in the case where the :class:`.Session` has been
1137 explicitly bound directly to a :class:`_engine.Connection`.
1138
1139 For a multiply-bound or unbound :class:`.Session`, the
1140 ``mapper`` or ``clause`` arguments are used to determine the
1141 appropriate bind to return.
1142
1143 Note that the "mapper" argument is usually present
1144 when :meth:`.Session.get_bind` is called via an ORM
1145 operation such as a :meth:`.Session.query`, each
1146 individual INSERT/UPDATE/DELETE operation within a
1147 :meth:`.Session.flush`, call, etc.
1148
1149 The order of resolution is:
1150
1151 1. if mapper given and :paramref:`.Session.binds` is present,
1152 locate a bind based first on the mapper in use, then
1153 on the mapped class in use, then on any base classes that are
1154 present in the ``__mro__`` of the mapped class, from more specific
1155 superclasses to more general.
1156 2. if clause given and ``Session.binds`` is present,
1157 locate a bind based on :class:`_schema.Table` objects
1158 found in the given clause present in ``Session.binds``.
1159 3. if ``Session.binds`` is present, return that.
1160 4. if clause given, attempt to return a bind
1161 linked to the :class:`_schema.MetaData` ultimately
1162 associated with the clause.
1163 5. if mapper given, attempt to return a bind
1164 linked to the :class:`_schema.MetaData` ultimately
1165 associated with the :class:`_schema.Table` or other
1166 selectable to which the mapper is mapped.
1167 6. No bind can be found, :exc:`~sqlalchemy.exc.UnboundExecutionError`
1168 is raised.
1169
1170 Note that the :meth:`.Session.get_bind` method can be overridden on
1171 a user-defined subclass of :class:`.Session` to provide any kind
1172 of bind resolution scheme. See the example at
1173 :ref:`session_custom_partitioning`.
1174
1175 :param mapper:
1176 Optional mapped class or corresponding :class:`_orm.Mapper` instance.
1177 The bind can be derived from a :class:`_orm.Mapper` first by
1178 consulting the "binds" map associated with this :class:`.Session`,
1179 and secondly by consulting the :class:`_schema.MetaData` associated
1180 with the :class:`_schema.Table` to which the :class:`_orm.Mapper` is
1181 mapped for a bind.
1182
1183 :param clause:
1184 A :class:`_expression.ClauseElement` (i.e.
1185 :func:`_expression.select`,
1186 :func:`_expression.text`,
1187 etc.). If the ``mapper`` argument is not present or could not
1188 produce a bind, the given expression construct will be searched
1189 for a bound element, typically a :class:`_schema.Table`
1190 associated with
1191 bound :class:`_schema.MetaData`.
1192
1193 .. seealso::
1194
1195 :ref:`session_partitioning`
1196
1197 :paramref:`.Session.binds`
1198
1199 :meth:`.Session.bind_mapper`
1200
1201 :meth:`.Session.bind_table`
1202
1203
1204 """ # noqa: E501
1205
1206 return self._proxied.get_bind(
1207 mapper=mapper,
1208 clause=clause,
1209 bind=bind,
1210 _sa_skip_events=_sa_skip_events,
1211 _sa_skip_for_implicit_returning=_sa_skip_for_implicit_returning,
1212 **kw,
1213 )
1214
1215 def is_modified(
1216 self, instance: object, include_collections: bool = True
1217 ) -> bool:
1218 r"""Return ``True`` if the given instance has locally
1219 modified attributes.
1220
1221 .. container:: class_bases
1222
1223 Proxied for the :class:`_orm.Session` class on
1224 behalf of the :class:`_orm.scoping.scoped_session` class.
1225
1226 This method retrieves the history for each instrumented
1227 attribute on the instance and performs a comparison of the current
1228 value to its previously flushed or committed value, if any.
1229
1230 It is in effect a more expensive and accurate
1231 version of checking for the given instance in the
1232 :attr:`.Session.dirty` collection; a full test for
1233 each attribute's net "dirty" status is performed.
1234
1235 E.g.::
1236
1237 return session.is_modified(someobject)
1238
1239 A few caveats to this method apply:
1240
1241 * Instances present in the :attr:`.Session.dirty` collection may
1242 report ``False`` when tested with this method. This is because
1243 the object may have received change events via attribute mutation,
1244 thus placing it in :attr:`.Session.dirty`, but ultimately the state
1245 is the same as that loaded from the database, resulting in no net
1246 change here.
1247 * Scalar attributes may not have recorded the previously set
1248 value when a new value was applied, if the attribute was not loaded,
1249 or was expired, at the time the new value was received - in these
1250 cases, the attribute is assumed to have a change, even if there is
1251 ultimately no net change against its database value. SQLAlchemy in
1252 most cases does not need the "old" value when a set event occurs, so
1253 it skips the expense of a SQL call if the old value isn't present,
1254 based on the assumption that an UPDATE of the scalar value is
1255 usually needed, and in those few cases where it isn't, is less
1256 expensive on average than issuing a defensive SELECT.
1257
1258 The "old" value is fetched unconditionally upon set only if the
1259 attribute container has the ``active_history`` flag set to ``True``.
1260 This flag is set typically for primary key attributes and scalar
1261 object references that are not a simple many-to-one. To set this
1262 flag for any arbitrary mapped column, use the ``active_history``
1263 argument with :func:`.column_property`.
1264
1265 :param instance: mapped instance to be tested for pending changes.
1266 :param include_collections: Indicates if multivalued collections
1267 should be included in the operation. Setting this to ``False`` is a
1268 way to detect only local-column based properties (i.e. scalar columns
1269 or many-to-one foreign keys) that would result in an UPDATE for this
1270 instance upon flush.
1271
1272
1273 """ # noqa: E501
1274
1275 return self._proxied.is_modified(
1276 instance, include_collections=include_collections
1277 )
1278
1279 def bulk_save_objects(
1280 self,
1281 objects: Iterable[object],
1282 return_defaults: bool = False,
1283 update_changed_only: bool = True,
1284 preserve_order: bool = True,
1285 ) -> None:
1286 r"""Perform a bulk save of the given list of objects.
1287
1288 .. container:: class_bases
1289
1290 Proxied for the :class:`_orm.Session` class on
1291 behalf of the :class:`_orm.scoping.scoped_session` class.
1292
1293 .. legacy::
1294
1295 This method is a legacy feature as of the 2.0 series of
1296 SQLAlchemy. For modern bulk INSERT and UPDATE, see
1297 the sections :ref:`orm_queryguide_bulk_insert` and
1298 :ref:`orm_queryguide_bulk_update`.
1299
1300 For general INSERT and UPDATE of existing ORM mapped objects,
1301 prefer standard :term:`unit of work` data management patterns,
1302 introduced in the :ref:`unified_tutorial` at
1303 :ref:`tutorial_orm_data_manipulation`. SQLAlchemy 2.0
1304 now uses :ref:`engine_insertmanyvalues` with modern dialects
1305 which solves previous issues of bulk INSERT slowness.
1306
1307 :param objects: a sequence of mapped object instances. The mapped
1308 objects are persisted as is, and are **not** associated with the
1309 :class:`.Session` afterwards.
1310
1311 For each object, whether the object is sent as an INSERT or an
1312 UPDATE is dependent on the same rules used by the :class:`.Session`
1313 in traditional operation; if the object has the
1314 :attr:`.InstanceState.key`
1315 attribute set, then the object is assumed to be "detached" and
1316 will result in an UPDATE. Otherwise, an INSERT is used.
1317
1318 In the case of an UPDATE, statements are grouped based on which
1319 attributes have changed, and are thus to be the subject of each
1320 SET clause. If ``update_changed_only`` is False, then all
1321 attributes present within each object are applied to the UPDATE
1322 statement, which may help in allowing the statements to be grouped
1323 together into a larger executemany(), and will also reduce the
1324 overhead of checking history on attributes.
1325
1326 :param return_defaults: when True, rows that are missing values which
1327 generate defaults, namely integer primary key defaults and sequences,
1328 will be inserted **one at a time**, so that the primary key value
1329 is available. In particular this will allow joined-inheritance
1330 and other multi-table mappings to insert correctly without the need
1331 to provide primary key values ahead of time; however,
1332 :paramref:`.Session.bulk_save_objects.return_defaults` **greatly
1333 reduces the performance gains** of the method overall. It is strongly
1334 advised to please use the standard :meth:`_orm.Session.add_all`
1335 approach.
1336
1337 :param update_changed_only: when True, UPDATE statements are rendered
1338 based on those attributes in each state that have logged changes.
1339 When False, all attributes present are rendered into the SET clause
1340 with the exception of primary key attributes.
1341
1342 :param preserve_order: when True, the order of inserts and updates
1343 matches exactly the order in which the objects are given. When
1344 False, common types of objects are grouped into inserts
1345 and updates, to allow for more batching opportunities.
1346
1347 .. seealso::
1348
1349 :doc:`queryguide/dml`
1350
1351 :meth:`.Session.bulk_insert_mappings`
1352
1353 :meth:`.Session.bulk_update_mappings`
1354
1355
1356 """ # noqa: E501
1357
1358 return self._proxied.bulk_save_objects(
1359 objects,
1360 return_defaults=return_defaults,
1361 update_changed_only=update_changed_only,
1362 preserve_order=preserve_order,
1363 )
1364
1365 def bulk_insert_mappings(
1366 self,
1367 mapper: Mapper[Any],
1368 mappings: Iterable[Dict[str, Any]],
1369 return_defaults: bool = False,
1370 render_nulls: bool = False,
1371 ) -> None:
1372 r"""Perform a bulk insert of the given list of mapping dictionaries.
1373
1374 .. container:: class_bases
1375
1376 Proxied for the :class:`_orm.Session` class on
1377 behalf of the :class:`_orm.scoping.scoped_session` class.
1378
1379 .. legacy::
1380
1381 This method is a legacy feature as of the 2.0 series of
1382 SQLAlchemy. For modern bulk INSERT and UPDATE, see
1383 the sections :ref:`orm_queryguide_bulk_insert` and
1384 :ref:`orm_queryguide_bulk_update`. The 2.0 API shares
1385 implementation details with this method and adds new features
1386 as well.
1387
1388 :param mapper: a mapped class, or the actual :class:`_orm.Mapper`
1389 object,
1390 representing the single kind of object represented within the mapping
1391 list.
1392
1393 :param mappings: a sequence of dictionaries, each one containing the
1394 state of the mapped row to be inserted, in terms of the attribute
1395 names on the mapped class. If the mapping refers to multiple tables,
1396 such as a joined-inheritance mapping, each dictionary must contain all
1397 keys to be populated into all tables.
1398
1399 :param return_defaults: when True, the INSERT process will be altered
1400 to ensure that newly generated primary key values will be fetched.
1401 The rationale for this parameter is typically to enable
1402 :ref:`Joined Table Inheritance <joined_inheritance>` mappings to
1403 be bulk inserted.
1404
1405 .. note:: for backends that don't support RETURNING, the
1406 :paramref:`_orm.Session.bulk_insert_mappings.return_defaults`
1407 parameter can significantly decrease performance as INSERT
1408 statements can no longer be batched. See
1409 :ref:`engine_insertmanyvalues`
1410 for background on which backends are affected.
1411
1412 :param render_nulls: When True, a value of ``None`` will result
1413 in a NULL value being included in the INSERT statement, rather
1414 than the column being omitted from the INSERT. This allows all
1415 the rows being INSERTed to have the identical set of columns which
1416 allows the full set of rows to be batched to the DBAPI. Normally,
1417 each column-set that contains a different combination of NULL values
1418 than the previous row must omit a different series of columns from
1419 the rendered INSERT statement, which means it must be emitted as a
1420 separate statement. By passing this flag, the full set of rows
1421 are guaranteed to be batchable into one batch; the cost however is
1422 that server-side defaults which are invoked by an omitted column will
1423 be skipped, so care must be taken to ensure that these are not
1424 necessary.
1425
1426 .. warning::
1427
1428 When this flag is set, **server side default SQL values will
1429 not be invoked** for those columns that are inserted as NULL;
1430 the NULL value will be sent explicitly. Care must be taken
1431 to ensure that no server-side default functions need to be
1432 invoked for the operation as a whole.
1433
1434 .. seealso::
1435
1436 :doc:`queryguide/dml`
1437
1438 :meth:`.Session.bulk_save_objects`
1439
1440 :meth:`.Session.bulk_update_mappings`
1441
1442
1443 """ # noqa: E501
1444
1445 return self._proxied.bulk_insert_mappings(
1446 mapper,
1447 mappings,
1448 return_defaults=return_defaults,
1449 render_nulls=render_nulls,
1450 )
1451
1452 def bulk_update_mappings(
1453 self, mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]]
1454 ) -> None:
1455 r"""Perform a bulk update of the given list of mapping dictionaries.
1456
1457 .. container:: class_bases
1458
1459 Proxied for the :class:`_orm.Session` class on
1460 behalf of the :class:`_orm.scoping.scoped_session` class.
1461
1462 .. legacy::
1463
1464 This method is a legacy feature as of the 2.0 series of
1465 SQLAlchemy. For modern bulk INSERT and UPDATE, see
1466 the sections :ref:`orm_queryguide_bulk_insert` and
1467 :ref:`orm_queryguide_bulk_update`. The 2.0 API shares
1468 implementation details with this method and adds new features
1469 as well.
1470
1471 :param mapper: a mapped class, or the actual :class:`_orm.Mapper`
1472 object,
1473 representing the single kind of object represented within the mapping
1474 list.
1475
1476 :param mappings: a sequence of dictionaries, each one containing the
1477 state of the mapped row to be updated, in terms of the attribute names
1478 on the mapped class. If the mapping refers to multiple tables, such
1479 as a joined-inheritance mapping, each dictionary may contain keys
1480 corresponding to all tables. All those keys which are present and
1481 are not part of the primary key are applied to the SET clause of the
1482 UPDATE statement; the primary key values, which are required, are
1483 applied to the WHERE clause.
1484
1485
1486 .. seealso::
1487
1488 :doc:`queryguide/dml`
1489
1490 :meth:`.Session.bulk_insert_mappings`
1491
1492 :meth:`.Session.bulk_save_objects`
1493
1494
1495 """ # noqa: E501
1496
1497 return self._proxied.bulk_update_mappings(mapper, mappings)
1498
1499 def merge(
1500 self,
1501 instance: _O,
1502 *,
1503 load: bool = True,
1504 options: Optional[Sequence[ORMOption]] = None,
1505 ) -> _O:
1506 r"""Copy the state of a given instance into a corresponding instance
1507 within this :class:`.Session`.
1508
1509 .. container:: class_bases
1510
1511 Proxied for the :class:`_orm.Session` class on
1512 behalf of the :class:`_orm.scoping.scoped_session` class.
1513
1514 :meth:`.Session.merge` examines the primary key attributes of the
1515 source instance, and attempts to reconcile it with an instance of the
1516 same primary key in the session. If not found locally, it attempts
1517 to load the object from the database based on primary key, and if
1518 none can be located, creates a new instance. The state of each
1519 attribute on the source instance is then copied to the target
1520 instance. The resulting target instance is then returned by the
1521 method; the original source instance is left unmodified, and
1522 un-associated with the :class:`.Session` if not already.
1523
1524 This operation cascades to associated instances if the association is
1525 mapped with ``cascade="merge"``.
1526
1527 See :ref:`unitofwork_merging` for a detailed discussion of merging.
1528
1529 :param instance: Instance to be merged.
1530 :param load: Boolean, when False, :meth:`.merge` switches into
1531 a "high performance" mode which causes it to forego emitting history
1532 events as well as all database access. This flag is used for
1533 cases such as transferring graphs of objects into a :class:`.Session`
1534 from a second level cache, or to transfer just-loaded objects
1535 into the :class:`.Session` owned by a worker thread or process
1536 without re-querying the database.
1537
1538 The ``load=False`` use case adds the caveat that the given
1539 object has to be in a "clean" state, that is, has no pending changes
1540 to be flushed - even if the incoming object is detached from any
1541 :class:`.Session`. This is so that when
1542 the merge operation populates local attributes and
1543 cascades to related objects and
1544 collections, the values can be "stamped" onto the
1545 target object as is, without generating any history or attribute
1546 events, and without the need to reconcile the incoming data with
1547 any existing related objects or collections that might not
1548 be loaded. The resulting objects from ``load=False`` are always
1549 produced as "clean", so it is only appropriate that the given objects
1550 should be "clean" as well, else this suggests a mis-use of the
1551 method.
1552 :param options: optional sequence of loader options which will be
1553 applied to the :meth:`_orm.Session.get` method when the merge
1554 operation loads the existing version of the object from the database.
1555
1556 .. versionadded:: 1.4.24
1557
1558
1559 .. seealso::
1560
1561 :func:`.make_transient_to_detached` - provides for an alternative
1562 means of "merging" a single object into the :class:`.Session`
1563
1564
1565 """ # noqa: E501
1566
1567 return self._proxied.merge(instance, load=load, options=options)
1568
1569 @overload
1570 def query(self, _entity: _EntityType[_O]) -> Query[_O]: ...
1571
1572 @overload
1573 def query(
1574 self, _colexpr: TypedColumnsClauseRole[_T]
1575 ) -> RowReturningQuery[Tuple[_T]]: ...
1576
1577 # START OVERLOADED FUNCTIONS self.query RowReturningQuery 2-8
1578
1579 # code within this block is **programmatically,
1580 # statically generated** by tools/generate_tuple_map_overloads.py
1581
1582 @overload
1583 def query(
1584 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1]
1585 ) -> RowReturningQuery[Tuple[_T0, _T1]]: ...
1586
1587 @overload
1588 def query(
1589 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2]
1590 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2]]: ...
1591
1592 @overload
1593 def query(
1594 self,
1595 __ent0: _TCCA[_T0],
1596 __ent1: _TCCA[_T1],
1597 __ent2: _TCCA[_T2],
1598 __ent3: _TCCA[_T3],
1599 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3]]: ...
1600
1601 @overload
1602 def query(
1603 self,
1604 __ent0: _TCCA[_T0],
1605 __ent1: _TCCA[_T1],
1606 __ent2: _TCCA[_T2],
1607 __ent3: _TCCA[_T3],
1608 __ent4: _TCCA[_T4],
1609 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4]]: ...
1610
1611 @overload
1612 def query(
1613 self,
1614 __ent0: _TCCA[_T0],
1615 __ent1: _TCCA[_T1],
1616 __ent2: _TCCA[_T2],
1617 __ent3: _TCCA[_T3],
1618 __ent4: _TCCA[_T4],
1619 __ent5: _TCCA[_T5],
1620 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ...
1621
1622 @overload
1623 def query(
1624 self,
1625 __ent0: _TCCA[_T0],
1626 __ent1: _TCCA[_T1],
1627 __ent2: _TCCA[_T2],
1628 __ent3: _TCCA[_T3],
1629 __ent4: _TCCA[_T4],
1630 __ent5: _TCCA[_T5],
1631 __ent6: _TCCA[_T6],
1632 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ...
1633
1634 @overload
1635 def query(
1636 self,
1637 __ent0: _TCCA[_T0],
1638 __ent1: _TCCA[_T1],
1639 __ent2: _TCCA[_T2],
1640 __ent3: _TCCA[_T3],
1641 __ent4: _TCCA[_T4],
1642 __ent5: _TCCA[_T5],
1643 __ent6: _TCCA[_T6],
1644 __ent7: _TCCA[_T7],
1645 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]: ...
1646
1647 # END OVERLOADED FUNCTIONS self.query
1648
1649 @overload
1650 def query(
1651 self, *entities: _ColumnsClauseArgument[Any], **kwargs: Any
1652 ) -> Query[Any]: ...
1653
1654 def query(
1655 self, *entities: _ColumnsClauseArgument[Any], **kwargs: Any
1656 ) -> Query[Any]:
1657 r"""Return a new :class:`_query.Query` object corresponding to this
1658 :class:`_orm.Session`.
1659
1660 .. container:: class_bases
1661
1662 Proxied for the :class:`_orm.Session` class on
1663 behalf of the :class:`_orm.scoping.scoped_session` class.
1664
1665 Note that the :class:`_query.Query` object is legacy as of
1666 SQLAlchemy 2.0; the :func:`_sql.select` construct is now used
1667 to construct ORM queries.
1668
1669 .. seealso::
1670
1671 :ref:`unified_tutorial`
1672
1673 :ref:`queryguide_toplevel`
1674
1675 :ref:`query_api_toplevel` - legacy API doc
1676
1677
1678 """ # noqa: E501
1679
1680 return self._proxied.query(*entities, **kwargs)
1681
1682 def refresh(
1683 self,
1684 instance: object,
1685 attribute_names: Optional[Iterable[str]] = None,
1686 with_for_update: ForUpdateParameter = None,
1687 ) -> None:
1688 r"""Expire and refresh attributes on the given instance.
1689
1690 .. container:: class_bases
1691
1692 Proxied for the :class:`_orm.Session` class on
1693 behalf of the :class:`_orm.scoping.scoped_session` class.
1694
1695 The selected attributes will first be expired as they would when using
1696 :meth:`_orm.Session.expire`; then a SELECT statement will be issued to
1697 the database to refresh column-oriented attributes with the current
1698 value available in the current transaction.
1699
1700 :func:`_orm.relationship` oriented attributes will also be immediately
1701 loaded if they were already eagerly loaded on the object, using the
1702 same eager loading strategy that they were loaded with originally.
1703
1704 .. versionadded:: 1.4 - the :meth:`_orm.Session.refresh` method
1705 can also refresh eagerly loaded attributes.
1706
1707 :func:`_orm.relationship` oriented attributes that would normally
1708 load using the ``select`` (or "lazy") loader strategy will also
1709 load **if they are named explicitly in the attribute_names
1710 collection**, emitting a SELECT statement for the attribute using the
1711 ``immediate`` loader strategy. If lazy-loaded relationships are not
1712 named in :paramref:`_orm.Session.refresh.attribute_names`, then
1713 they remain as "lazy loaded" attributes and are not implicitly
1714 refreshed.
1715
1716 .. versionchanged:: 2.0.4 The :meth:`_orm.Session.refresh` method
1717 will now refresh lazy-loaded :func:`_orm.relationship` oriented
1718 attributes for those which are named explicitly in the
1719 :paramref:`_orm.Session.refresh.attribute_names` collection.
1720
1721 .. tip::
1722
1723 While the :meth:`_orm.Session.refresh` method is capable of
1724 refreshing both column and relationship oriented attributes, its
1725 primary focus is on refreshing of local column-oriented attributes
1726 on a single instance. For more open ended "refresh" functionality,
1727 including the ability to refresh the attributes on many objects at
1728 once while having explicit control over relationship loader
1729 strategies, use the
1730 :ref:`populate existing <orm_queryguide_populate_existing>` feature
1731 instead.
1732
1733 Note that a highly isolated transaction will return the same values as
1734 were previously read in that same transaction, regardless of changes
1735 in database state outside of that transaction. Refreshing
1736 attributes usually only makes sense at the start of a transaction
1737 where database rows have not yet been accessed.
1738
1739 :param attribute_names: optional. An iterable collection of
1740 string attribute names indicating a subset of attributes to
1741 be refreshed.
1742
1743 :param with_for_update: optional boolean ``True`` indicating FOR UPDATE
1744 should be used, or may be a dictionary containing flags to
1745 indicate a more specific set of FOR UPDATE flags for the SELECT;
1746 flags should match the parameters of
1747 :meth:`_query.Query.with_for_update`.
1748 Supersedes the :paramref:`.Session.refresh.lockmode` parameter.
1749
1750 .. seealso::
1751
1752 :ref:`session_expire` - introductory material
1753
1754 :meth:`.Session.expire`
1755
1756 :meth:`.Session.expire_all`
1757
1758 :ref:`orm_queryguide_populate_existing` - allows any ORM query
1759 to refresh objects as they would be loaded normally.
1760
1761
1762 """ # noqa: E501
1763
1764 return self._proxied.refresh(
1765 instance,
1766 attribute_names=attribute_names,
1767 with_for_update=with_for_update,
1768 )
1769
1770 def rollback(self) -> None:
1771 r"""Rollback the current transaction in progress.
1772
1773 .. container:: class_bases
1774
1775 Proxied for the :class:`_orm.Session` class on
1776 behalf of the :class:`_orm.scoping.scoped_session` class.
1777
1778 If no transaction is in progress, this method is a pass-through.
1779
1780 The method always rolls back
1781 the topmost database transaction, discarding any nested
1782 transactions that may be in progress.
1783
1784 .. seealso::
1785
1786 :ref:`session_rollback`
1787
1788 :ref:`unitofwork_transaction`
1789
1790
1791 """ # noqa: E501
1792
1793 return self._proxied.rollback()
1794
1795 @overload
1796 def scalar(
1797 self,
1798 statement: TypedReturnsRows[Tuple[_T]],
1799 params: Optional[_CoreSingleExecuteParams] = None,
1800 *,
1801 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1802 bind_arguments: Optional[_BindArguments] = None,
1803 **kw: Any,
1804 ) -> Optional[_T]: ...
1805
1806 @overload
1807 def scalar(
1808 self,
1809 statement: Executable,
1810 params: Optional[_CoreSingleExecuteParams] = None,
1811 *,
1812 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1813 bind_arguments: Optional[_BindArguments] = None,
1814 **kw: Any,
1815 ) -> Any: ...
1816
1817 def scalar(
1818 self,
1819 statement: Executable,
1820 params: Optional[_CoreSingleExecuteParams] = None,
1821 *,
1822 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1823 bind_arguments: Optional[_BindArguments] = None,
1824 **kw: Any,
1825 ) -> Any:
1826 r"""Execute a statement and return a scalar result.
1827
1828 .. container:: class_bases
1829
1830 Proxied for the :class:`_orm.Session` class on
1831 behalf of the :class:`_orm.scoping.scoped_session` class.
1832
1833 Usage and parameters are the same as that of
1834 :meth:`_orm.Session.execute`; the return result is a scalar Python
1835 value.
1836
1837
1838 """ # noqa: E501
1839
1840 return self._proxied.scalar(
1841 statement,
1842 params=params,
1843 execution_options=execution_options,
1844 bind_arguments=bind_arguments,
1845 **kw,
1846 )
1847
1848 @overload
1849 def scalars(
1850 self,
1851 statement: TypedReturnsRows[Tuple[_T]],
1852 params: Optional[_CoreAnyExecuteParams] = None,
1853 *,
1854 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1855 bind_arguments: Optional[_BindArguments] = None,
1856 **kw: Any,
1857 ) -> ScalarResult[_T]: ...
1858
1859 @overload
1860 def scalars(
1861 self,
1862 statement: Executable,
1863 params: Optional[_CoreAnyExecuteParams] = None,
1864 *,
1865 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1866 bind_arguments: Optional[_BindArguments] = None,
1867 **kw: Any,
1868 ) -> ScalarResult[Any]: ...
1869
1870 def scalars(
1871 self,
1872 statement: Executable,
1873 params: Optional[_CoreAnyExecuteParams] = None,
1874 *,
1875 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1876 bind_arguments: Optional[_BindArguments] = None,
1877 **kw: Any,
1878 ) -> ScalarResult[Any]:
1879 r"""Execute a statement and return the results as scalars.
1880
1881 .. container:: class_bases
1882
1883 Proxied for the :class:`_orm.Session` class on
1884 behalf of the :class:`_orm.scoping.scoped_session` class.
1885
1886 Usage and parameters are the same as that of
1887 :meth:`_orm.Session.execute`; the return result is a
1888 :class:`_result.ScalarResult` filtering object which
1889 will return single elements rather than :class:`_row.Row` objects.
1890
1891 :return: a :class:`_result.ScalarResult` object
1892
1893 .. versionadded:: 1.4.24 Added :meth:`_orm.Session.scalars`
1894
1895 .. versionadded:: 1.4.26 Added :meth:`_orm.scoped_session.scalars`
1896
1897 .. seealso::
1898
1899 :ref:`orm_queryguide_select_orm_entities` - contrasts the behavior
1900 of :meth:`_orm.Session.execute` to :meth:`_orm.Session.scalars`
1901
1902
1903 """ # noqa: E501
1904
1905 return self._proxied.scalars(
1906 statement,
1907 params=params,
1908 execution_options=execution_options,
1909 bind_arguments=bind_arguments,
1910 **kw,
1911 )
1912
1913 @property
1914 def bind(self) -> Optional[Union[Engine, Connection]]:
1915 r"""Proxy for the :attr:`_orm.Session.bind` attribute
1916 on behalf of the :class:`_orm.scoping.scoped_session` class.
1917
1918 """ # noqa: E501
1919
1920 return self._proxied.bind
1921
1922 @bind.setter
1923 def bind(self, attr: Optional[Union[Engine, Connection]]) -> None:
1924 self._proxied.bind = attr
1925
1926 @property
1927 def dirty(self) -> Any:
1928 r"""The set of all persistent instances considered dirty.
1929
1930 .. container:: class_bases
1931
1932 Proxied for the :class:`_orm.Session` class
1933 on behalf of the :class:`_orm.scoping.scoped_session` class.
1934
1935 E.g.::
1936
1937 some_mapped_object in session.dirty
1938
1939 Instances are considered dirty when they were modified but not
1940 deleted.
1941
1942 Note that this 'dirty' calculation is 'optimistic'; most
1943 attribute-setting or collection modification operations will
1944 mark an instance as 'dirty' and place it in this set, even if
1945 there is no net change to the attribute's value. At flush
1946 time, the value of each attribute is compared to its
1947 previously saved value, and if there's no net change, no SQL
1948 operation will occur (this is a more expensive operation so
1949 it's only done at flush time).
1950
1951 To check if an instance has actionable net changes to its
1952 attributes, use the :meth:`.Session.is_modified` method.
1953
1954
1955 """ # noqa: E501
1956
1957 return self._proxied.dirty
1958
1959 @property
1960 def deleted(self) -> Any:
1961 r"""The set of all instances marked as 'deleted' within this ``Session``
1962
1963 .. container:: class_bases
1964
1965 Proxied for the :class:`_orm.Session` class
1966 on behalf of the :class:`_orm.scoping.scoped_session` class.
1967
1968 """ # noqa: E501
1969
1970 return self._proxied.deleted
1971
1972 @property
1973 def new(self) -> Any:
1974 r"""The set of all instances marked as 'new' within this ``Session``.
1975
1976 .. container:: class_bases
1977
1978 Proxied for the :class:`_orm.Session` class
1979 on behalf of the :class:`_orm.scoping.scoped_session` class.
1980
1981 """ # noqa: E501
1982
1983 return self._proxied.new
1984
1985 @property
1986 def identity_map(self) -> IdentityMap:
1987 r"""Proxy for the :attr:`_orm.Session.identity_map` attribute
1988 on behalf of the :class:`_orm.scoping.scoped_session` class.
1989
1990 """ # noqa: E501
1991
1992 return self._proxied.identity_map
1993
1994 @identity_map.setter
1995 def identity_map(self, attr: IdentityMap) -> None:
1996 self._proxied.identity_map = attr
1997
1998 @property
1999 def is_active(self) -> Any:
2000 r"""True if this :class:`.Session` not in "partial rollback" state.
2001
2002 .. container:: class_bases
2003
2004 Proxied for the :class:`_orm.Session` class
2005 on behalf of the :class:`_orm.scoping.scoped_session` class.
2006
2007 .. versionchanged:: 1.4 The :class:`_orm.Session` no longer begins
2008 a new transaction immediately, so this attribute will be False
2009 when the :class:`_orm.Session` is first instantiated.
2010
2011 "partial rollback" state typically indicates that the flush process
2012 of the :class:`_orm.Session` has failed, and that the
2013 :meth:`_orm.Session.rollback` method must be emitted in order to
2014 fully roll back the transaction.
2015
2016 If this :class:`_orm.Session` is not in a transaction at all, the
2017 :class:`_orm.Session` will autobegin when it is first used, so in this
2018 case :attr:`_orm.Session.is_active` will return True.
2019
2020 Otherwise, if this :class:`_orm.Session` is within a transaction,
2021 and that transaction has not been rolled back internally, the
2022 :attr:`_orm.Session.is_active` will also return True.
2023
2024 .. seealso::
2025
2026 :ref:`faq_session_rollback`
2027
2028 :meth:`_orm.Session.in_transaction`
2029
2030
2031 """ # noqa: E501
2032
2033 return self._proxied.is_active
2034
2035 @property
2036 def autoflush(self) -> bool:
2037 r"""Proxy for the :attr:`_orm.Session.autoflush` attribute
2038 on behalf of the :class:`_orm.scoping.scoped_session` class.
2039
2040 """ # noqa: E501
2041
2042 return self._proxied.autoflush
2043
2044 @autoflush.setter
2045 def autoflush(self, attr: bool) -> None:
2046 self._proxied.autoflush = attr
2047
2048 @property
2049 def no_autoflush(self) -> Any:
2050 r"""Return a context manager that disables autoflush.
2051
2052 .. container:: class_bases
2053
2054 Proxied for the :class:`_orm.Session` class
2055 on behalf of the :class:`_orm.scoping.scoped_session` class.
2056
2057 e.g.::
2058
2059 with session.no_autoflush:
2060
2061 some_object = SomeClass()
2062 session.add(some_object)
2063 # won't autoflush
2064 some_object.related_thing = session.query(SomeRelated).first()
2065
2066 Operations that proceed within the ``with:`` block
2067 will not be subject to flushes occurring upon query
2068 access. This is useful when initializing a series
2069 of objects which involve existing database queries,
2070 where the uncompleted object should not yet be flushed.
2071
2072
2073 """ # noqa: E501
2074
2075 return self._proxied.no_autoflush
2076
2077 @property
2078 def info(self) -> Any:
2079 r"""A user-modifiable dictionary.
2080
2081 .. container:: class_bases
2082
2083 Proxied for the :class:`_orm.Session` class
2084 on behalf of the :class:`_orm.scoping.scoped_session` class.
2085
2086 The initial value of this dictionary can be populated using the
2087 ``info`` argument to the :class:`.Session` constructor or
2088 :class:`.sessionmaker` constructor or factory methods. The dictionary
2089 here is always local to this :class:`.Session` and can be modified
2090 independently of all other :class:`.Session` objects.
2091
2092
2093 """ # noqa: E501
2094
2095 return self._proxied.info
2096
2097 @classmethod
2098 def close_all(cls) -> None:
2099 r"""Close *all* sessions in memory.
2100
2101 .. container:: class_bases
2102
2103 Proxied for the :class:`_orm.Session` class on
2104 behalf of the :class:`_orm.scoping.scoped_session` class.
2105
2106 .. deprecated:: 1.3 The :meth:`.Session.close_all` method is deprecated and will be removed in a future release. Please refer to :func:`.session.close_all_sessions`.
2107
2108 """ # noqa: E501
2109
2110 return Session.close_all()
2111
2112 @classmethod
2113 def object_session(cls, instance: object) -> Optional[Session]:
2114 r"""Return the :class:`.Session` to which an object belongs.
2115
2116 .. container:: class_bases
2117
2118 Proxied for the :class:`_orm.Session` class on
2119 behalf of the :class:`_orm.scoping.scoped_session` class.
2120
2121 This is an alias of :func:`.object_session`.
2122
2123
2124 """ # noqa: E501
2125
2126 return Session.object_session(instance)
2127
2128 @classmethod
2129 def identity_key(
2130 cls,
2131 class_: Optional[Type[Any]] = None,
2132 ident: Union[Any, Tuple[Any, ...]] = None,
2133 *,
2134 instance: Optional[Any] = None,
2135 row: Optional[Union[Row[Any], RowMapping]] = None,
2136 identity_token: Optional[Any] = None,
2137 ) -> _IdentityKeyType[Any]:
2138 r"""Return an identity key.
2139
2140 .. container:: class_bases
2141
2142 Proxied for the :class:`_orm.Session` class on
2143 behalf of the :class:`_orm.scoping.scoped_session` class.
2144
2145 This is an alias of :func:`.util.identity_key`.
2146
2147
2148 """ # noqa: E501
2149
2150 return Session.identity_key(
2151 class_=class_,
2152 ident=ident,
2153 instance=instance,
2154 row=row,
2155 identity_token=identity_token,
2156 )
2157
2158 # END PROXY METHODS scoped_session
2159
2160
2161ScopedSession = scoped_session
2162"""Old name for backwards compatibility."""