Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
scoping.py1615 linesDownload Raw Back to asyncio
1# ext/asyncio/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 Generic
13from typing import Iterable
14from typing import Iterator
15from typing import Optional
16from typing import overload
17from typing import Sequence
18from typing import Tuple
19from typing import Type
20from typing import TYPE_CHECKING
21from typing import TypeVar
22from typing import Union
23
24from .session import _AS
25from .session import async_sessionmaker
26from .session import AsyncSession
27from ... import exc as sa_exc
28from ... import util
29from ...orm.session import Session
30from ...util import create_proxy_methods
31from ...util import ScopedRegistry
32from ...util import warn
33from ...util import warn_deprecated
34
35if TYPE_CHECKING:
36    from .engine import AsyncConnection
37    from .result import AsyncResult
38    from .result import AsyncScalarResult
39    from .session import AsyncSessionTransaction
40    from ...engine import Connection
41    from ...engine import CursorResult
42    from ...engine import Engine
43    from ...engine import Result
44    from ...engine import Row
45    from ...engine import RowMapping
46    from ...engine.interfaces import _CoreAnyExecuteParams
47    from ...engine.interfaces import CoreExecuteOptionsParameter
48    from ...engine.result import ScalarResult
49    from ...orm._typing import _IdentityKeyType
50    from ...orm._typing import _O
51    from ...orm._typing import OrmExecuteOptionsParameter
52    from ...orm.interfaces import ORMOption
53    from ...orm.session import _BindArguments
54    from ...orm.session import _EntityBindKey
55    from ...orm.session import _PKIdentityArgument
56    from ...orm.session import _SessionBind
57    from ...sql.base import Executable
58    from ...sql.dml import UpdateBase
59    from ...sql.elements import ClauseElement
60    from ...sql.selectable import ForUpdateParameter
61    from ...sql.selectable import TypedReturnsRows
62
63_T = TypeVar("_T", bound=Any)
64
65
66@create_proxy_methods(
67    AsyncSession,
68    ":class:`_asyncio.AsyncSession`",
69    ":class:`_asyncio.scoping.async_scoped_session`",
70    classmethods=["close_all", "object_session", "identity_key"],
71    methods=[
72        "__contains__",
73        "__iter__",
74        "aclose",
75        "add",
76        "add_all",
77        "begin",
78        "begin_nested",
79        "close",
80        "reset",
81        "commit",
82        "connection",
83        "delete",
84        "execute",
85        "expire",
86        "expire_all",
87        "expunge",
88        "expunge_all",
89        "flush",
90        "get_bind",
91        "is_modified",
92        "invalidate",
93        "merge",
94        "refresh",
95        "rollback",
96        "scalar",
97        "scalars",
98        "get",
99        "get_one",
100        "stream",
101        "stream_scalars",
102    ],
103    attributes=[
104        "bind",
105        "dirty",
106        "deleted",
107        "new",
108        "identity_map",
109        "is_active",
110        "autoflush",
111        "no_autoflush",
112        "info",
113    ],
114    use_intermediate_variable=["get"],
115)
116class async_scoped_session(Generic[_AS]):
117    """Provides scoped management of :class:`.AsyncSession` objects.
118
119    See the section :ref:`asyncio_scoped_session` for usage details.
120
121    .. versionadded:: 1.4.19
122
123
124    """
125
126    _support_async = True
127
128    session_factory: async_sessionmaker[_AS]
129    """The `session_factory` provided to `__init__` is stored in this
130    attribute and may be accessed at a later time.  This can be useful when
131    a new non-scoped :class:`.AsyncSession` is needed."""
132
133    registry: ScopedRegistry[_AS]
134
135    def __init__(
136        self,
137        session_factory: async_sessionmaker[_AS],
138        scopefunc: Callable[[], Any],
139    ):
140        """Construct a new :class:`_asyncio.async_scoped_session`.
141
142        :param session_factory: a factory to create new :class:`_asyncio.AsyncSession`
143         instances. This is usually, but not necessarily, an instance
144         of :class:`_asyncio.async_sessionmaker`.
145
146        :param scopefunc: function which defines
147         the current scope.   A function such as ``asyncio.current_task``
148         may be useful here.
149
150        """  # noqa: E501
151
152        self.session_factory = session_factory
153        self.registry = ScopedRegistry(session_factory, scopefunc)
154
155    @property
156    def _proxied(self) -> _AS:
157        return self.registry()
158
159    def __call__(self, **kw: Any) -> _AS:
160        r"""Return the current :class:`.AsyncSession`, creating it
161        using the :attr:`.scoped_session.session_factory` if not present.
162
163        :param \**kw: Keyword arguments will be passed to the
164         :attr:`.scoped_session.session_factory` callable, if an existing
165         :class:`.AsyncSession` is not present.  If the
166         :class:`.AsyncSession` is present
167         and keyword arguments have been passed,
168         :exc:`~sqlalchemy.exc.InvalidRequestError` is raised.
169
170        """
171        if kw:
172            if self.registry.has():
173                raise sa_exc.InvalidRequestError(
174                    "Scoped session is already present; "
175                    "no new arguments may be specified."
176                )
177            else:
178                sess = self.session_factory(**kw)
179                self.registry.set(sess)
180        else:
181            sess = self.registry()
182        if not self._support_async and sess._is_asyncio:
183            warn_deprecated(
184                "Using `scoped_session` with asyncio is deprecated and "
185                "will raise an error in a future version. "
186                "Please use `async_scoped_session` instead.",
187                "1.4.23",
188            )
189        return sess
190
191    def configure(self, **kwargs: Any) -> None:
192        """reconfigure the :class:`.sessionmaker` used by this
193        :class:`.scoped_session`.
194
195        See :meth:`.sessionmaker.configure`.
196
197        """
198
199        if self.registry.has():
200            warn(
201                "At least one scoped session is already present. "
202                " configure() can not affect sessions that have "
203                "already been created."
204            )
205
206        self.session_factory.configure(**kwargs)
207
208    async def remove(self) -> None:
209        """Dispose of the current :class:`.AsyncSession`, if present.
210
211        Different from scoped_session's remove method, this method would use
212        await to wait for the close method of AsyncSession.
213
214        """
215
216        if self.registry.has():
217            await self.registry().close()
218        self.registry.clear()
219
220    # START PROXY METHODS async_scoped_session
221
222    # code within this block is **programmatically,
223    # statically generated** by tools/generate_proxy_methods.py
224
225    def __contains__(self, instance: object) -> bool:
226        r"""Return True if the instance is associated with this session.
227
228        .. container:: class_bases
229
230            Proxied for the :class:`_asyncio.AsyncSession` class on
231            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
232
233        .. container:: class_bases
234
235            Proxied for the :class:`_orm.Session` class on
236            behalf of the :class:`_asyncio.AsyncSession` class.
237
238        The instance may be pending or persistent within the Session for a
239        result of True.
240
241
242
243        """  # noqa: E501
244
245        return self._proxied.__contains__(instance)
246
247    def __iter__(self) -> Iterator[object]:
248        r"""Iterate over all pending or persistent instances within this
249        Session.
250
251        .. container:: class_bases
252
253            Proxied for the :class:`_asyncio.AsyncSession` class on
254            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
255
256        .. container:: class_bases
257
258            Proxied for the :class:`_orm.Session` class on
259            behalf of the :class:`_asyncio.AsyncSession` class.
260
261
262
263        """  # noqa: E501
264
265        return self._proxied.__iter__()
266
267    async def aclose(self) -> None:
268        r"""A synonym for :meth:`_asyncio.AsyncSession.close`.
269
270        .. container:: class_bases
271
272            Proxied for the :class:`_asyncio.AsyncSession` class on
273            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
274
275        The :meth:`_asyncio.AsyncSession.aclose` name is specifically
276        to support the Python standard library ``@contextlib.aclosing``
277        context manager function.
278
279        .. versionadded:: 2.0.20
280
281
282        """  # noqa: E501
283
284        return await self._proxied.aclose()
285
286    def add(self, instance: object, _warn: bool = True) -> None:
287        r"""Place an object into this :class:`_orm.Session`.
288
289        .. container:: class_bases
290
291            Proxied for the :class:`_asyncio.AsyncSession` class on
292            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
293
294        .. container:: class_bases
295
296            Proxied for the :class:`_orm.Session` class on
297            behalf of the :class:`_asyncio.AsyncSession` class.
298
299        Objects that are in the :term:`transient` state when passed to the
300        :meth:`_orm.Session.add` method will move to the
301        :term:`pending` state, until the next flush, at which point they
302        will move to the :term:`persistent` state.
303
304        Objects that are in the :term:`detached` state when passed to the
305        :meth:`_orm.Session.add` method will move to the :term:`persistent`
306        state directly.
307
308        If the transaction used by the :class:`_orm.Session` is rolled back,
309        objects which were transient when they were passed to
310        :meth:`_orm.Session.add` will be moved back to the
311        :term:`transient` state, and will no longer be present within this
312        :class:`_orm.Session`.
313
314        .. seealso::
315
316            :meth:`_orm.Session.add_all`
317
318            :ref:`session_adding` - at :ref:`session_basics`
319
320
321
322        """  # noqa: E501
323
324        return self._proxied.add(instance, _warn=_warn)
325
326    def add_all(self, instances: Iterable[object]) -> None:
327        r"""Add the given collection of instances to this :class:`_orm.Session`.
328
329        .. container:: class_bases
330
331            Proxied for the :class:`_asyncio.AsyncSession` class on
332            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
333
334        .. container:: class_bases
335
336            Proxied for the :class:`_orm.Session` class on
337            behalf of the :class:`_asyncio.AsyncSession` class.
338
339        See the documentation for :meth:`_orm.Session.add` for a general
340        behavioral description.
341
342        .. seealso::
343
344            :meth:`_orm.Session.add`
345
346            :ref:`session_adding` - at :ref:`session_basics`
347
348
349
350        """  # noqa: E501
351
352        return self._proxied.add_all(instances)
353
354    def begin(self) -> AsyncSessionTransaction:
355        r"""Return an :class:`_asyncio.AsyncSessionTransaction` object.
356
357        .. container:: class_bases
358
359            Proxied for the :class:`_asyncio.AsyncSession` class on
360            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
361
362        The underlying :class:`_orm.Session` will perform the
363        "begin" action when the :class:`_asyncio.AsyncSessionTransaction`
364        object is entered::
365
366            async with async_session.begin():
367                # .. ORM transaction is begun
368
369        Note that database IO will not normally occur when the session-level
370        transaction is begun, as database transactions begin on an
371        on-demand basis.  However, the begin block is async to accommodate
372        for a :meth:`_orm.SessionEvents.after_transaction_create`
373        event hook that may perform IO.
374
375        For a general description of ORM begin, see
376        :meth:`_orm.Session.begin`.
377
378
379        """  # noqa: E501
380
381        return self._proxied.begin()
382
383    def begin_nested(self) -> AsyncSessionTransaction:
384        r"""Return an :class:`_asyncio.AsyncSessionTransaction` object
385        which will begin a "nested" transaction, e.g. SAVEPOINT.
386
387        .. container:: class_bases
388
389            Proxied for the :class:`_asyncio.AsyncSession` class on
390            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
391
392        Behavior is the same as that of :meth:`_asyncio.AsyncSession.begin`.
393
394        For a general description of ORM begin nested, see
395        :meth:`_orm.Session.begin_nested`.
396
397        .. seealso::
398
399            :ref:`aiosqlite_serializable` - special workarounds required
400            with the SQLite asyncio driver in order for SAVEPOINT to work
401            correctly.
402
403
404        """  # noqa: E501
405
406        return self._proxied.begin_nested()
407
408    async def close(self) -> None:
409        r"""Close out the transactional resources and ORM objects used by this
410        :class:`_asyncio.AsyncSession`.
411
412        .. container:: class_bases
413
414            Proxied for the :class:`_asyncio.AsyncSession` class on
415            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
416
417        .. seealso::
418
419            :meth:`_orm.Session.close` - main documentation for
420            "close"
421
422            :ref:`session_closing` - detail on the semantics of
423            :meth:`_asyncio.AsyncSession.close` and
424            :meth:`_asyncio.AsyncSession.reset`.
425
426
427        """  # noqa: E501
428
429        return await self._proxied.close()
430
431    async def reset(self) -> None:
432        r"""Close out the transactional resources and ORM objects used by this
433        :class:`_orm.Session`, resetting the session to its initial state.
434
435        .. container:: class_bases
436
437            Proxied for the :class:`_asyncio.AsyncSession` class on
438            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
439
440        .. versionadded:: 2.0.22
441
442        .. seealso::
443
444            :meth:`_orm.Session.reset` - main documentation for
445            "reset"
446
447            :ref:`session_closing` - detail on the semantics of
448            :meth:`_asyncio.AsyncSession.close` and
449            :meth:`_asyncio.AsyncSession.reset`.
450
451
452        """  # noqa: E501
453
454        return await self._proxied.reset()
455
456    async def commit(self) -> None:
457        r"""Commit the current transaction in progress.
458
459        .. container:: class_bases
460
461            Proxied for the :class:`_asyncio.AsyncSession` class on
462            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
463
464        .. seealso::
465
466            :meth:`_orm.Session.commit` - main documentation for
467            "commit"
468
469        """  # noqa: E501
470
471        return await self._proxied.commit()
472
473    async def connection(
474        self,
475        bind_arguments: Optional[_BindArguments] = None,
476        execution_options: Optional[CoreExecuteOptionsParameter] = None,
477        **kw: Any,
478    ) -> AsyncConnection:
479        r"""Return a :class:`_asyncio.AsyncConnection` object corresponding to
480        this :class:`.Session` object's transactional state.
481
482        .. container:: class_bases
483
484            Proxied for the :class:`_asyncio.AsyncSession` class on
485            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
486
487        This method may also be used to establish execution options for the
488        database connection used by the current transaction.
489
490        .. versionadded:: 1.4.24  Added \**kw arguments which are passed
491           through to the underlying :meth:`_orm.Session.connection` method.
492
493        .. seealso::
494
495            :meth:`_orm.Session.connection` - main documentation for
496            "connection"
497
498
499        """  # noqa: E501
500
501        return await self._proxied.connection(
502            bind_arguments=bind_arguments,
503            execution_options=execution_options,
504            **kw,
505        )
506
507    async def delete(self, instance: object) -> None:
508        r"""Mark an instance as deleted.
509
510        .. container:: class_bases
511
512            Proxied for the :class:`_asyncio.AsyncSession` class on
513            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
514
515        The database delete operation occurs upon ``flush()``.
516
517        As this operation may need to cascade along unloaded relationships,
518        it is awaitable to allow for those queries to take place.
519
520        .. seealso::
521
522            :meth:`_orm.Session.delete` - main documentation for delete
523
524
525        """  # noqa: E501
526
527        return await self._proxied.delete(instance)
528
529    @overload
530    async def execute(
531        self,
532        statement: TypedReturnsRows[_T],
533        params: Optional[_CoreAnyExecuteParams] = None,
534        *,
535        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
536        bind_arguments: Optional[_BindArguments] = None,
537        _parent_execute_state: Optional[Any] = None,
538        _add_event: Optional[Any] = None,
539    ) -> Result[_T]: ...
540
541    @overload
542    async def execute(
543        self,
544        statement: UpdateBase,
545        params: Optional[_CoreAnyExecuteParams] = None,
546        *,
547        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
548        bind_arguments: Optional[_BindArguments] = None,
549        _parent_execute_state: Optional[Any] = None,
550        _add_event: Optional[Any] = None,
551    ) -> CursorResult[Any]: ...
552
553    @overload
554    async def execute(
555        self,
556        statement: Executable,
557        params: Optional[_CoreAnyExecuteParams] = None,
558        *,
559        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
560        bind_arguments: Optional[_BindArguments] = None,
561        _parent_execute_state: Optional[Any] = None,
562        _add_event: Optional[Any] = None,
563    ) -> Result[Any]: ...
564
565    async def execute(
566        self,
567        statement: Executable,
568        params: Optional[_CoreAnyExecuteParams] = None,
569        *,
570        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
571        bind_arguments: Optional[_BindArguments] = None,
572        **kw: Any,
573    ) -> Result[Any]:
574        r"""Execute a statement and return a buffered
575        :class:`_engine.Result` object.
576
577        .. container:: class_bases
578
579            Proxied for the :class:`_asyncio.AsyncSession` class on
580            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
581
582        .. seealso::
583
584            :meth:`_orm.Session.execute` - main documentation for execute
585
586
587        """  # noqa: E501
588
589        return await self._proxied.execute(
590            statement,
591            params=params,
592            execution_options=execution_options,
593            bind_arguments=bind_arguments,
594            **kw,
595        )
596
597    def expire(
598        self, instance: object, attribute_names: Optional[Iterable[str]] = None
599    ) -> None:
600        r"""Expire the attributes on an instance.
601
602        .. container:: class_bases
603
604            Proxied for the :class:`_asyncio.AsyncSession` class on
605            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
606
607        .. container:: class_bases
608
609            Proxied for the :class:`_orm.Session` class on
610            behalf of the :class:`_asyncio.AsyncSession` class.
611
612        Marks the attributes of an instance as out of date. When an expired
613        attribute is next accessed, a query will be issued to the
614        :class:`.Session` object's current transactional context in order to
615        load all expired attributes for the given instance.   Note that
616        a highly isolated transaction will return the same values as were
617        previously read in that same transaction, regardless of changes
618        in database state outside of that transaction.
619
620        To expire all objects in the :class:`.Session` simultaneously,
621        use :meth:`Session.expire_all`.
622
623        The :class:`.Session` object's default behavior is to
624        expire all state whenever the :meth:`Session.rollback`
625        or :meth:`Session.commit` methods are called, so that new
626        state can be loaded for the new transaction.   For this reason,
627        calling :meth:`Session.expire` only makes sense for the specific
628        case that a non-ORM SQL statement was emitted in the current
629        transaction.
630
631        :param instance: The instance to be refreshed.
632        :param attribute_names: optional list of string attribute names
633          indicating a subset of attributes to be expired.
634
635        .. seealso::
636
637            :ref:`session_expire` - introductory material
638
639            :meth:`.Session.expire`
640
641            :meth:`.Session.refresh`
642
643            :meth:`_orm.Query.populate_existing`
644
645
646
647        """  # noqa: E501
648
649        return self._proxied.expire(instance, attribute_names=attribute_names)
650
651    def expire_all(self) -> None:
652        r"""Expires all persistent instances within this Session.
653
654        .. container:: class_bases
655
656            Proxied for the :class:`_asyncio.AsyncSession` class on
657            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
658
659        .. container:: class_bases
660
661            Proxied for the :class:`_orm.Session` class on
662            behalf of the :class:`_asyncio.AsyncSession` class.
663
664        When any attributes on a persistent instance is next accessed,
665        a query will be issued using the
666        :class:`.Session` object's current transactional context in order to
667        load all expired attributes for the given instance.   Note that
668        a highly isolated transaction will return the same values as were
669        previously read in that same transaction, regardless of changes
670        in database state outside of that transaction.
671
672        To expire individual objects and individual attributes
673        on those objects, use :meth:`Session.expire`.
674
675        The :class:`.Session` object's default behavior is to
676        expire all state whenever the :meth:`Session.rollback`
677        or :meth:`Session.commit` methods are called, so that new
678        state can be loaded for the new transaction.   For this reason,
679        calling :meth:`Session.expire_all` is not usually needed,
680        assuming the transaction is isolated.
681
682        .. seealso::
683
684            :ref:`session_expire` - introductory material
685
686            :meth:`.Session.expire`
687
688            :meth:`.Session.refresh`
689
690            :meth:`_orm.Query.populate_existing`
691
692
693
694        """  # noqa: E501
695
696        return self._proxied.expire_all()
697
698    def expunge(self, instance: object) -> None:
699        r"""Remove the `instance` from this ``Session``.
700
701        .. container:: class_bases
702
703            Proxied for the :class:`_asyncio.AsyncSession` class on
704            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
705
706        .. container:: class_bases
707
708            Proxied for the :class:`_orm.Session` class on
709            behalf of the :class:`_asyncio.AsyncSession` class.
710
711        This will free all internal references to the instance.  Cascading
712        will be applied according to the *expunge* cascade rule.
713
714
715
716        """  # noqa: E501
717
718        return self._proxied.expunge(instance)
719
720    def expunge_all(self) -> None:
721        r"""Remove all object instances from this ``Session``.
722
723        .. container:: class_bases
724
725            Proxied for the :class:`_asyncio.AsyncSession` class on
726            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
727
728        .. container:: class_bases
729
730            Proxied for the :class:`_orm.Session` class on
731            behalf of the :class:`_asyncio.AsyncSession` class.
732
733        This is equivalent to calling ``expunge(obj)`` on all objects in this
734        ``Session``.
735
736
737
738        """  # noqa: E501
739
740        return self._proxied.expunge_all()
741
742    async def flush(self, objects: Optional[Sequence[Any]] = None) -> None:
743        r"""Flush all the object changes to the database.
744
745        .. container:: class_bases
746
747            Proxied for the :class:`_asyncio.AsyncSession` class on
748            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
749
750        .. seealso::
751
752            :meth:`_orm.Session.flush` - main documentation for flush
753
754
755        """  # noqa: E501
756
757        return await self._proxied.flush(objects=objects)
758
759    def get_bind(
760        self,
761        mapper: Optional[_EntityBindKey[_O]] = None,
762        clause: Optional[ClauseElement] = None,
763        bind: Optional[_SessionBind] = None,
764        **kw: Any,
765    ) -> Union[Engine, Connection]:
766        r"""Return a "bind" to which the synchronous proxied :class:`_orm.Session`
767        is bound.
768
769        .. container:: class_bases
770
771            Proxied for the :class:`_asyncio.AsyncSession` class on
772            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
773
774        Unlike the :meth:`_orm.Session.get_bind` method, this method is
775        currently **not** used by this :class:`.AsyncSession` in any way
776        in order to resolve engines for requests.
777
778        .. note::
779
780            This method proxies directly to the :meth:`_orm.Session.get_bind`
781            method, however is currently **not** useful as an override target,
782            in contrast to that of the :meth:`_orm.Session.get_bind` method.
783            The example below illustrates how to implement custom
784            :meth:`_orm.Session.get_bind` schemes that work with
785            :class:`.AsyncSession` and :class:`.AsyncEngine`.
786
787        The pattern introduced at :ref:`session_custom_partitioning`
788        illustrates how to apply a custom bind-lookup scheme to a
789        :class:`_orm.Session` given a set of :class:`_engine.Engine` objects.
790        To apply a corresponding :meth:`_orm.Session.get_bind` implementation
791        for use with a :class:`.AsyncSession` and :class:`.AsyncEngine`
792        objects, continue to subclass :class:`_orm.Session` and apply it to
793        :class:`.AsyncSession` using
794        :paramref:`.AsyncSession.sync_session_class`. The inner method must
795        continue to return :class:`_engine.Engine` instances, which can be
796        acquired from a :class:`_asyncio.AsyncEngine` using the
797        :attr:`_asyncio.AsyncEngine.sync_engine` attribute::
798
799            # using example from "Custom Vertical Partitioning"
800
801
802            import random
803
804            from sqlalchemy.ext.asyncio import AsyncSession
805            from sqlalchemy.ext.asyncio import create_async_engine
806            from sqlalchemy.ext.asyncio import async_sessionmaker
807            from sqlalchemy.orm import Session
808
809            # construct async engines w/ async drivers
810            engines = {
811                'leader':create_async_engine("sqlite+aiosqlite:///leader.db"),
812                'other':create_async_engine("sqlite+aiosqlite:///other.db"),
813                'follower1':create_async_engine("sqlite+aiosqlite:///follower1.db"),
814                'follower2':create_async_engine("sqlite+aiosqlite:///follower2.db"),
815            }
816
817            class RoutingSession(Session):
818                def get_bind(self, mapper=None, clause=None, **kw):
819                    # within get_bind(), return sync engines
820                    if mapper and issubclass(mapper.class_, MyOtherClass):
821                        return engines['other'].sync_engine
822                    elif self._flushing or isinstance(clause, (Update, Delete)):
823                        return engines['leader'].sync_engine
824                    else:
825                        return engines[
826                            random.choice(['follower1','follower2'])
827                        ].sync_engine
828
829            # apply to AsyncSession using sync_session_class
830            AsyncSessionMaker = async_sessionmaker(
831                sync_session_class=RoutingSession
832            )
833
834        The :meth:`_orm.Session.get_bind` method is called in a non-asyncio,
835        implicitly non-blocking context in the same manner as ORM event hooks
836        and functions that are invoked via :meth:`.AsyncSession.run_sync`, so
837        routines that wish to run SQL commands inside of
838        :meth:`_orm.Session.get_bind` can continue to do so using
839        blocking-style code, which will be translated to implicitly async calls
840        at the point of invoking IO on the database drivers.
841
842
843        """  # noqa: E501
844
845        return self._proxied.get_bind(
846            mapper=mapper, clause=clause, bind=bind, **kw
847        )
848
849    def is_modified(
850        self, instance: object, include_collections: bool = True
851    ) -> bool:
852        r"""Return ``True`` if the given instance has locally
853        modified attributes.
854
855        .. container:: class_bases
856
857            Proxied for the :class:`_asyncio.AsyncSession` class on
858            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
859
860        .. container:: class_bases
861
862            Proxied for the :class:`_orm.Session` class on
863            behalf of the :class:`_asyncio.AsyncSession` class.
864
865        This method retrieves the history for each instrumented
866        attribute on the instance and performs a comparison of the current
867        value to its previously committed value, if any.
868
869        It is in effect a more expensive and accurate
870        version of checking for the given instance in the
871        :attr:`.Session.dirty` collection; a full test for
872        each attribute's net "dirty" status is performed.
873
874        E.g.::
875
876            return session.is_modified(someobject)
877
878        A few caveats to this method apply:
879
880        * Instances present in the :attr:`.Session.dirty` collection may
881          report ``False`` when tested with this method.  This is because
882          the object may have received change events via attribute mutation,
883          thus placing it in :attr:`.Session.dirty`, but ultimately the state
884          is the same as that loaded from the database, resulting in no net
885          change here.
886        * Scalar attributes may not have recorded the previously set
887          value when a new value was applied, if the attribute was not loaded,
888          or was expired, at the time the new value was received - in these
889          cases, the attribute is assumed to have a change, even if there is
890          ultimately no net change against its database value. SQLAlchemy in
891          most cases does not need the "old" value when a set event occurs, so
892          it skips the expense of a SQL call if the old value isn't present,
893          based on the assumption that an UPDATE of the scalar value is
894          usually needed, and in those few cases where it isn't, is less
895          expensive on average than issuing a defensive SELECT.
896
897          The "old" value is fetched unconditionally upon set only if the
898          attribute container has the ``active_history`` flag set to ``True``.
899          This flag is set typically for primary key attributes and scalar
900          object references that are not a simple many-to-one.  To set this
901          flag for any arbitrary mapped column, use the ``active_history``
902          argument with :func:`.column_property`.
903
904        :param instance: mapped instance to be tested for pending changes.
905        :param include_collections: Indicates if multivalued collections
906         should be included in the operation.  Setting this to ``False`` is a
907         way to detect only local-column based properties (i.e. scalar columns
908         or many-to-one foreign keys) that would result in an UPDATE for this
909         instance upon flush.
910
911
912
913        """  # noqa: E501
914
915        return self._proxied.is_modified(
916            instance, include_collections=include_collections
917        )
918
919    async def invalidate(self) -> None:
920        r"""Close this Session, using connection invalidation.
921
922        .. container:: class_bases
923
924            Proxied for the :class:`_asyncio.AsyncSession` class on
925            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
926
927        For a complete description, see :meth:`_orm.Session.invalidate`.
928
929        """  # noqa: E501
930
931        return await self._proxied.invalidate()
932
933    async def merge(
934        self,
935        instance: _O,
936        *,
937        load: bool = True,
938        options: Optional[Sequence[ORMOption]] = None,
939    ) -> _O:
940        r"""Copy the state of a given instance into a corresponding instance
941        within this :class:`_asyncio.AsyncSession`.
942
943        .. container:: class_bases
944
945            Proxied for the :class:`_asyncio.AsyncSession` class on
946            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
947
948        .. seealso::
949
950            :meth:`_orm.Session.merge` - main documentation for merge
951
952
953        """  # noqa: E501
954
955        return await self._proxied.merge(instance, load=load, options=options)
956
957    async def refresh(
958        self,
959        instance: object,
960        attribute_names: Optional[Iterable[str]] = None,
961        with_for_update: ForUpdateParameter = None,
962    ) -> None:
963        r"""Expire and refresh the attributes on the given instance.
964
965        .. container:: class_bases
966
967            Proxied for the :class:`_asyncio.AsyncSession` class on
968            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
969
970        A query will be issued to the database and all attributes will be
971        refreshed with their current database value.
972
973        This is the async version of the :meth:`_orm.Session.refresh` method.
974        See that method for a complete description of all options.
975
976        .. seealso::
977
978            :meth:`_orm.Session.refresh` - main documentation for refresh
979
980
981        """  # noqa: E501
982
983        return await self._proxied.refresh(
984            instance,
985            attribute_names=attribute_names,
986            with_for_update=with_for_update,
987        )
988
989    async def rollback(self) -> None:
990        r"""Rollback the current transaction in progress.
991
992        .. container:: class_bases
993
994            Proxied for the :class:`_asyncio.AsyncSession` class on
995            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
996
997        .. seealso::
998
999            :meth:`_orm.Session.rollback` - main documentation for
1000            "rollback"
1001
1002        """  # noqa: E501
1003
1004        return await self._proxied.rollback()
1005
1006    @overload
1007    async def scalar(
1008        self,
1009        statement: TypedReturnsRows[Tuple[_T]],
1010        params: Optional[_CoreAnyExecuteParams] = None,
1011        *,
1012        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1013        bind_arguments: Optional[_BindArguments] = None,
1014        **kw: Any,
1015    ) -> Optional[_T]: ...
1016
1017    @overload
1018    async def scalar(
1019        self,
1020        statement: Executable,
1021        params: Optional[_CoreAnyExecuteParams] = None,
1022        *,
1023        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1024        bind_arguments: Optional[_BindArguments] = None,
1025        **kw: Any,
1026    ) -> Any: ...
1027
1028    async def scalar(
1029        self,
1030        statement: Executable,
1031        params: Optional[_CoreAnyExecuteParams] = None,
1032        *,
1033        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1034        bind_arguments: Optional[_BindArguments] = None,
1035        **kw: Any,
1036    ) -> Any:
1037        r"""Execute a statement and return a scalar result.
1038
1039        .. container:: class_bases
1040
1041            Proxied for the :class:`_asyncio.AsyncSession` class on
1042            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
1043
1044        .. seealso::
1045
1046            :meth:`_orm.Session.scalar` - main documentation for scalar
1047
1048
1049        """  # noqa: E501
1050
1051        return await self._proxied.scalar(
1052            statement,
1053            params=params,
1054            execution_options=execution_options,
1055            bind_arguments=bind_arguments,
1056            **kw,
1057        )
1058
1059    @overload
1060    async def scalars(
1061        self,
1062        statement: TypedReturnsRows[Tuple[_T]],
1063        params: Optional[_CoreAnyExecuteParams] = None,
1064        *,
1065        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1066        bind_arguments: Optional[_BindArguments] = None,
1067        **kw: Any,
1068    ) -> ScalarResult[_T]: ...
1069
1070    @overload
1071    async def scalars(
1072        self,
1073        statement: Executable,
1074        params: Optional[_CoreAnyExecuteParams] = None,
1075        *,
1076        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1077        bind_arguments: Optional[_BindArguments] = None,
1078        **kw: Any,
1079    ) -> ScalarResult[Any]: ...
1080
1081    async def scalars(
1082        self,
1083        statement: Executable,
1084        params: Optional[_CoreAnyExecuteParams] = None,
1085        *,
1086        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1087        bind_arguments: Optional[_BindArguments] = None,
1088        **kw: Any,
1089    ) -> ScalarResult[Any]:
1090        r"""Execute a statement and return scalar results.
1091
1092        .. container:: class_bases
1093
1094            Proxied for the :class:`_asyncio.AsyncSession` class on
1095            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
1096
1097        :return: a :class:`_result.ScalarResult` object
1098
1099        .. versionadded:: 1.4.24 Added :meth:`_asyncio.AsyncSession.scalars`
1100
1101        .. versionadded:: 1.4.26 Added
1102           :meth:`_asyncio.async_scoped_session.scalars`
1103
1104        .. seealso::
1105
1106            :meth:`_orm.Session.scalars` - main documentation for scalars
1107
1108            :meth:`_asyncio.AsyncSession.stream_scalars` - streaming version
1109
1110
1111        """  # noqa: E501
1112
1113        return await self._proxied.scalars(
1114            statement,
1115            params=params,
1116            execution_options=execution_options,
1117            bind_arguments=bind_arguments,
1118            **kw,
1119        )
1120
1121    async def get(
1122        self,
1123        entity: _EntityBindKey[_O],
1124        ident: _PKIdentityArgument,
1125        *,
1126        options: Optional[Sequence[ORMOption]] = None,
1127        populate_existing: bool = False,
1128        with_for_update: ForUpdateParameter = None,
1129        identity_token: Optional[Any] = None,
1130        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1131    ) -> Union[_O, None]:
1132        r"""Return an instance based on the given primary key identifier,
1133        or ``None`` if not found.
1134
1135        .. container:: class_bases
1136
1137            Proxied for the :class:`_asyncio.AsyncSession` class on
1138            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
1139
1140        .. seealso::
1141
1142            :meth:`_orm.Session.get` - main documentation for get
1143
1144
1145
1146        """  # noqa: E501
1147
1148        result = await self._proxied.get(
1149            entity,
1150            ident,
1151            options=options,
1152            populate_existing=populate_existing,
1153            with_for_update=with_for_update,
1154            identity_token=identity_token,
1155            execution_options=execution_options,
1156        )
1157        return result
1158
1159    async def get_one(
1160        self,
1161        entity: _EntityBindKey[_O],
1162        ident: _PKIdentityArgument,
1163        *,
1164        options: Optional[Sequence[ORMOption]] = None,
1165        populate_existing: bool = False,
1166        with_for_update: ForUpdateParameter = None,
1167        identity_token: Optional[Any] = None,
1168        execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
1169    ) -> _O:
1170        r"""Return an instance based on the given primary key identifier,
1171        or raise an exception if not found.
1172
1173        .. container:: class_bases
1174
1175            Proxied for the :class:`_asyncio.AsyncSession` class on
1176            behalf of the :class:`_asyncio.scoping.async_scoped_session` class.
1177
1178        Raises ``sqlalchemy.orm.exc.NoResultFound`` if the query selects
1179        no rows.
1180
1181        ..versionadded: 2.0.22
1182
1183        .. seealso::
1184
1185            :meth:`_orm.Session.get_one` - main documentation for get_one
1186
1187
1188        """  # noqa: E501
1189
1190        return await self._proxied.get_one(
1191            entity,
1192            ident,
1193            options=options,
1194            populate_existing=populate_existing,
1195            with_for_update=with_for_update,
1196            identity_token=identity_token,
1197            execution_options=execution_options,
1198        )
1199
1200    @overload

Showing the first 1,200 of 1615 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai