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