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