codekingpro/portable-devtools
114k
1# orm/scoping.py
2# Copyright (C) 2005-2024 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 CursorResult
53 from ..engine import Engine
54 from ..engine import Result
55 from ..engine import Row
56 from ..engine import RowMapping
57 from ..engine.interfaces import _CoreAnyExecuteParams
58 from ..engine.interfaces import _CoreSingleExecuteParams
59 from ..engine.interfaces import CoreExecuteOptionsParameter
60 from ..engine.result import ScalarResult
61 from ..sql._typing import _ColumnsClauseArgument
62 from ..sql._typing import _T0
63 from ..sql._typing import _T1
64 from ..sql._typing import _T2
65 from ..sql._typing import _T3
66 from ..sql._typing import _T4
67 from ..sql._typing import _T5
68 from ..sql._typing import _T6
69 from ..sql._typing import _T7
70 from ..sql._typing import _TypedColumnClauseArgument as _TCCA
71 from ..sql.base import Executable
72 from ..sql.dml import UpdateBase
73 from ..sql.elements import ClauseElement
74 from ..sql.roles import TypedColumnsClauseRole
75 from ..sql.selectable import ForUpdateParameter
76 from ..sql.selectable import TypedReturnsRows
77
78_T = TypeVar("_T", bound=Any)
79
80
81class QueryPropertyDescriptor(Protocol):
82 """Describes the type applied to a class-level
83 :meth:`_orm.scoped_session.query_property` attribute.
84
85 .. versionadded:: 2.0.5
86
87 """
88
89 def __get__(self, instance: Any, owner: Type[_T]) -> Query[_T]: ...
90
91
92_O = TypeVar("_O", bound=object)
93
94__all__ = ["scoped_session"]
95
96
97@create_proxy_methods(
98 Session,
99 ":class:`_orm.Session`",
100 ":class:`_orm.scoping.scoped_session`",
101 classmethods=["close_all", "object_session", "identity_key"],
102 methods=[
103 "__contains__",
104 "__iter__",
105 "add",
106 "add_all",
107 "begin",
108 "begin_nested",
109 "close",
110 "reset",
111 "commit",
112 "connection",
113 "delete",
114 "execute",
115 "expire",
116 "expire_all",
117 "expunge",
118 "expunge_all",
119 "flush",
120 "get",
121 "get_one",
122 "get_bind",
123 "is_modified",
124 "bulk_save_objects",
125 "bulk_insert_mappings",
126 "bulk_update_mappings",
127 "merge",
128 "query",
129 "refresh",
130 "rollback",
131 "scalar",
132 "scalars",
133 ],
134 attributes=[
135 "bind",
136 "dirty",
137 "deleted",
138 "new",
139 "identity_map",
140 "is_active",
141 "autoflush",
142 "no_autoflush",
143 "info",
144 ],
145)
146class scoped_session(Generic[_S]):
147 """Provides scoped management of :class:`.Session` objects.
148
149 See :ref:`unitofwork_contextual` for a tutorial.
150
151 .. note::
152
153 When using :ref:`asyncio_toplevel`, the async-compatible
154 :class:`_asyncio.async_scoped_session` class should be
155 used in place of :class:`.scoped_session`.
156
157 """
158
159 _support_async: bool = False
160
161 session_factory: sessionmaker[_S]
162 """The `session_factory` provided to `__init__` is stored in this
163 attribute and may be accessed at a later time. This can be useful when
164 a new non-scoped :class:`.Session` is needed."""
165
166 registry: ScopedRegistry[_S]
167
168 def __init__(
169 self,
170 session_factory: sessionmaker[_S],
171 scopefunc: Optional[Callable[[], Any]] = None,
172 ):
173 """Construct a new :class:`.scoped_session`.
174
175 :param session_factory: a factory to create new :class:`.Session`
176 instances. This is usually, but not necessarily, an instance
177 of :class:`.sessionmaker`.
178 :param scopefunc: optional function which defines
179 the current scope. If not passed, the :class:`.scoped_session`
180 object assumes "thread-local" scope, and will use
181 a Python ``threading.local()`` in order to maintain the current
182 :class:`.Session`. If passed, the function should return
183 a hashable token; this token will be used as the key in a
184 dictionary in order to store and retrieve the current
185 :class:`.Session`.
186
187 """
188 self.session_factory = session_factory
189
190 if scopefunc:
191 self.registry = ScopedRegistry(session_factory, scopefunc)
192 else:
193 self.registry = ThreadLocalRegistry(session_factory)
194
195 @property
196 def _proxied(self) -> _S:
197 return self.registry()
198
199 def __call__(self, **kw: Any) -> _S:
200 r"""Return the current :class:`.Session`, creating it
201 using the :attr:`.scoped_session.session_factory` if not present.
202
203 :param \**kw: Keyword arguments will be passed to the
204 :attr:`.scoped_session.session_factory` callable, if an existing
205 :class:`.Session` is not present. If the :class:`.Session` is present
206 and keyword arguments have been passed,
207 :exc:`~sqlalchemy.exc.InvalidRequestError` is raised.
208
209 """
210 if kw:
211 if self.registry.has():
212 raise sa_exc.InvalidRequestError(
213 "Scoped session is already present; "
214 "no new arguments may be specified."
215 )
216 else:
217 sess = self.session_factory(**kw)
218 self.registry.set(sess)
219 else:
220 sess = self.registry()
221 if not self._support_async and sess._is_asyncio:
222 warn_deprecated(
223 "Using `scoped_session` with asyncio is deprecated and "
224 "will raise an error in a future version. "
225 "Please use `async_scoped_session` instead.",
226 "1.4.23",
227 )
228 return sess
229
230 def configure(self, **kwargs: Any) -> None:
231 """reconfigure the :class:`.sessionmaker` used by this
232 :class:`.scoped_session`.
233
234 See :meth:`.sessionmaker.configure`.
235
236 """
237
238 if self.registry.has():
239 warn(
240 "At least one scoped session is already present. "
241 " configure() can not affect sessions that have "
242 "already been created."
243 )
244
245 self.session_factory.configure(**kwargs)
246
247 def remove(self) -> None:
248 """Dispose of the current :class:`.Session`, if present.
249
250 This will first call :meth:`.Session.close` method
251 on the current :class:`.Session`, which releases any existing
252 transactional/connection resources still being held; transactions
253 specifically are rolled back. The :class:`.Session` is then
254 discarded. Upon next usage within the same scope,
255 the :class:`.scoped_session` will produce a new
256 :class:`.Session` object.
257
258 """
259
260 if self.registry.has():
261 self.registry().close()
262 self.registry.clear()
263
264 def query_property(
265 self, query_cls: Optional[Type[Query[_T]]] = None
266 ) -> QueryPropertyDescriptor:
267 """return a class property which produces a legacy
268 :class:`_query.Query` object against the class and the current
269 :class:`.Session` when called.
270
271 .. legacy:: The :meth:`_orm.scoped_session.query_property` accessor
272 is specific to the legacy :class:`.Query` object and is not
273 considered to be part of :term:`2.0-style` ORM use.
274
275 e.g.::
276
277 from sqlalchemy.orm import QueryPropertyDescriptor
278 from sqlalchemy.orm import scoped_session
279 from sqlalchemy.orm import sessionmaker
280
281 Session = scoped_session(sessionmaker())
282
283 class MyClass:
284 query: QueryPropertyDescriptor = Session.query_property()
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: UpdateBase,
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 ) -> CursorResult[Any]: ...
697
698 @overload
699 def execute(
700 self,
701 statement: Executable,
702 params: Optional[_CoreAnyExecuteParams] = None,
703 *,
704 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
705 bind_arguments: Optional[_BindArguments] = None,
706 _parent_execute_state: Optional[Any] = None,
707 _add_event: Optional[Any] = None,
708 ) -> Result[Any]: ...
709
710 def execute(
711 self,
712 statement: Executable,
713 params: Optional[_CoreAnyExecuteParams] = None,
714 *,
715 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
716 bind_arguments: Optional[_BindArguments] = None,
717 _parent_execute_state: Optional[Any] = None,
718 _add_event: Optional[Any] = None,
719 ) -> Result[Any]:
720 r"""Execute a SQL expression construct.
721
722 .. container:: class_bases
723
724 Proxied for the :class:`_orm.Session` class on
725 behalf of the :class:`_orm.scoping.scoped_session` class.
726
727 Returns a :class:`_engine.Result` object representing
728 results of the statement execution.
729
730 E.g.::
731
732 from sqlalchemy import select
733 result = session.execute(
734 select(User).where(User.id == 5)
735 )
736
737 The API contract of :meth:`_orm.Session.execute` is similar to that
738 of :meth:`_engine.Connection.execute`, the :term:`2.0 style` version
739 of :class:`_engine.Connection`.
740
741 .. versionchanged:: 1.4 the :meth:`_orm.Session.execute` method is
742 now the primary point of ORM statement execution when using
743 :term:`2.0 style` ORM usage.
744
745 :param statement:
746 An executable statement (i.e. an :class:`.Executable` expression
747 such as :func:`_expression.select`).
748
749 :param params:
750 Optional dictionary, or list of dictionaries, containing
751 bound parameter values. If a single dictionary, single-row
752 execution occurs; if a list of dictionaries, an
753 "executemany" will be invoked. The keys in each dictionary
754 must correspond to parameter names present in the statement.
755
756 :param execution_options: optional dictionary of execution options,
757 which will be associated with the statement execution. This
758 dictionary can provide a subset of the options that are accepted
759 by :meth:`_engine.Connection.execution_options`, and may also
760 provide additional options understood only in an ORM context.
761
762 .. seealso::
763
764 :ref:`orm_queryguide_execution_options` - ORM-specific execution
765 options
766
767 :param bind_arguments: dictionary of additional arguments to determine
768 the bind. May include "mapper", "bind", or other custom arguments.
769 Contents of this dictionary are passed to the
770 :meth:`.Session.get_bind` method.
771
772 :return: a :class:`_engine.Result` object.
773
774
775
776 """ # noqa: E501
777
778 return self._proxied.execute(
779 statement,
780 params=params,
781 execution_options=execution_options,
782 bind_arguments=bind_arguments,
783 _parent_execute_state=_parent_execute_state,
784 _add_event=_add_event,
785 )
786
787 def expire(
788 self, instance: object, attribute_names: Optional[Iterable[str]] = None
789 ) -> None:
790 r"""Expire the attributes on an instance.
791
792 .. container:: class_bases
793
794 Proxied for the :class:`_orm.Session` class on
795 behalf of the :class:`_orm.scoping.scoped_session` class.
796
797 Marks the attributes of an instance as out of date. When an expired
798 attribute is next accessed, a query will be issued to the
799 :class:`.Session` object's current transactional context in order to
800 load all expired attributes for the given instance. Note that
801 a highly isolated transaction will return the same values as were
802 previously read in that same transaction, regardless of changes
803 in database state outside of that transaction.
804
805 To expire all objects in the :class:`.Session` simultaneously,
806 use :meth:`Session.expire_all`.
807
808 The :class:`.Session` object's default behavior is to
809 expire all state whenever the :meth:`Session.rollback`
810 or :meth:`Session.commit` methods are called, so that new
811 state can be loaded for the new transaction. For this reason,
812 calling :meth:`Session.expire` only makes sense for the specific
813 case that a non-ORM SQL statement was emitted in the current
814 transaction.
815
816 :param instance: The instance to be refreshed.
817 :param attribute_names: optional list of string attribute names
818 indicating a subset of attributes to be expired.
819
820 .. seealso::
821
822 :ref:`session_expire` - introductory material
823
824 :meth:`.Session.expire`
825
826 :meth:`.Session.refresh`
827
828 :meth:`_orm.Query.populate_existing`
829
830
831 """ # noqa: E501
832
833 return self._proxied.expire(instance, attribute_names=attribute_names)
834
835 def expire_all(self) -> None:
836 r"""Expires all persistent instances within this Session.
837
838 .. container:: class_bases
839
840 Proxied for the :class:`_orm.Session` class on
841 behalf of the :class:`_orm.scoping.scoped_session` class.
842
843 When any attributes on a persistent instance is next accessed,
844 a query will be issued using the
845 :class:`.Session` object's current transactional context in order to
846 load all expired attributes for the given instance. Note that
847 a highly isolated transaction will return the same values as were
848 previously read in that same transaction, regardless of changes
849 in database state outside of that transaction.
850
851 To expire individual objects and individual attributes
852 on those objects, use :meth:`Session.expire`.
853
854 The :class:`.Session` object's default behavior is to
855 expire all state whenever the :meth:`Session.rollback`
856 or :meth:`Session.commit` methods are called, so that new
857 state can be loaded for the new transaction. For this reason,
858 calling :meth:`Session.expire_all` is not usually needed,
859 assuming the transaction is isolated.
860
861 .. seealso::
862
863 :ref:`session_expire` - introductory material
864
865 :meth:`.Session.expire`
866
867 :meth:`.Session.refresh`
868
869 :meth:`_orm.Query.populate_existing`
870
871
872 """ # noqa: E501
873
874 return self._proxied.expire_all()
875
876 def expunge(self, instance: object) -> None:
877 r"""Remove the `instance` from this ``Session``.
878
879 .. container:: class_bases
880
881 Proxied for the :class:`_orm.Session` class on
882 behalf of the :class:`_orm.scoping.scoped_session` class.
883
884 This will free all internal references to the instance. Cascading
885 will be applied according to the *expunge* cascade rule.
886
887
888 """ # noqa: E501
889
890 return self._proxied.expunge(instance)
891
892 def expunge_all(self) -> None:
893 r"""Remove all object instances from this ``Session``.
894
895 .. container:: class_bases
896
897 Proxied for the :class:`_orm.Session` class on
898 behalf of the :class:`_orm.scoping.scoped_session` class.
899
900 This is equivalent to calling ``expunge(obj)`` on all objects in this
901 ``Session``.
902
903
904 """ # noqa: E501
905
906 return self._proxied.expunge_all()
907
908 def flush(self, objects: Optional[Sequence[Any]] = None) -> None:
909 r"""Flush all the object changes to the database.
910
911 .. container:: class_bases
912
913 Proxied for the :class:`_orm.Session` class on
914 behalf of the :class:`_orm.scoping.scoped_session` class.
915
916 Writes out all pending object creations, deletions and modifications
917 to the database as INSERTs, DELETEs, UPDATEs, etc. Operations are
918 automatically ordered by the Session's unit of work dependency
919 solver.
920
921 Database operations will be issued in the current transactional
922 context and do not affect the state of the transaction, unless an
923 error occurs, in which case the entire transaction is rolled back.
924 You may flush() as often as you like within a transaction to move
925 changes from Python to the database's transaction buffer.
926
927 :param objects: Optional; restricts the flush operation to operate
928 only on elements that are in the given collection.
929
930 This feature is for an extremely narrow set of use cases where
931 particular objects may need to be operated upon before the
932 full flush() occurs. It is not intended for general use.
933
934
935 """ # noqa: E501
936
937 return self._proxied.flush(objects=objects)
938
939 def get(
940 self,
941 entity: _EntityBindKey[_O],
942 ident: _PKIdentityArgument,
943 *,
944 options: Optional[Sequence[ORMOption]] = None,
945 populate_existing: bool = False,
946 with_for_update: ForUpdateParameter = None,
947 identity_token: Optional[Any] = None,
948 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
949 bind_arguments: Optional[_BindArguments] = None,
950 ) -> Optional[_O]:
951 r"""Return an instance based on the given primary key identifier,
952 or ``None`` if not found.
953
954 .. container:: class_bases
955
956 Proxied for the :class:`_orm.Session` class on
957 behalf of the :class:`_orm.scoping.scoped_session` class.
958
959 E.g.::
960
961 my_user = session.get(User, 5)
962
963 some_object = session.get(VersionedFoo, (5, 10))
964
965 some_object = session.get(
966 VersionedFoo,
967 {"id": 5, "version_id": 10}
968 )
969
970 .. versionadded:: 1.4 Added :meth:`_orm.Session.get`, which is moved
971 from the now legacy :meth:`_orm.Query.get` method.
972
973 :meth:`_orm.Session.get` is special in that it provides direct
974 access to the identity map of the :class:`.Session`.
975 If the given primary key identifier is present
976 in the local identity map, the object is returned
977 directly from this collection and no SQL is emitted,
978 unless the object has been marked fully expired.
979 If not present,
980 a SELECT is performed in order to locate the object.
981
982 :meth:`_orm.Session.get` also will perform a check if
983 the object is present in the identity map and
984 marked as expired - a SELECT
985 is emitted to refresh the object as well as to
986 ensure that the row is still present.
987 If not, :class:`~sqlalchemy.orm.exc.ObjectDeletedError` is raised.
988
989 :param entity: a mapped class or :class:`.Mapper` indicating the
990 type of entity to be loaded.
991
992 :param ident: A scalar, tuple, or dictionary representing the
993 primary key. For a composite (e.g. multiple column) primary key,
994 a tuple or dictionary should be passed.
995
996 For a single-column primary key, the scalar calling form is typically
997 the most expedient. If the primary key of a row is the value "5",
998 the call looks like::
999
1000 my_object = session.get(SomeClass, 5)
1001
1002 The tuple form contains primary key values typically in
1003 the order in which they correspond to the mapped
1004 :class:`_schema.Table`
1005 object's primary key columns, or if the
1006 :paramref:`_orm.Mapper.primary_key` configuration parameter were
1007 used, in
1008 the order used for that parameter. For example, if the primary key
1009 of a row is represented by the integer
1010 digits "5, 10" the call would look like::
1011
1012 my_object = session.get(SomeClass, (5, 10))
1013
1014 The dictionary form should include as keys the mapped attribute names
1015 corresponding to each element of the primary key. If the mapped class
1016 has the attributes ``id``, ``version_id`` as the attributes which
1017 store the object's primary key value, the call would look like::
1018
1019 my_object = session.get(SomeClass, {"id": 5, "version_id": 10})
1020
1021 :param options: optional sequence of loader options which will be
1022 applied to the query, if one is emitted.
1023
1024 :param populate_existing: causes the method to unconditionally emit
1025 a SQL query and refresh the object with the newly loaded data,
1026 regardless of whether or not the object is already present.
1027
1028 :param with_for_update: optional boolean ``True`` indicating FOR UPDATE
1029 should be used, or may be a dictionary containing flags to
1030 indicate a more specific set of FOR UPDATE flags for the SELECT;
1031 flags should match the parameters of
1032 :meth:`_query.Query.with_for_update`.
1033 Supersedes the :paramref:`.Session.refresh.lockmode` parameter.
1034
1035 :param execution_options: optional dictionary of execution options,
1036 which will be associated with the query execution if one is emitted.
1037 This dictionary can provide a subset of the options that are
1038 accepted by :meth:`_engine.Connection.execution_options`, and may
1039 also provide additional options understood only in an ORM context.
1040
1041 .. versionadded:: 1.4.29
1042
1043 .. seealso::
1044
1045 :ref:`orm_queryguide_execution_options` - ORM-specific execution
1046 options
1047
1048 :param bind_arguments: dictionary of additional arguments to determine
1049 the bind. May include "mapper", "bind", or other custom arguments.
1050 Contents of this dictionary are passed to the
1051 :meth:`.Session.get_bind` method.
1052
1053 .. versionadded: 2.0.0rc1
1054
1055 :return: The object instance, or ``None``.
1056
1057
1058 """ # noqa: E501
1059
1060 return self._proxied.get(
1061 entity,
1062 ident,
1063 options=options,
1064 populate_existing=populate_existing,
1065 with_for_update=with_for_update,
1066 identity_token=identity_token,
1067 execution_options=execution_options,
1068 bind_arguments=bind_arguments,
1069 )
1070
1071 def get_one(
1072 self,
1073 entity: _EntityBindKey[_O],
1074 ident: _PKIdentityArgument,
1075 *,
1076 options: Optional[Sequence[ORMOption]] = None,
1077 populate_existing: bool = False,
1078 with_for_update: ForUpdateParameter = None,
1079 identity_token: Optional[Any] = None,
1080 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1081 bind_arguments: Optional[_BindArguments] = None,
1082 ) -> _O:
1083 r"""Return exactly one instance based on the given primary key
1084 identifier, or raise an exception if not found.
1085
1086 .. container:: class_bases
1087
1088 Proxied for the :class:`_orm.Session` class on
1089 behalf of the :class:`_orm.scoping.scoped_session` class.
1090
1091 Raises ``sqlalchemy.orm.exc.NoResultFound`` if the query
1092 selects no rows.
1093
1094 For a detailed documentation of the arguments see the
1095 method :meth:`.Session.get`.
1096
1097 .. versionadded:: 2.0.22
1098
1099 :return: The object instance.
1100
1101 .. seealso::
1102
1103 :meth:`.Session.get` - equivalent method that instead
1104 returns ``None`` if no row was found with the provided primary
1105 key
1106
1107
1108 """ # noqa: E501
1109
1110 return self._proxied.get_one(
1111 entity,
1112 ident,
1113 options=options,
1114 populate_existing=populate_existing,
1115 with_for_update=with_for_update,
1116 identity_token=identity_token,
1117 execution_options=execution_options,
1118 bind_arguments=bind_arguments,
1119 )
1120
1121 def get_bind(
1122 self,
1123 mapper: Optional[_EntityBindKey[_O]] = None,
1124 *,
1125 clause: Optional[ClauseElement] = None,
1126 bind: Optional[_SessionBind] = None,
1127 _sa_skip_events: Optional[bool] = None,
1128 _sa_skip_for_implicit_returning: bool = False,
1129 **kw: Any,
1130 ) -> Union[Engine, Connection]:
1131 r"""Return a "bind" to which this :class:`.Session` is bound.
1132
1133 .. container:: class_bases
1134
1135 Proxied for the :class:`_orm.Session` class on
1136 behalf of the :class:`_orm.scoping.scoped_session` class.
1137
1138 The "bind" is usually an instance of :class:`_engine.Engine`,
1139 except in the case where the :class:`.Session` has been
1140 explicitly bound directly to a :class:`_engine.Connection`.
1141
1142 For a multiply-bound or unbound :class:`.Session`, the
1143 ``mapper`` or ``clause`` arguments are used to determine the
1144 appropriate bind to return.
1145
1146 Note that the "mapper" argument is usually present
1147 when :meth:`.Session.get_bind` is called via an ORM
1148 operation such as a :meth:`.Session.query`, each
1149 individual INSERT/UPDATE/DELETE operation within a
1150 :meth:`.Session.flush`, call, etc.
1151
1152 The order of resolution is:
1153
1154 1. if mapper given and :paramref:`.Session.binds` is present,
1155 locate a bind based first on the mapper in use, then
1156 on the mapped class in use, then on any base classes that are
1157 present in the ``__mro__`` of the mapped class, from more specific
1158 superclasses to more general.
1159 2. if clause given and ``Session.binds`` is present,
1160 locate a bind based on :class:`_schema.Table` objects
1161 found in the given clause present in ``Session.binds``.
1162 3. if ``Session.binds`` is present, return that.
1163 4. if clause given, attempt to return a bind
1164 linked to the :class:`_schema.MetaData` ultimately
1165 associated with the clause.
1166 5. if mapper given, attempt to return a bind
1167 linked to the :class:`_schema.MetaData` ultimately
1168 associated with the :class:`_schema.Table` or other
1169 selectable to which the mapper is mapped.
1170 6. No bind can be found, :exc:`~sqlalchemy.exc.UnboundExecutionError`
1171 is raised.
1172
1173 Note that the :meth:`.Session.get_bind` method can be overridden on
1174 a user-defined subclass of :class:`.Session` to provide any kind
1175 of bind resolution scheme. See the example at
1176 :ref:`session_custom_partitioning`.
1177
1178 :param mapper:
1179 Optional mapped class or corresponding :class:`_orm.Mapper` instance.
1180 The bind can be derived from a :class:`_orm.Mapper` first by
1181 consulting the "binds" map associated with this :class:`.Session`,
1182 and secondly by consulting the :class:`_schema.MetaData` associated
1183 with the :class:`_schema.Table` to which the :class:`_orm.Mapper` is
1184 mapped for a bind.
1185
1186 :param clause:
1187 A :class:`_expression.ClauseElement` (i.e.
1188 :func:`_expression.select`,
1189 :func:`_expression.text`,
1190 etc.). If the ``mapper`` argument is not present or could not
1191 produce a bind, the given expression construct will be searched
1192 for a bound element, typically a :class:`_schema.Table`
1193 associated with
1194 bound :class:`_schema.MetaData`.
1195
1196 .. seealso::
1197
1198 :ref:`session_partitioning`
1199
1200 :paramref:`.Session.binds`
