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