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