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 = False,
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
1052 :param with_for_update: optional boolean ``True`` indicating FOR UPDATE
1053 should be used, or may be a dictionary containing flags to
1054 indicate a more specific set of FOR UPDATE flags for the SELECT;
1055 flags should match the parameters of
1056 :meth:`_query.Query.with_for_update`.
1057 Supersedes the :paramref:`.Session.refresh.lockmode` parameter.
1058
1059 :param execution_options: optional dictionary of execution options,
1060 which will be associated with the query execution if one is emitted.
1061 This dictionary can provide a subset of the options that are
1062 accepted by :meth:`_engine.Connection.execution_options`, and may
1063 also provide additional options understood only in an ORM context.
1064
1065 .. versionadded:: 1.4.29
1066
1067 .. seealso::
1068
1069 :ref:`orm_queryguide_execution_options` - ORM-specific execution
1070 options
1071
1072 :param bind_arguments: dictionary of additional arguments to determine
1073 the bind. May include "mapper", "bind", or other custom arguments.
1074 Contents of this dictionary are passed to the
1075 :meth:`.Session.get_bind` method.
1076
1077 .. versionadded:: 2.0.0rc1
1078
1079 :return: The object instance, or ``None``.
1080
1081
1082 """ # noqa: E501
1083
1084 return self._proxied.get(
1085 entity,
1086 ident,
1087 options=options,
1088 populate_existing=populate_existing,
1089 with_for_update=with_for_update,
1090 identity_token=identity_token,
1091 execution_options=execution_options,
1092 bind_arguments=bind_arguments,
1093 )
1094
1095 def get_one(
1096 self,
1097 entity: _EntityBindKey[_O],
1098 ident: _PKIdentityArgument,
1099 *,
1100 options: Optional[Sequence[ORMOption]] = None,
1101 populate_existing: bool = False,
1102 with_for_update: ForUpdateParameter = None,
1103 identity_token: Optional[Any] = None,
1104 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1105 bind_arguments: Optional[_BindArguments] = None,
1106 ) -> _O:
1107 r"""Return exactly one instance based on the given primary key
1108 identifier, or raise an exception if not found.
1109
1110 .. container:: class_bases
1111
1112 Proxied for the :class:`_orm.Session` class on
1113 behalf of the :class:`_orm.scoping.scoped_session` class.
1114
1115 Raises :class:`_exc.NoResultFound` if the query selects no rows.
1116
1117 For a detailed documentation of the arguments see the
1118 method :meth:`.Session.get`.
1119
1120 .. versionadded:: 2.0.22
1121
1122 :return: The object instance.
1123
1124 .. seealso::
1125
1126 :meth:`.Session.get` - equivalent method that instead
1127 returns ``None`` if no row was found with the provided primary
1128 key
1129
1130
1131 """ # noqa: E501
1132
1133 return self._proxied.get_one(
1134 entity,
1135 ident,
1136 options=options,
1137 populate_existing=populate_existing,
1138 with_for_update=with_for_update,
1139 identity_token=identity_token,
1140 execution_options=execution_options,
1141 bind_arguments=bind_arguments,
1142 )
1143
1144 def get_bind(
1145 self,
1146 mapper: Optional[_EntityBindKey[_O]] = None,
1147 *,
1148 clause: Optional[ClauseElement] = None,
1149 bind: Optional[_SessionBind] = None,
1150 _sa_skip_events: Optional[bool] = None,
1151 _sa_skip_for_implicit_returning: bool = False,
1152 **kw: Any,
1153 ) -> Union[Engine, Connection]:
1154 r"""Return a "bind" to which this :class:`.Session` is bound.
1155
1156 .. container:: class_bases
1157
1158 Proxied for the :class:`_orm.Session` class on
1159 behalf of the :class:`_orm.scoping.scoped_session` class.
1160
1161 The "bind" is usually an instance of :class:`_engine.Engine`,
1162 except in the case where the :class:`.Session` has been
1163 explicitly bound directly to a :class:`_engine.Connection`.
1164
1165 For a multiply-bound or unbound :class:`.Session`, the
1166 ``mapper`` or ``clause`` arguments are used to determine the
1167 appropriate bind to return.
1168
1169 Note that the "mapper" argument is usually present
1170 when :meth:`.Session.get_bind` is called via an ORM
1171 operation such as a :meth:`.Session.query`, each
1172 individual INSERT/UPDATE/DELETE operation within a
1173 :meth:`.Session.flush`, call, etc.
1174
1175 The order of resolution is:
1176
1177 1. if mapper given and :paramref:`.Session.binds` is present,
1178 locate a bind based first on the mapper in use, then
1179 on the mapped class in use, then on any base classes that are
1180 present in the ``__mro__`` of the mapped class, from more specific
1181 superclasses to more general.
1182 2. if clause given and ``Session.binds`` is present,
1183 locate a bind based on :class:`_schema.Table` objects
1184 found in the given clause present in ``Session.binds``.
1185 3. if ``Session.binds`` is present, return that.
1186 4. if clause given, attempt to return a bind
1187 linked to the :class:`_schema.MetaData` ultimately
1188 associated with the clause.
1189 5. if mapper given, attempt to return a bind
1190 linked to the :class:`_schema.MetaData` ultimately
1191 associated with the :class:`_schema.Table` or other
1192 selectable to which the mapper is mapped.
1193 6. No bind can be found, :exc:`~sqlalchemy.exc.UnboundExecutionError`
1194 is raised.
1195
1196 Note that the :meth:`.Session.get_bind` method can be overridden on
1197 a user-defined subclass of :class:`.Session` to provide any kind
1198 of bind resolution scheme. See the example at
1199 :ref:`session_custom_partitioning`.
1200
1201 :param mapper:
1202 Optional mapped class or corresponding :class:`_orm.Mapper` instance.
1203 The bind can be derived from a :class:`_orm.Mapper` first by
1204 consulting the "binds" map associated with this :class:`.Session`,
1205 and secondly by consulting the :class:`_schema.MetaData` associated
1206 with the :class:`_schema.Table` to which the :class:`_orm.Mapper` is
1207 mapped for a bind.
1208
1209 :param clause:
1210 A :class:`_expression.ClauseElement` (i.e.
1211 :func:`_expression.select`,
1212 :func:`_expression.text`,
1213 etc.). If the ``mapper`` argument is not present or could not
1214 produce a bind, the given expression construct will be searched
1215 for a bound element, typically a :class:`_schema.Table`
1216 associated with
1217 bound :class:`_schema.MetaData`.
1218
1219 .. seealso::
1220
1221 :ref:`session_partitioning`
1222
1223 :paramref:`.Session.binds`
1224
1225 :meth:`.Session.bind_mapper`
1226
1227 :meth:`.Session.bind_table`
1228
1229
1230 """ # noqa: E501
1231
1232 return self._proxied.get_bind(
1233 mapper=mapper,
1234 clause=clause,
1235 bind=bind,
1236 _sa_skip_events=_sa_skip_events,
1237 _sa_skip_for_implicit_returning=_sa_skip_for_implicit_returning,
1238 **kw,
1239 )
1240
1241 def is_modified(
1242 self, instance: object, include_collections: bool = True
1243 ) -> bool:
1244 r"""Return ``True`` if the given instance has locally
1245 modified attributes.
1246
1247 .. container:: class_bases
1248
1249 Proxied for the :class:`_orm.Session` class on
1250 behalf of the :class:`_orm.scoping.scoped_session` class.
1251
1252 This method retrieves the history for each instrumented
1253 attribute on the instance and performs a comparison of the current
1254 value to its previously flushed or committed value, if any.
1255
1256 It is in effect a more expensive and accurate
1257 version of checking for the given instance in the
1258 :attr:`.Session.dirty` collection; a full test for
1259 each attribute's net "dirty" status is performed.
1260
1261 E.g.::
1262
1263 return session.is_modified(someobject)
1264
1265 A few caveats to this method apply:
1266
1267 * Instances present in the :attr:`.Session.dirty` collection may
1268 report ``False`` when tested with this method. This is because
1269 the object may have received change events via attribute mutation,
1270 thus placing it in :attr:`.Session.dirty`, but ultimately the state
1271 is the same as that loaded from the database, resulting in no net
1272 change here.
1273 * Scalar attributes may not have recorded the previously set
1274 value when a new value was applied, if the attribute was not loaded,
1275 or was expired, at the time the new value was received - in these
1276 cases, the attribute is assumed to have a change, even if there is
1277 ultimately no net change against its database value. SQLAlchemy in
1278 most cases does not need the "old" value when a set event occurs, so
1279 it skips the expense of a SQL call if the old value isn't present,
1280 based on the assumption that an UPDATE of the scalar value is
1281 usually needed, and in those few cases where it isn't, is less
1282 expensive on average than issuing a defensive SELECT.
1283
1284 The "old" value is fetched unconditionally upon set only if the
1285 attribute container has the ``active_history`` flag set to ``True``.
1286 This flag is set typically for primary key attributes and scalar
1287 object references that are not a simple many-to-one. To set this
1288 flag for any arbitrary mapped column, use the ``active_history``
1289 argument with :func:`.column_property`.
1290
1291 :param instance: mapped instance to be tested for pending changes.
1292 :param include_collections: Indicates if multivalued collections
1293 should be included in the operation. Setting this to ``False`` is a
1294 way to detect only local-column based properties (i.e. scalar columns
1295 or many-to-one foreign keys) that would result in an UPDATE for this
1296 instance upon flush.
1297
1298
1299 """ # noqa: E501
1300
1301 return self._proxied.is_modified(
1302 instance, include_collections=include_collections
1303 )
1304
1305 def bulk_save_objects(
1306 self,
1307 objects: Iterable[object],
1308 return_defaults: bool = False,
1309 update_changed_only: bool = True,
1310 preserve_order: bool = True,
1311 ) -> None:
1312 r"""Perform a bulk save of the given list of objects.
1313
1314 .. container:: class_bases
1315
1316 Proxied for the :class:`_orm.Session` class on
1317 behalf of the :class:`_orm.scoping.scoped_session` class.
1318
1319 .. legacy::
1320
1321 This method is a legacy feature as of the 2.0 series of
1322 SQLAlchemy. For modern bulk INSERT and UPDATE, see
1323 the sections :ref:`orm_queryguide_bulk_insert` and
1324 :ref:`orm_queryguide_bulk_update`.
1325
1326 For general INSERT and UPDATE of existing ORM mapped objects,
1327 prefer standard :term:`unit of work` data management patterns,
1328 introduced in the :ref:`unified_tutorial` at
1329 :ref:`tutorial_orm_data_manipulation`. SQLAlchemy 2.0
1330 now uses :ref:`engine_insertmanyvalues` with modern dialects
1331 which solves previous issues of bulk INSERT slowness.
1332
1333 :param objects: a sequence of mapped object instances. The mapped
1334 objects are persisted as is, and are **not** associated with the
1335 :class:`.Session` afterwards.
1336
1337 For each object, whether the object is sent as an INSERT or an
1338 UPDATE is dependent on the same rules used by the :class:`.Session`
1339 in traditional operation; if the object has the
1340 :attr:`.InstanceState.key`
1341 attribute set, then the object is assumed to be "detached" and
1342 will result in an UPDATE. Otherwise, an INSERT is used.
1343
1344 In the case of an UPDATE, statements are grouped based on which
1345 attributes have changed, and are thus to be the subject of each
1346 SET clause. If ``update_changed_only`` is False, then all
1347 attributes present within each object are applied to the UPDATE
1348 statement, which may help in allowing the statements to be grouped
1349 together into a larger executemany(), and will also reduce the
1350 overhead of checking history on attributes.
1351
1352 :param return_defaults: when True, rows that are missing values which
1353 generate defaults, namely integer primary key defaults and sequences,
1354 will be inserted **one at a time**, so that the primary key value
1355 is available. In particular this will allow joined-inheritance
1356 and other multi-table mappings to insert correctly without the need
1357 to provide primary key values ahead of time; however,
1358 :paramref:`.Session.bulk_save_objects.return_defaults` **greatly
1359 reduces the performance gains** of the method overall. It is strongly
1360 advised to please use the standard :meth:`_orm.Session.add_all`
1361 approach.
1362
1363 :param update_changed_only: when True, UPDATE statements are rendered
1364 based on those attributes in each state that have logged changes.
1365 When False, all attributes present are rendered into the SET clause
1366 with the exception of primary key attributes.
1367
1368 :param preserve_order: when True, the order of inserts and updates
1369 matches exactly the order in which the objects are given. When
1370 False, common types of objects are grouped into inserts
1371 and updates, to allow for more batching opportunities.
1372
1373 .. seealso::
1374
1375 :doc:`queryguide/dml`
1376
1377 :meth:`.Session.bulk_insert_mappings`
1378
1379 :meth:`.Session.bulk_update_mappings`
1380
1381
1382 """ # noqa: E501
1383
1384 return self._proxied.bulk_save_objects(
1385 objects,
1386 return_defaults=return_defaults,
1387 update_changed_only=update_changed_only,
1388 preserve_order=preserve_order,
1389 )
1390
1391 def bulk_insert_mappings(
1392 self,
1393 mapper: Mapper[Any],
1394 mappings: Iterable[Dict[str, Any]],
1395 return_defaults: bool = False,
1396 render_nulls: bool = False,
1397 ) -> None:
1398 r"""Perform a bulk insert of the given list of mapping dictionaries.
1399
1400 .. container:: class_bases
1401
1402 Proxied for the :class:`_orm.Session` class on
1403 behalf of the :class:`_orm.scoping.scoped_session` class.
1404
1405 .. legacy::
1406
1407 This method is a legacy feature as of the 2.0 series of
1408 SQLAlchemy. For modern bulk INSERT and UPDATE, see
1409 the sections :ref:`orm_queryguide_bulk_insert` and
1410 :ref:`orm_queryguide_bulk_update`. The 2.0 API shares
1411 implementation details with this method and adds new features
1412 as well.
1413
1414 :param mapper: a mapped class, or the actual :class:`_orm.Mapper`
1415 object,
1416 representing the single kind of object represented within the mapping
1417 list.
1418
1419 :param mappings: a sequence of dictionaries, each one containing the
1420 state of the mapped row to be inserted, in terms of the attribute
1421 names on the mapped class. If the mapping refers to multiple tables,
1422 such as a joined-inheritance mapping, each dictionary must contain all
1423 keys to be populated into all tables.
1424
1425 :param return_defaults: when True, the INSERT process will be altered
1426 to ensure that newly generated primary key values will be fetched.
1427 The rationale for this parameter is typically to enable
1428 :ref:`Joined Table Inheritance <joined_inheritance>` mappings to
1429 be bulk inserted.
1430
1431 .. note:: for backends that don't support RETURNING, the
1432 :paramref:`_orm.Session.bulk_insert_mappings.return_defaults`
1433 parameter can significantly decrease performance as INSERT
1434 statements can no longer be batched. See
1435 :ref:`engine_insertmanyvalues`
1436 for background on which backends are affected.
1437
1438 :param render_nulls: When True, a value of ``None`` will result
1439 in a NULL value being included in the INSERT statement, rather
1440 than the column being omitted from the INSERT. This allows all
1441 the rows being INSERTed to have the identical set of columns which
1442 allows the full set of rows to be batched to the DBAPI. Normally,
1443 each column-set that contains a different combination of NULL values
1444 than the previous row must omit a different series of columns from
1445 the rendered INSERT statement, which means it must be emitted as a
1446 separate statement. By passing this flag, the full set of rows
1447 are guaranteed to be batchable into one batch; the cost however is
1448 that server-side defaults which are invoked by an omitted column will
1449 be skipped, so care must be taken to ensure that these are not
1450 necessary.
1451
1452 .. warning::
1453
1454 When this flag is set, **server side default SQL values will
1455 not be invoked** for those columns that are inserted as NULL;
1456 the NULL value will be sent explicitly. Care must be taken
1457 to ensure that no server-side default functions need to be
1458 invoked for the operation as a whole.
1459
1460 .. seealso::
1461
1462 :doc:`queryguide/dml`
1463
1464 :meth:`.Session.bulk_save_objects`
1465
1466 :meth:`.Session.bulk_update_mappings`
1467
1468
1469 """ # noqa: E501
1470
1471 return self._proxied.bulk_insert_mappings(
1472 mapper,
1473 mappings,
1474 return_defaults=return_defaults,
1475 render_nulls=render_nulls,
1476 )
1477
1478 def bulk_update_mappings(
1479 self, mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]]
1480 ) -> None:
1481 r"""Perform a bulk update of the given list of mapping dictionaries.
1482
1483 .. container:: class_bases
1484
1485 Proxied for the :class:`_orm.Session` class on
1486 behalf of the :class:`_orm.scoping.scoped_session` class.
1487
1488 .. legacy::
1489
1490 This method is a legacy feature as of the 2.0 series of
1491 SQLAlchemy. For modern bulk INSERT and UPDATE, see
1492 the sections :ref:`orm_queryguide_bulk_insert` and
1493 :ref:`orm_queryguide_bulk_update`. The 2.0 API shares
1494 implementation details with this method and adds new features
1495 as well.
1496
1497 :param mapper: a mapped class, or the actual :class:`_orm.Mapper`
1498 object,
1499 representing the single kind of object represented within the mapping
1500 list.
1501
1502 :param mappings: a sequence of dictionaries, each one containing the
1503 state of the mapped row to be updated, in terms of the attribute names
1504 on the mapped class. If the mapping refers to multiple tables, such
1505 as a joined-inheritance mapping, each dictionary may contain keys
1506 corresponding to all tables. All those keys which are present and
1507 are not part of the primary key are applied to the SET clause of the
1508 UPDATE statement; the primary key values, which are required, are
1509 applied to the WHERE clause.
1510
1511
1512 .. seealso::
1513
1514 :doc:`queryguide/dml`
1515
1516 :meth:`.Session.bulk_insert_mappings`
1517
1518 :meth:`.Session.bulk_save_objects`
1519
1520
1521 """ # noqa: E501
1522
1523 return self._proxied.bulk_update_mappings(mapper, mappings)
1524
1525 def merge(
1526 self,
1527 instance: _O,
1528 *,
1529 load: bool = True,
1530 options: Optional[Sequence[ORMOption]] = None,
1531 ) -> _O:
1532 r"""Copy the state of a given instance into a corresponding instance
1533 within this :class:`.Session`.
1534
1535 .. container:: class_bases
1536
1537 Proxied for the :class:`_orm.Session` class on
1538 behalf of the :class:`_orm.scoping.scoped_session` class.
1539
1540 :meth:`.Session.merge` examines the primary key attributes of the
1541 source instance, and attempts to reconcile it with an instance of the
1542 same primary key in the session. If not found locally, it attempts
1543 to load the object from the database based on primary key, and if
1544 none can be located, creates a new instance. The state of each
1545 attribute on the source instance is then copied to the target
1546 instance. The resulting target instance is then returned by the
1547 method; the original source instance is left unmodified, and
1548 un-associated with the :class:`.Session` if not already.
1549
1550 This operation cascades to associated instances if the association is
1551 mapped with ``cascade="merge"``.
1552
1553 See :ref:`unitofwork_merging` for a detailed discussion of merging.
1554
1555 :param instance: Instance to be merged.
1556 :param load: Boolean, when False, :meth:`.merge` switches into
1557 a "high performance" mode which causes it to forego emitting history
1558 events as well as all database access. This flag is used for
1559 cases such as transferring graphs of objects into a :class:`.Session`
1560 from a second level cache, or to transfer just-loaded objects
1561 into the :class:`.Session` owned by a worker thread or process
1562 without re-querying the database.
1563
1564 The ``load=False`` use case adds the caveat that the given
1565 object has to be in a "clean" state, that is, has no pending changes
1566 to be flushed - even if the incoming object is detached from any
1567 :class:`.Session`. This is so that when
1568 the merge operation populates local attributes and
1569 cascades to related objects and
1570 collections, the values can be "stamped" onto the
1571 target object as is, without generating any history or attribute
1572 events, and without the need to reconcile the incoming data with
1573 any existing related objects or collections that might not
1574 be loaded. The resulting objects from ``load=False`` are always
1575 produced as "clean", so it is only appropriate that the given objects
1576 should be "clean" as well, else this suggests a mis-use of the
1577 method.
1578 :param options: optional sequence of loader options which will be
1579 applied to the :meth:`_orm.Session.get` method when the merge
1580 operation loads the existing version of the object from the database.
1581
1582 .. versionadded:: 1.4.24
1583
1584
1585 .. seealso::
1586
1587 :func:`.make_transient_to_detached` - provides for an alternative
1588 means of "merging" a single object into the :class:`.Session`
1589
1590 :meth:`.Session.merge_all` - multiple instance version
1591
1592
1593 """ # noqa: E501
1594
1595 return self._proxied.merge(instance, load=load, options=options)
1596
1597 def merge_all(
1598 self,
1599 instances: Iterable[_O],
1600 *,
1601 load: bool = True,
1602 options: Optional[Sequence[ORMOption]] = None,
1603 ) -> Sequence[_O]:
1604 r"""Calls :meth:`.Session.merge` on multiple instances.
1605
1606 .. container:: class_bases
1607
1608 Proxied for the :class:`_orm.Session` class on
1609 behalf of the :class:`_orm.scoping.scoped_session` class.
1610
1611 .. seealso::
1612
1613 :meth:`.Session.merge` - main documentation on merge
1614
1615 .. versionadded:: 2.1
1616
1617
1618 """ # noqa: E501
1619
1620 return self._proxied.merge_all(instances, load=load, options=options)
1621
1622 @overload
1623 def query(self, _entity: _EntityType[_O]) -> Query[_O]: ...
1624
1625 @overload
1626 def query(
1627 self, _colexpr: TypedColumnsClauseRole[_T]
1628 ) -> RowReturningQuery[_T]: ...
1629
1630 # START OVERLOADED FUNCTIONS self.query RowReturningQuery 2-8
1631
1632 # code within this block is **programmatically,
1633 # statically generated** by tools/generate_tuple_map_overloads.py
1634
1635 @overload
1636 def query(
1637 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], /
1638 ) -> RowReturningQuery[_T0, _T1]: ...
1639
1640 @overload
1641 def query(
1642 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2], /
1643 ) -> RowReturningQuery[_T0, _T1, _T2]: ...
1644
1645 @overload
1646 def query(
1647 self,
1648 __ent0: _TCCA[_T0],
1649 __ent1: _TCCA[_T1],
1650 __ent2: _TCCA[_T2],
1651 __ent3: _TCCA[_T3],
1652 /,
1653 ) -> RowReturningQuery[_T0, _T1, _T2, _T3]: ...
1654
1655 @overload
1656 def query(
1657 self,
1658 __ent0: _TCCA[_T0],
1659 __ent1: _TCCA[_T1],
1660 __ent2: _TCCA[_T2],
1661 __ent3: _TCCA[_T3],
1662 __ent4: _TCCA[_T4],
1663 /,
1664 ) -> RowReturningQuery[_T0, _T1, _T2, _T3, _T4]: ...
1665
1666 @overload
1667 def query(
1668 self,
1669 __ent0: _TCCA[_T0],
1670 __ent1: _TCCA[_T1],
1671 __ent2: _TCCA[_T2],
1672 __ent3: _TCCA[_T3],
1673 __ent4: _TCCA[_T4],
1674 __ent5: _TCCA[_T5],
1675 /,
1676 ) -> RowReturningQuery[_T0, _T1, _T2, _T3, _T4, _T5]: ...
1677
1678 @overload
1679 def query(
1680 self,
1681 __ent0: _TCCA[_T0],
1682 __ent1: _TCCA[_T1],
1683 __ent2: _TCCA[_T2],
1684 __ent3: _TCCA[_T3],
1685 __ent4: _TCCA[_T4],
1686 __ent5: _TCCA[_T5],
1687 __ent6: _TCCA[_T6],
1688 /,
1689 ) -> RowReturningQuery[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ...
1690
1691 @overload
1692 def query(
1693 self,
1694 __ent0: _TCCA[_T0],
1695 __ent1: _TCCA[_T1],
1696 __ent2: _TCCA[_T2],
1697 __ent3: _TCCA[_T3],
1698 __ent4: _TCCA[_T4],
1699 __ent5: _TCCA[_T5],
1700 __ent6: _TCCA[_T6],
1701 __ent7: _TCCA[_T7],
1702 /,
1703 *entities: _ColumnsClauseArgument[Any],
1704 ) -> RowReturningQuery[
1705 _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny]
1706 ]: ...
1707
1708 # END OVERLOADED FUNCTIONS self.query
1709
1710 @overload
1711 def query(
1712 self, *entities: _ColumnsClauseArgument[Any], **kwargs: Any
1713 ) -> Query[Any]: ...
1714
1715 def query(
1716 self, *entities: _ColumnsClauseArgument[Any], **kwargs: Any
1717 ) -> Query[Any]:
1718 r"""Return a new :class:`_query.Query` object corresponding to this
1719 :class:`_orm.Session`.
1720
1721 .. container:: class_bases
1722
1723 Proxied for the :class:`_orm.Session` class on
1724 behalf of the :class:`_orm.scoping.scoped_session` class.
1725
1726 Note that the :class:`_query.Query` object is legacy as of
1727 SQLAlchemy 2.0; the :func:`_sql.select` construct is now used
1728 to construct ORM queries.
1729
1730 .. seealso::
1731
1732 :ref:`unified_tutorial`
1733
1734 :ref:`queryguide_toplevel`
1735
1736 :ref:`query_api_toplevel` - legacy API doc
1737
1738
1739 """ # noqa: E501
1740
1741 return self._proxied.query(*entities, **kwargs)
1742
1743 def refresh(
1744 self,
1745 instance: object,
1746 attribute_names: Optional[Iterable[str]] = None,
1747 with_for_update: ForUpdateParameter = None,
1748 ) -> None:
1749 r"""Expire and refresh attributes on the given instance.
1750
1751 .. container:: class_bases
1752
1753 Proxied for the :class:`_orm.Session` class on
1754 behalf of the :class:`_orm.scoping.scoped_session` class.
1755
1756 The selected attributes will first be expired as they would when using
1757 :meth:`_orm.Session.expire`; then a SELECT statement will be issued to
1758 the database to refresh column-oriented attributes with the current
1759 value available in the current transaction.
1760
1761 :func:`_orm.relationship` oriented attributes will also be immediately
1762 loaded if they were already eagerly loaded on the object, using the
1763 same eager loading strategy that they were loaded with originally.
1764
1765 .. versionadded:: 1.4 - the :meth:`_orm.Session.refresh` method
1766 can also refresh eagerly loaded attributes.
1767
1768 :func:`_orm.relationship` oriented attributes that would normally
1769 load using the ``select`` (or "lazy") loader strategy will also
1770 load **if they are named explicitly in the attribute_names
1771 collection**, emitting a SELECT statement for the attribute using the
1772 ``immediate`` loader strategy. If lazy-loaded relationships are not
1773 named in :paramref:`_orm.Session.refresh.attribute_names`, then
1774 they remain as "lazy loaded" attributes and are not implicitly
1775 refreshed.
1776
1777 .. versionchanged:: 2.0.4 The :meth:`_orm.Session.refresh` method
1778 will now refresh lazy-loaded :func:`_orm.relationship` oriented
1779 attributes for those which are named explicitly in the
1780 :paramref:`_orm.Session.refresh.attribute_names` collection.
1781
1782 .. tip::
1783
1784 While the :meth:`_orm.Session.refresh` method is capable of
1785 refreshing both column and relationship oriented attributes, its
1786 primary focus is on refreshing of local column-oriented attributes
1787 on a single instance. For more open ended "refresh" functionality,
1788 including the ability to refresh the attributes on many objects at
1789 once while having explicit control over relationship loader
1790 strategies, use the
1791 :ref:`populate existing <orm_queryguide_populate_existing>` feature
1792 instead.
1793
1794 Note that a highly isolated transaction will return the same values as
1795 were previously read in that same transaction, regardless of changes
1796 in database state outside of that transaction. Refreshing
1797 attributes usually only makes sense at the start of a transaction
1798 where database rows have not yet been accessed.
1799
1800 :param attribute_names: optional. An iterable collection of
1801 string attribute names indicating a subset of attributes to
1802 be refreshed.
1803
1804 :param with_for_update: optional boolean ``True`` indicating FOR UPDATE
1805 should be used, or may be a dictionary containing flags to
1806 indicate a more specific set of FOR UPDATE flags for the SELECT;
1807 flags should match the parameters of
1808 :meth:`_query.Query.with_for_update`.
1809 Supersedes the :paramref:`.Session.refresh.lockmode` parameter.
1810
1811 .. seealso::
1812
1813 :ref:`session_expire` - introductory material
1814
1815 :meth:`.Session.expire`
1816
1817 :meth:`.Session.expire_all`
1818
1819 :ref:`orm_queryguide_populate_existing` - allows any ORM query
1820 to refresh objects as they would be loaded normally.
1821
1822
1823 """ # noqa: E501
1824
1825 return self._proxied.refresh(
1826 instance,
1827 attribute_names=attribute_names,
1828 with_for_update=with_for_update,
1829 )
1830
1831 def rollback(self) -> None:
1832 r"""Rollback the current transaction in progress.
1833
1834 .. container:: class_bases
1835
1836 Proxied for the :class:`_orm.Session` class on
1837 behalf of the :class:`_orm.scoping.scoped_session` class.
1838
1839 If no transaction is in progress, this method is a pass-through.
1840
1841 The method always rolls back
1842 the topmost database transaction, discarding any nested
1843 transactions that may be in progress.
1844
1845 .. seealso::
1846
1847 :ref:`session_rollback`
1848
1849 :ref:`unitofwork_transaction`
1850
1851
1852 """ # noqa: E501
1853
1854 return self._proxied.rollback()
1855
1856 @overload
1857 def scalar(
1858 self,
1859 statement: TypedReturnsRows[Never],
1860 params: Optional[_CoreSingleExecuteParams] = None,
1861 *,
1862 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1863 bind_arguments: Optional[_BindArguments] = None,
1864 **kw: Any,
1865 ) -> Optional[Any]: ...
1866
1867 @overload
1868 def scalar(
1869 self,
1870 statement: TypedReturnsRows[_T],
1871 params: Optional[_CoreSingleExecuteParams] = None,
1872 *,
1873 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1874 bind_arguments: Optional[_BindArguments] = None,
1875 **kw: Any,
1876 ) -> Optional[_T]: ...
1877
1878 @overload
1879 def scalar(
1880 self,
1881 statement: Executable,
1882 params: Optional[_CoreSingleExecuteParams] = None,
1883 *,
1884 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1885 bind_arguments: Optional[_BindArguments] = None,
1886 **kw: Any,
1887 ) -> Any: ...
1888
1889 def scalar(
1890 self,
1891 statement: Executable,
1892 params: Optional[_CoreSingleExecuteParams] = None,
1893 *,
1894 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1895 bind_arguments: Optional[_BindArguments] = None,
1896 **kw: Any,
1897 ) -> Any:
1898 r"""Execute a statement and return a scalar result.
1899
1900 .. container:: class_bases
1901
1902 Proxied for the :class:`_orm.Session` class on
1903 behalf of the :class:`_orm.scoping.scoped_session` class.
1904
1905 Usage and parameters are the same as that of
1906 :meth:`_orm.Session.execute`; the return result is a scalar Python
1907 value.
1908
1909
1910 """ # noqa: E501
1911
1912 return self._proxied.scalar(
1913 statement,
1914 params=params,
1915 execution_options=execution_options,
1916 bind_arguments=bind_arguments,
1917 **kw,
1918 )
1919
1920 @overload
1921 def scalars(
1922 self,
1923 statement: TypedReturnsRows[_T],
1924 params: Optional[_CoreAnyExecuteParams] = None,
1925 *,
1926 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1927 bind_arguments: Optional[_BindArguments] = None,
1928 **kw: Any,
1929 ) -> ScalarResult[_T]: ...
1930
1931 @overload
1932 def scalars(
1933 self,
1934 statement: Executable,
1935 params: Optional[_CoreAnyExecuteParams] = None,
1936 *,
1937 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1938 bind_arguments: Optional[_BindArguments] = None,
1939 **kw: Any,
1940 ) -> ScalarResult[Any]: ...
1941
1942 def scalars(
1943 self,
1944 statement: Executable,
1945 params: Optional[_CoreAnyExecuteParams] = None,
1946 *,
1947 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1948 bind_arguments: Optional[_BindArguments] = None,
1949 **kw: Any,
1950 ) -> ScalarResult[Any]:
1951 r"""Execute a statement and return the results as scalars.
1952
1953 .. container:: class_bases
1954
1955 Proxied for the :class:`_orm.Session` class on
1956 behalf of the :class:`_orm.scoping.scoped_session` class.
1957
1958 Usage and parameters are the same as that of
1959 :meth:`_orm.Session.execute`; the return result is a
1960 :class:`_result.ScalarResult` filtering object which
1961 will return single elements rather than :class:`_row.Row` objects.
1962
1963 :return: a :class:`_result.ScalarResult` object
1964
1965 .. versionadded:: 1.4.24 Added :meth:`_orm.Session.scalars`
1966
1967 .. versionadded:: 1.4.26 Added :meth:`_orm.scoped_session.scalars`
1968
1969 .. seealso::
1970
1971 :ref:`orm_queryguide_select_orm_entities` - contrasts the behavior
1972 of :meth:`_orm.Session.execute` to :meth:`_orm.Session.scalars`
1973
1974
1975 """ # noqa: E501
1976
1977 return self._proxied.scalars(
1978 statement,
1979 params=params,
1980 execution_options=execution_options,
1981 bind_arguments=bind_arguments,
1982 **kw,
1983 )
1984
1985 @property
1986 def bind(self) -> Optional[Union[Engine, Connection]]:
1987 r"""Proxy for the :attr:`_orm.Session.bind` attribute
1988 on behalf of the :class:`_orm.scoping.scoped_session` class.
1989
1990 """ # noqa: E501
1991
1992 return self._proxied.bind
1993
1994 @bind.setter
1995 def bind(self, attr: Optional[Union[Engine, Connection]]) -> None:
1996 self._proxied.bind = attr
1997
1998 @property
1999 def dirty(self) -> Any:
2000 r"""The set of all persistent instances considered dirty.
2001
2002 .. container:: class_bases
2003
2004 Proxied for the :class:`_orm.Session` class
2005 on behalf of the :class:`_orm.scoping.scoped_session` class.
2006
2007 E.g.::
2008
2009 some_mapped_object in session.dirty
2010
2011 Instances are considered dirty when they were modified but not
2012 deleted.
2013
2014 Note that this 'dirty' calculation is 'optimistic'; most
2015 attribute-setting or collection modification operations will
2016 mark an instance as 'dirty' and place it in this set, even if
2017 there is no net change to the attribute's value. At flush
2018 time, the value of each attribute is compared to its
2019 previously saved value, and if there's no net change, no SQL
2020 operation will occur (this is a more expensive operation so
2021 it's only done at flush time).
2022
2023 To check if an instance has actionable net changes to its
2024 attributes, use the :meth:`.Session.is_modified` method.
2025
2026
2027 """ # noqa: E501
2028
2029 return self._proxied.dirty
2030
2031 @property
2032 def deleted(self) -> Any:
2033 r"""The set of all instances marked as 'deleted' within this ``Session``
2034
2035 .. container:: class_bases
2036
2037 Proxied for the :class:`_orm.Session` class
2038 on behalf of the :class:`_orm.scoping.scoped_session` class.
2039
2040 """ # noqa: E501
2041
2042 return self._proxied.deleted
2043
2044 @property
2045 def new(self) -> Any:
2046 r"""The set of all instances marked as 'new' within this ``Session``.
2047
2048 .. container:: class_bases
2049
2050 Proxied for the :class:`_orm.Session` class
2051 on behalf of the :class:`_orm.scoping.scoped_session` class.
2052
2053 """ # noqa: E501
2054
2055 return self._proxied.new
2056
2057 @property
2058 def identity_map(self) -> IdentityMap:
2059 r"""Proxy for the :attr:`_orm.Session.identity_map` attribute
2060 on behalf of the :class:`_orm.scoping.scoped_session` class.
2061
2062 """ # noqa: E501
2063
2064 return self._proxied.identity_map
2065
2066 @identity_map.setter
2067 def identity_map(self, attr: IdentityMap) -> None:
2068 self._proxied.identity_map = attr
2069
2070 @property
2071 def is_active(self) -> Any:
2072 r"""True if this :class:`.Session` not in "partial rollback" state.
2073
2074 .. container:: class_bases
2075
2076 Proxied for the :class:`_orm.Session` class
2077 on behalf of the :class:`_orm.scoping.scoped_session` class.
2078
2079 .. versionchanged:: 1.4 The :class:`_orm.Session` no longer begins
2080 a new transaction immediately, so this attribute will be False
2081 when the :class:`_orm.Session` is first instantiated.
2082
2083 "partial rollback" state typically indicates that the flush process
2084 of the :class:`_orm.Session` has failed, and that the
2085 :meth:`_orm.Session.rollback` method must be emitted in order to
2086 fully roll back the transaction.
2087
2088 If this :class:`_orm.Session` is not in a transaction at all, the
2089 :class:`_orm.Session` will autobegin when it is first used, so in this
2090 case :attr:`_orm.Session.is_active` will return True.
2091
2092 Otherwise, if this :class:`_orm.Session` is within a transaction,
2093 and that transaction has not been rolled back internally, the
2094 :attr:`_orm.Session.is_active` will also return True.
2095
2096 .. seealso::
2097
2098 :ref:`faq_session_rollback`
2099
2100 :meth:`_orm.Session.in_transaction`
2101
2102
2103 """ # noqa: E501
2104
2105 return self._proxied.is_active
2106
2107 @property
2108 def autoflush(self) -> bool:
2109 r"""Proxy for the :attr:`_orm.Session.autoflush` attribute
2110 on behalf of the :class:`_orm.scoping.scoped_session` class.
2111
2112 """ # noqa: E501
2113
2114 return self._proxied.autoflush
2115
2116 @autoflush.setter
2117 def autoflush(self, attr: bool) -> None:
2118 self._proxied.autoflush = attr
2119
2120 @property
2121 def no_autoflush(self) -> Any:
2122 r"""Return a context manager that disables autoflush.
2123
2124 .. container:: class_bases
2125
2126 Proxied for the :class:`_orm.Session` class
2127 on behalf of the :class:`_orm.scoping.scoped_session` class.
2128
2129 e.g.::
2130
2131 with session.no_autoflush:
2132
2133 some_object = SomeClass()
2134 session.add(some_object)
2135 # won't autoflush
2136 some_object.related_thing = session.query(SomeRelated).first()
2137
2138 Operations that proceed within the ``with:`` block
2139 will not be subject to flushes occurring upon query
2140 access. This is useful when initializing a series
2141 of objects which involve existing database queries,
2142 where the uncompleted object should not yet be flushed.
2143
2144
2145 """ # noqa: E501
2146
2147 return self._proxied.no_autoflush
2148
2149 @property
2150 def info(self) -> Any:
2151 r"""A user-modifiable dictionary.
2152
2153 .. container:: class_bases
2154
2155 Proxied for the :class:`_orm.Session` class
2156 on behalf of the :class:`_orm.scoping.scoped_session` class.
2157
2158 The initial value of this dictionary can be populated using the
2159 ``info`` argument to the :class:`.Session` constructor or
2160 :class:`.sessionmaker` constructor or factory methods. The dictionary
2161 here is always local to this :class:`.Session` and can be modified
2162 independently of all other :class:`.Session` objects.
2163
2164
2165 """ # noqa: E501
2166
2167 return self._proxied.info
2168
2169 @property
2170 def execution_options(self) -> _ExecuteOptions:
2171 r"""Proxy for the :attr:`_orm.Session.execution_options` attribute
2172 on behalf of the :class:`_orm.scoping.scoped_session` class.
2173
2174 """ # noqa: E501
2175
2176 return self._proxied.execution_options
2177
2178 @execution_options.setter
2179 def execution_options(self, attr: _ExecuteOptions) -> None:
2180 self._proxied.execution_options = attr
2181
2182 @classmethod
2183 def object_session(cls, instance: object) -> Optional[Session]:
2184 r"""Return the :class:`.Session` to which an object belongs.
2185
2186 .. container:: class_bases
2187
2188 Proxied for the :class:`_orm.Session` class on
2189 behalf of the :class:`_orm.scoping.scoped_session` class.
2190
2191 This is an alias of :func:`.object_session`.
2192
2193
2194 """ # noqa: E501
2195
2196 return Session.object_session(instance)
2197
2198 @classmethod
2199 def identity_key(
2200 cls,
2201 class_: Optional[Type[Any]] = None,
2202 ident: Union[Any, Tuple[Any, ...]] = None,
2203 *,
2204 instance: Optional[Any] = None,
2205 row: Optional[Union[Row[Unpack[TupleAny]], RowMapping]] = None,
2206 identity_token: Optional[Any] = None,
2207 ) -> _IdentityKeyType[Any]:
2208 r"""Return an identity key.
2209
2210 .. container:: class_bases
2211
2212 Proxied for the :class:`_orm.Session` class on
2213 behalf of the :class:`_orm.scoping.scoped_session` class.
2214
2215 This is an alias of :func:`.util.identity_key`.
2216
2217
2218 """ # noqa: E501
2219
2220 return Session.identity_key(
2221 class_=class_,
2222 ident=ident,
2223 instance=instance,
2224 row=row,
2225 identity_token=identity_token,
2226 )
2227
2228 # END PROXY METHODS scoped_session
2229
2230
2231ScopedSession = scoped_session
2232"""Old name for backwards compatibility."""