Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
result.py966 linesDownload Raw Back to asyncio
1# ext/asyncio/result.py
2# Copyright (C) 2020-2026 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
7from __future__ import annotations
8
9import operator
10from typing import Any
11from typing import AsyncIterator
12from typing import Optional
13from typing import overload
14from typing import Sequence
15from typing import Tuple
16from typing import TYPE_CHECKING
17from typing import TypeVar
18
19from . import exc as async_exc
20from ... import util
21from ...engine import Result
22from ...engine.result import _NO_ROW
23from ...engine.result import _R
24from ...engine.result import _WithKeys
25from ...engine.result import FilterResult
26from ...engine.result import FrozenResult
27from ...engine.result import ResultMetaData
28from ...engine.row import Row
29from ...engine.row import RowMapping
30from ...sql.base import _generative
31from ...util.concurrency import greenlet_spawn
32from ...util.typing import Literal
33from ...util.typing import Self
34
35if TYPE_CHECKING:
36    from ...engine import CursorResult
37    from ...engine.result import _KeyIndexType
38    from ...engine.result import _UniqueFilterType
39
40_T = TypeVar("_T", bound=Any)
41_TP = TypeVar("_TP", bound=Tuple[Any, ...])
42
43
44class AsyncCommon(FilterResult[_R]):
45    __slots__ = ()
46
47    _real_result: Result[Any]
48    _metadata: ResultMetaData
49
50    async def close(self) -> None:  # type: ignore[override]
51        """Close this result."""
52
53        await greenlet_spawn(self._real_result.close)
54
55    @property
56    def closed(self) -> bool:
57        """proxies the .closed attribute of the underlying result object,
58        if any, else raises ``AttributeError``.
59
60        .. versionadded:: 2.0.0b3
61
62        """
63        return self._real_result.closed
64
65
66class AsyncResult(_WithKeys, AsyncCommon[Row[_TP]]):
67    """An asyncio wrapper around a :class:`_result.Result` object.
68
69    The :class:`_asyncio.AsyncResult` only applies to statement executions that
70    use a server-side cursor.  It is returned only from the
71    :meth:`_asyncio.AsyncConnection.stream` and
72    :meth:`_asyncio.AsyncSession.stream` methods.
73
74    .. note:: As is the case with :class:`_engine.Result`, this object is
75       used for ORM results returned by :meth:`_asyncio.AsyncSession.execute`,
76       which can yield instances of ORM mapped objects either individually or
77       within tuple-like rows.  Note that these result objects do not
78       deduplicate instances or rows automatically as is the case with the
79       legacy :class:`_orm.Query` object. For in-Python de-duplication of
80       instances or rows, use the :meth:`_asyncio.AsyncResult.unique` modifier
81       method.
82
83    .. versionadded:: 1.4
84
85    """
86
87    __slots__ = ()
88
89    _real_result: Result[_TP]
90
91    def __init__(self, real_result: Result[_TP]):
92        self._real_result = real_result
93
94        self._metadata = real_result._metadata
95        self._unique_filter_state = real_result._unique_filter_state
96        self._source_supports_scalars = real_result._source_supports_scalars
97        self._post_creational_filter = None
98
99        # BaseCursorResult pre-generates the "_row_getter".  Use that
100        # if available rather than building a second one
101        if "_row_getter" in real_result.__dict__:
102            self._set_memoized_attribute(
103                "_row_getter", real_result.__dict__["_row_getter"]
104            )
105
106    @property
107    def t(self) -> AsyncTupleResult[_TP]:
108        """Apply a "typed tuple" typing filter to returned rows.
109
110        The :attr:`_asyncio.AsyncResult.t` attribute is a synonym for
111        calling the :meth:`_asyncio.AsyncResult.tuples` method.
112
113        .. versionadded:: 2.0
114
115        """
116        return self  # type: ignore
117
118    def tuples(self) -> AsyncTupleResult[_TP]:
119        """Apply a "typed tuple" typing filter to returned rows.
120
121        This method returns the same :class:`_asyncio.AsyncResult` object
122        at runtime,
123        however annotates as returning a :class:`_asyncio.AsyncTupleResult`
124        object that will indicate to :pep:`484` typing tools that plain typed
125        ``Tuple`` instances are returned rather than rows.  This allows
126        tuple unpacking and ``__getitem__`` access of :class:`_engine.Row`
127        objects to by typed, for those cases where the statement invoked
128        itself included typing information.
129
130        .. versionadded:: 2.0
131
132        :return: the :class:`_result.AsyncTupleResult` type at typing time.
133
134        .. seealso::
135
136            :attr:`_asyncio.AsyncResult.t` - shorter synonym
137
138            :attr:`_engine.Row.t` - :class:`_engine.Row` version
139
140        """
141
142        return self  # type: ignore
143
144    @_generative
145    def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self:
146        """Apply unique filtering to the objects returned by this
147        :class:`_asyncio.AsyncResult`.
148
149        Refer to :meth:`_engine.Result.unique` in the synchronous
150        SQLAlchemy API for a complete behavioral description.
151
152        """
153        self._unique_filter_state = (set(), strategy)
154        return self
155
156    def columns(self, *col_expressions: _KeyIndexType) -> Self:
157        r"""Establish the columns that should be returned in each row.
158
159        Refer to :meth:`_engine.Result.columns` in the synchronous
160        SQLAlchemy API for a complete behavioral description.
161
162        """
163        return self._column_slices(col_expressions)
164
165    async def partitions(
166        self, size: Optional[int] = None
167    ) -> AsyncIterator[Sequence[Row[_TP]]]:
168        """Iterate through sub-lists of rows of the size given.
169
170        An async iterator is returned::
171
172            async def scroll_results(connection):
173                result = await connection.stream(select(users_table))
174
175                async for partition in result.partitions(100):
176                    print("list of rows: %s" % partition)
177
178        Refer to :meth:`_engine.Result.partitions` in the synchronous
179        SQLAlchemy API for a complete behavioral description.
180
181        """
182
183        getter = self._manyrow_getter
184
185        while True:
186            partition = await greenlet_spawn(getter, self, size)
187            if partition:
188                yield partition
189            else:
190                break
191
192    async def fetchall(self) -> Sequence[Row[_TP]]:
193        """A synonym for the :meth:`_asyncio.AsyncResult.all` method.
194
195        .. versionadded:: 2.0
196
197        """
198
199        return await greenlet_spawn(self._allrows)
200
201    async def fetchone(self) -> Optional[Row[_TP]]:
202        """Fetch one row.
203
204        When all rows are exhausted, returns None.
205
206        This method is provided for backwards compatibility with
207        SQLAlchemy 1.x.x.
208
209        To fetch the first row of a result only, use the
210        :meth:`_asyncio.AsyncResult.first` method.  To iterate through all
211        rows, iterate the :class:`_asyncio.AsyncResult` object directly.
212
213        :return: a :class:`_engine.Row` object if no filters are applied,
214         or ``None`` if no rows remain.
215
216        """
217        row = await greenlet_spawn(self._onerow_getter, self)
218        if row is _NO_ROW:
219            return None
220        else:
221            return row
222
223    async def fetchmany(
224        self, size: Optional[int] = None
225    ) -> Sequence[Row[_TP]]:
226        """Fetch many rows.
227
228        When all rows are exhausted, returns an empty list.
229
230        This method is provided for backwards compatibility with
231        SQLAlchemy 1.x.x.
232
233        To fetch rows in groups, use the
234        :meth:`._asyncio.AsyncResult.partitions` method.
235
236        :return: a list of :class:`_engine.Row` objects.
237
238        .. seealso::
239
240            :meth:`_asyncio.AsyncResult.partitions`
241
242        """
243
244        return await greenlet_spawn(self._manyrow_getter, self, size)
245
246    async def all(self) -> Sequence[Row[_TP]]:
247        """Return all rows in a list.
248
249        Closes the result set after invocation.   Subsequent invocations
250        will return an empty list.
251
252        :return: a list of :class:`_engine.Row` objects.
253
254        """
255
256        return await greenlet_spawn(self._allrows)
257
258    def __aiter__(self) -> AsyncResult[_TP]:
259        return self
260
261    async def __anext__(self) -> Row[_TP]:
262        row = await greenlet_spawn(self._onerow_getter, self)
263        if row is _NO_ROW:
264            raise StopAsyncIteration()
265        else:
266            return row
267
268    async def first(self) -> Optional[Row[_TP]]:
269        """Fetch the first row or ``None`` if no row is present.
270
271        Closes the result set and discards remaining rows.
272
273        .. note::  This method returns one **row**, e.g. tuple, by default.
274           To return exactly one single scalar value, that is, the first
275           column of the first row, use the
276           :meth:`_asyncio.AsyncResult.scalar` method,
277           or combine :meth:`_asyncio.AsyncResult.scalars` and
278           :meth:`_asyncio.AsyncResult.first`.
279
280           Additionally, in contrast to the behavior of the legacy  ORM
281           :meth:`_orm.Query.first` method, **no limit is applied** to the
282           SQL query which was invoked to produce this
283           :class:`_asyncio.AsyncResult`;
284           for a DBAPI driver that buffers results in memory before yielding
285           rows, all rows will be sent to the Python process and all but
286           the first row will be discarded.
287
288           .. seealso::
289
290                :ref:`migration_20_unify_select`
291
292        :return: a :class:`_engine.Row` object, or None
293         if no rows remain.
294
295        .. seealso::
296
297            :meth:`_asyncio.AsyncResult.scalar`
298
299            :meth:`_asyncio.AsyncResult.one`
300
301        """
302        return await greenlet_spawn(self._only_one_row, False, False, False)
303
304    async def one_or_none(self) -> Optional[Row[_TP]]:
305        """Return at most one result or raise an exception.
306
307        Returns ``None`` if the result has no rows.
308        Raises :class:`.MultipleResultsFound`
309        if multiple rows are returned.
310
311        .. versionadded:: 1.4
312
313        :return: The first :class:`_engine.Row` or ``None`` if no row
314         is available.
315
316        :raises: :class:`.MultipleResultsFound`
317
318        .. seealso::
319
320            :meth:`_asyncio.AsyncResult.first`
321
322            :meth:`_asyncio.AsyncResult.one`
323
324        """
325        return await greenlet_spawn(self._only_one_row, True, False, False)
326
327    @overload
328    async def scalar_one(self: AsyncResult[Tuple[_T]]) -> _T: ...
329
330    @overload
331    async def scalar_one(self) -> Any: ...
332
333    async def scalar_one(self) -> Any:
334        """Return exactly one scalar result or raise an exception.
335
336        This is equivalent to calling :meth:`_asyncio.AsyncResult.scalars` and
337        then :meth:`_asyncio.AsyncScalarResult.one`.
338
339        .. seealso::
340
341            :meth:`_asyncio.AsyncScalarResult.one`
342
343            :meth:`_asyncio.AsyncResult.scalars`
344
345        """
346        return await greenlet_spawn(self._only_one_row, True, True, True)
347
348    @overload
349    async def scalar_one_or_none(
350        self: AsyncResult[Tuple[_T]],
351    ) -> Optional[_T]: ...
352
353    @overload
354    async def scalar_one_or_none(self) -> Optional[Any]: ...
355
356    async def scalar_one_or_none(self) -> Optional[Any]:
357        """Return exactly one scalar result or ``None``.
358
359        This is equivalent to calling :meth:`_asyncio.AsyncResult.scalars` and
360        then :meth:`_asyncio.AsyncScalarResult.one_or_none`.
361
362        .. seealso::
363
364            :meth:`_asyncio.AsyncScalarResult.one_or_none`
365
366            :meth:`_asyncio.AsyncResult.scalars`
367
368        """
369        return await greenlet_spawn(self._only_one_row, True, False, True)
370
371    async def one(self) -> Row[_TP]:
372        """Return exactly one row or raise an exception.
373
374        Raises :class:`.NoResultFound` if the result returns no
375        rows, or :class:`.MultipleResultsFound` if multiple rows
376        would be returned.
377
378        .. note::  This method returns one **row**, e.g. tuple, by default.
379           To return exactly one single scalar value, that is, the first
380           column of the first row, use the
381           :meth:`_asyncio.AsyncResult.scalar_one` method, or combine
382           :meth:`_asyncio.AsyncResult.scalars` and
383           :meth:`_asyncio.AsyncResult.one`.
384
385        .. versionadded:: 1.4
386
387        :return: The first :class:`_engine.Row`.
388
389        :raises: :class:`.MultipleResultsFound`, :class:`.NoResultFound`
390
391        .. seealso::
392
393            :meth:`_asyncio.AsyncResult.first`
394
395            :meth:`_asyncio.AsyncResult.one_or_none`
396
397            :meth:`_asyncio.AsyncResult.scalar_one`
398
399        """
400        return await greenlet_spawn(self._only_one_row, True, True, False)
401
402    @overload
403    async def scalar(self: AsyncResult[Tuple[_T]]) -> Optional[_T]: ...
404
405    @overload
406    async def scalar(self) -> Any: ...
407
408    async def scalar(self) -> Any:
409        """Fetch the first column of the first row, and close the result set.
410
411        Returns ``None`` if there are no rows to fetch.
412
413        No validation is performed to test if additional rows remain.
414
415        After calling this method, the object is fully closed,
416        e.g. the :meth:`_engine.CursorResult.close`
417        method will have been called.
418
419        :return: a Python scalar value, or ``None`` if no rows remain.
420
421        """
422        return await greenlet_spawn(self._only_one_row, False, False, True)
423
424    async def freeze(self) -> FrozenResult[_TP]:
425        """Return a callable object that will produce copies of this
426        :class:`_asyncio.AsyncResult` when invoked.
427
428        The callable object returned is an instance of
429        :class:`_engine.FrozenResult`.
430
431        This is used for result set caching.  The method must be called
432        on the result when it has been unconsumed, and calling the method
433        will consume the result fully.   When the :class:`_engine.FrozenResult`
434        is retrieved from a cache, it can be called any number of times where
435        it will produce a new :class:`_engine.Result` object each time
436        against its stored set of rows.
437
438        .. seealso::
439
440            :ref:`do_orm_execute_re_executing` - example usage within the
441            ORM to implement a result-set cache.
442
443        """
444
445        return await greenlet_spawn(FrozenResult, self)
446
447    @overload
448    def scalars(
449        self: AsyncResult[Tuple[_T]], index: Literal[0]
450    ) -> AsyncScalarResult[_T]: ...
451
452    @overload
453    def scalars(self: AsyncResult[Tuple[_T]]) -> AsyncScalarResult[_T]: ...
454
455    @overload
456    def scalars(self, index: _KeyIndexType = 0) -> AsyncScalarResult[Any]: ...
457
458    def scalars(self, index: _KeyIndexType = 0) -> AsyncScalarResult[Any]:
459        """Return an :class:`_asyncio.AsyncScalarResult` filtering object which
460        will return single elements rather than :class:`_row.Row` objects.
461
462        Refer to :meth:`_result.Result.scalars` in the synchronous
463        SQLAlchemy API for a complete behavioral description.
464
465        :param index: integer or row key indicating the column to be fetched
466         from each row, defaults to ``0`` indicating the first column.
467
468        :return: a new :class:`_asyncio.AsyncScalarResult` filtering object
469         referring to this :class:`_asyncio.AsyncResult` object.
470
471        """
472        return AsyncScalarResult(self._real_result, index)
473
474    def mappings(self) -> AsyncMappingResult:
475        """Apply a mappings filter to returned rows, returning an instance of
476        :class:`_asyncio.AsyncMappingResult`.
477
478        When this filter is applied, fetching rows will return
479        :class:`_engine.RowMapping` objects instead of :class:`_engine.Row`
480        objects.
481
482        :return: a new :class:`_asyncio.AsyncMappingResult` filtering object
483         referring to the underlying :class:`_result.Result` object.
484
485        """
486
487        return AsyncMappingResult(self._real_result)
488
489
490class AsyncScalarResult(AsyncCommon[_R]):
491    """A wrapper for a :class:`_asyncio.AsyncResult` that returns scalar values
492    rather than :class:`_row.Row` values.
493
494    The :class:`_asyncio.AsyncScalarResult` object is acquired by calling the
495    :meth:`_asyncio.AsyncResult.scalars` method.
496
497    Refer to the :class:`_result.ScalarResult` object in the synchronous
498    SQLAlchemy API for a complete behavioral description.
499
500    .. versionadded:: 1.4
501
502    """
503
504    __slots__ = ()
505
506    _generate_rows = False
507
508    def __init__(self, real_result: Result[Any], index: _KeyIndexType):
509        self._real_result = real_result
510
511        if real_result._source_supports_scalars:
512            self._metadata = real_result._metadata
513            self._post_creational_filter = None
514        else:
515            self._metadata = real_result._metadata._reduce([index])
516            self._post_creational_filter = operator.itemgetter(0)
517
518        self._unique_filter_state = real_result._unique_filter_state
519
520    def unique(
521        self,
522        strategy: Optional[_UniqueFilterType] = None,
523    ) -> Self:
524        """Apply unique filtering to the objects returned by this
525        :class:`_asyncio.AsyncScalarResult`.
526
527        See :meth:`_asyncio.AsyncResult.unique` for usage details.
528
529        """
530        self._unique_filter_state = (set(), strategy)
531        return self
532
533    async def partitions(
534        self, size: Optional[int] = None
535    ) -> AsyncIterator[Sequence[_R]]:
536        """Iterate through sub-lists of elements of the size given.
537
538        Equivalent to :meth:`_asyncio.AsyncResult.partitions` except that
539        scalar values, rather than :class:`_engine.Row` objects,
540        are returned.
541
542        """
543
544        getter = self._manyrow_getter
545
546        while True:
547            partition = await greenlet_spawn(getter, self, size)
548            if partition:
549                yield partition
550            else:
551                break
552
553    async def fetchall(self) -> Sequence[_R]:
554        """A synonym for the :meth:`_asyncio.AsyncScalarResult.all` method."""
555
556        return await greenlet_spawn(self._allrows)
557
558    async def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]:
559        """Fetch many objects.
560
561        Equivalent to :meth:`_asyncio.AsyncResult.fetchmany` except that
562        scalar values, rather than :class:`_engine.Row` objects,
563        are returned.
564
565        """
566        return await greenlet_spawn(self._manyrow_getter, self, size)
567
568    async def all(self) -> Sequence[_R]:
569        """Return all scalar values in a list.
570
571        Equivalent to :meth:`_asyncio.AsyncResult.all` except that
572        scalar values, rather than :class:`_engine.Row` objects,
573        are returned.
574
575        """
576        return await greenlet_spawn(self._allrows)
577
578    def __aiter__(self) -> AsyncScalarResult[_R]:
579        return self
580
581    async def __anext__(self) -> _R:
582        row = await greenlet_spawn(self._onerow_getter, self)
583        if row is _NO_ROW:
584            raise StopAsyncIteration()
585        else:
586            return row
587
588    async def first(self) -> Optional[_R]:
589        """Fetch the first object or ``None`` if no object is present.
590
591        Equivalent to :meth:`_asyncio.AsyncResult.first` except that
592        scalar values, rather than :class:`_engine.Row` objects,
593        are returned.
594
595        """
596        return await greenlet_spawn(self._only_one_row, False, False, False)
597
598    async def one_or_none(self) -> Optional[_R]:
599        """Return at most one object or raise an exception.
600
601        Equivalent to :meth:`_asyncio.AsyncResult.one_or_none` except that
602        scalar values, rather than :class:`_engine.Row` objects,
603        are returned.
604
605        """
606        return await greenlet_spawn(self._only_one_row, True, False, False)
607
608    async def one(self) -> _R:
609        """Return exactly one object or raise an exception.
610
611        Equivalent to :meth:`_asyncio.AsyncResult.one` except that
612        scalar values, rather than :class:`_engine.Row` objects,
613        are returned.
614
615        """
616        return await greenlet_spawn(self._only_one_row, True, True, False)
617
618
619class AsyncMappingResult(_WithKeys, AsyncCommon[RowMapping]):
620    """A wrapper for a :class:`_asyncio.AsyncResult` that returns dictionary
621    values rather than :class:`_engine.Row` values.
622
623    The :class:`_asyncio.AsyncMappingResult` object is acquired by calling the
624    :meth:`_asyncio.AsyncResult.mappings` method.
625
626    Refer to the :class:`_result.MappingResult` object in the synchronous
627    SQLAlchemy API for a complete behavioral description.
628
629    .. versionadded:: 1.4
630
631    """
632
633    __slots__ = ()
634
635    _generate_rows = True
636
637    _post_creational_filter = operator.attrgetter("_mapping")
638
639    def __init__(self, result: Result[Any]):
640        self._real_result = result
641        self._unique_filter_state = result._unique_filter_state
642        self._metadata = result._metadata
643        if result._source_supports_scalars:
644            self._metadata = self._metadata._reduce([0])
645
646    def unique(
647        self,
648        strategy: Optional[_UniqueFilterType] = None,
649    ) -> Self:
650        """Apply unique filtering to the objects returned by this
651        :class:`_asyncio.AsyncMappingResult`.
652
653        See :meth:`_asyncio.AsyncResult.unique` for usage details.
654
655        """
656        self._unique_filter_state = (set(), strategy)
657        return self
658
659    def columns(self, *col_expressions: _KeyIndexType) -> Self:
660        r"""Establish the columns that should be returned in each row."""
661        return self._column_slices(col_expressions)
662
663    async def partitions(
664        self, size: Optional[int] = None
665    ) -> AsyncIterator[Sequence[RowMapping]]:
666        """Iterate through sub-lists of elements of the size given.
667
668        Equivalent to :meth:`_asyncio.AsyncResult.partitions` except that
669        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
670        objects, are returned.
671
672        """
673
674        getter = self._manyrow_getter
675
676        while True:
677            partition = await greenlet_spawn(getter, self, size)
678            if partition:
679                yield partition
680            else:
681                break
682
683    async def fetchall(self) -> Sequence[RowMapping]:
684        """A synonym for the :meth:`_asyncio.AsyncMappingResult.all` method."""
685
686        return await greenlet_spawn(self._allrows)
687
688    async def fetchone(self) -> Optional[RowMapping]:
689        """Fetch one object.
690
691        Equivalent to :meth:`_asyncio.AsyncResult.fetchone` except that
692        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
693        objects, are returned.
694
695        """
696
697        row = await greenlet_spawn(self._onerow_getter, self)
698        if row is _NO_ROW:
699            return None
700        else:
701            return row
702
703    async def fetchmany(
704        self, size: Optional[int] = None
705    ) -> Sequence[RowMapping]:
706        """Fetch many rows.
707
708        Equivalent to :meth:`_asyncio.AsyncResult.fetchmany` except that
709        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
710        objects, are returned.
711
712        """
713
714        return await greenlet_spawn(self._manyrow_getter, self, size)
715
716    async def all(self) -> Sequence[RowMapping]:
717        """Return all rows in a list.
718
719        Equivalent to :meth:`_asyncio.AsyncResult.all` except that
720        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
721        objects, are returned.
722
723        """
724
725        return await greenlet_spawn(self._allrows)
726
727    def __aiter__(self) -> AsyncMappingResult:
728        return self
729
730    async def __anext__(self) -> RowMapping:
731        row = await greenlet_spawn(self._onerow_getter, self)
732        if row is _NO_ROW:
733            raise StopAsyncIteration()
734        else:
735            return row
736
737    async def first(self) -> Optional[RowMapping]:
738        """Fetch the first object or ``None`` if no object is present.
739
740        Equivalent to :meth:`_asyncio.AsyncResult.first` except that
741        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
742        objects, are returned.
743
744        """
745        return await greenlet_spawn(self._only_one_row, False, False, False)
746
747    async def one_or_none(self) -> Optional[RowMapping]:
748        """Return at most one object or raise an exception.
749
750        Equivalent to :meth:`_asyncio.AsyncResult.one_or_none` except that
751        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
752        objects, are returned.
753
754        """
755        return await greenlet_spawn(self._only_one_row, True, False, False)
756
757    async def one(self) -> RowMapping:
758        """Return exactly one object or raise an exception.
759
760        Equivalent to :meth:`_asyncio.AsyncResult.one` except that
761        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
762        objects, are returned.
763
764        """
765        return await greenlet_spawn(self._only_one_row, True, True, False)
766
767
768class AsyncTupleResult(AsyncCommon[_R], util.TypingOnly):
769    """A :class:`_asyncio.AsyncResult` that's typed as returning plain
770    Python tuples instead of rows.
771
772    Since :class:`_engine.Row` acts like a tuple in every way already,
773    this class is a typing only class, regular :class:`_asyncio.AsyncResult` is
774    still used at runtime.
775
776    """
777
778    __slots__ = ()
779
780    if TYPE_CHECKING:
781
782        async def partitions(
783            self, size: Optional[int] = None
784        ) -> AsyncIterator[Sequence[_R]]:
785            """Iterate through sub-lists of elements of the size given.
786
787            Equivalent to :meth:`_result.Result.partitions` except that
788            tuple values, rather than :class:`_engine.Row` objects,
789            are returned.
790
791            """
792            ...
793
794        async def fetchone(self) -> Optional[_R]:
795            """Fetch one tuple.
796
797            Equivalent to :meth:`_result.Result.fetchone` except that
798            tuple values, rather than :class:`_engine.Row`
799            objects, are returned.
800
801            """
802            ...
803
804        async def fetchall(self) -> Sequence[_R]:
805            """A synonym for the :meth:`_engine.ScalarResult.all` method."""
806            ...
807
808        async def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]:
809            """Fetch many objects.
810
811            Equivalent to :meth:`_result.Result.fetchmany` except that
812            tuple values, rather than :class:`_engine.Row` objects,
813            are returned.
814
815            """
816            ...
817
818        async def all(self) -> Sequence[_R]:  # noqa: A001
819            """Return all scalar values in a list.
820
821            Equivalent to :meth:`_result.Result.all` except that
822            tuple values, rather than :class:`_engine.Row` objects,
823            are returned.
824
825            """
826            ...
827
828        def __aiter__(self) -> AsyncIterator[_R]: ...
829
830        async def __anext__(self) -> _R: ...
831
832        async def first(self) -> Optional[_R]:
833            """Fetch the first object or ``None`` if no object is present.
834
835            Equivalent to :meth:`_result.Result.first` except that
836            tuple values, rather than :class:`_engine.Row` objects,
837            are returned.
838
839
840            """
841            ...
842
843        async def one_or_none(self) -> Optional[_R]:
844            """Return at most one object or raise an exception.
845
846            Equivalent to :meth:`_result.Result.one_or_none` except that
847            tuple values, rather than :class:`_engine.Row` objects,
848            are returned.
849
850            """
851            ...
852
853        async def one(self) -> _R:
854            """Return exactly one object or raise an exception.
855
856            Equivalent to :meth:`_result.Result.one` except that
857            tuple values, rather than :class:`_engine.Row` objects,
858            are returned.
859
860            """
861            ...
862
863        @overload
864        async def scalar_one(self: AsyncTupleResult[Tuple[_T]]) -> _T: ...
865
866        @overload
867        async def scalar_one(self) -> Any: ...
868
869        async def scalar_one(self) -> Any:
870            """Return exactly one scalar result or raise an exception.
871
872            This is equivalent to calling :meth:`_engine.Result.scalars`
873            and then :meth:`_engine.AsyncScalarResult.one`.
874
875            .. seealso::
876
877                :meth:`_engine.AsyncScalarResult.one`
878
879                :meth:`_engine.Result.scalars`
880
881            """
882            ...
883
884        @overload
885        async def scalar_one_or_none(
886            self: AsyncTupleResult[Tuple[_T]],
887        ) -> Optional[_T]: ...
888
889        @overload
890        async def scalar_one_or_none(self) -> Optional[Any]: ...
891
892        async def scalar_one_or_none(self) -> Optional[Any]:
893            """Return exactly one or no scalar result.
894
895            This is equivalent to calling :meth:`_engine.Result.scalars`
896            and then :meth:`_engine.AsyncScalarResult.one_or_none`.
897
898            .. seealso::
899
900                :meth:`_engine.AsyncScalarResult.one_or_none`
901
902                :meth:`_engine.Result.scalars`
903
904            """
905            ...
906
907        @overload
908        async def scalar(
909            self: AsyncTupleResult[Tuple[_T]],
910        ) -> Optional[_T]: ...
911
912        @overload
913        async def scalar(self) -> Any: ...
914
915        async def scalar(self) -> Any:
916            """Fetch the first column of the first row, and close the result
917            set.
918
919            Returns ``None`` if there are no rows to fetch.
920
921            No validation is performed to test if additional rows remain.
922
923            After calling this method, the object is fully closed,
924            e.g. the :meth:`_engine.CursorResult.close`
925            method will have been called.
926
927            :return: a Python scalar value , or ``None`` if no rows remain.
928
929            """
930            ...
931
932
933_RT = TypeVar("_RT", bound="Result[Any]")
934
935
936async def _ensure_sync_result(result: _RT, calling_method: Any) -> _RT:
937    cursor_result: CursorResult[Any]
938
939    try:
940        is_cursor = result._is_cursor
941    except AttributeError:
942        # legacy execute(DefaultGenerator) case
943        return result
944
945    if not is_cursor:
946        cursor_result = getattr(result, "raw", None)  # type: ignore
947    else:
948        cursor_result = result  # type: ignore
949    if cursor_result and cursor_result.context._is_server_side:
950        await greenlet_spawn(cursor_result.close)
951        raise async_exc.AsyncMethodRequired(
952            "Can't use the %s.%s() method with a "
953            "server-side cursor. "
954            "Use the %s.stream() method for an async "
955            "streaming result set."
956            % (
957                calling_method.__self__.__class__.__name__,
958                calling_method.__name__,
959                calling_method.__self__.__class__.__name__,
960            )
961        )
962
963    if is_cursor and cursor_result.cursor is not None:
964        await cursor_result.cursor._async_soft_close()
965    return result
966 
codekingpro/portable-devtools · Team Ai