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