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