1# engine/result.py 
    2# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 
    3# <see AUTHORS file> 
    4# 
    5# This module is part of SQLAlchemy and is released under 
    6# the MIT License: https://www.opensource.org/licenses/mit-license.php 
    7 
    8"""Define generic result set constructs.""" 
    9 
    10from __future__ import annotations 
    11 
    12from enum import Enum 
    13import functools 
    14import itertools 
    15import operator 
    16import typing 
    17from typing import Any 
    18from typing import Callable 
    19from typing import cast 
    20from typing import Dict 
    21from typing import Generic 
    22from typing import Iterable 
    23from typing import Iterator 
    24from typing import List 
    25from typing import Literal 
    26from typing import Mapping 
    27from typing import NoReturn 
    28from typing import Optional 
    29from typing import overload 
    30from typing import Sequence 
    31from typing import Set 
    32from typing import Tuple 
    33from typing import TYPE_CHECKING 
    34from typing import TypeVar 
    35from typing import Union 
    36 
    37from ._util_cy import tuplegetter as tuplegetter 
    38from .row import Row 
    39from .row import RowMapping 
    40from .. import exc 
    41from .. import util 
    42from ..sql.base import _generative 
    43from ..sql.base import HasMemoized 
    44from ..sql.base import InPlaceGenerative 
    45from ..util import deprecated 
    46from ..util import HasMemoized_ro_memoized_attribute 
    47from ..util import NONE_SET 
    48from ..util.typing import Self 
    49from ..util.typing import TupleAny 
    50from ..util.typing import TypeVarTuple 
    51from ..util.typing import Unpack 
    52 
    53if typing.TYPE_CHECKING: 
    54    from ..sql.elements import SQLCoreOperations 
    55    from ..sql.type_api import _ResultProcessorType 
    56 
    57_KeyType = Union[str, "SQLCoreOperations[Any]"] 
    58_KeyIndexType = Union[_KeyType, int] 
    59 
    60# is overridden in cursor using _CursorKeyMapRecType 
    61_KeyMapRecType = Any 
    62 
    63_KeyMapType = Mapping[_KeyType, _KeyMapRecType] 
    64 
    65 
    66_RowData = Union[Row[Unpack[TupleAny]], RowMapping, Any] 
    67"""A generic form of "row" that accommodates for the different kinds of 
    68"rows" that different result objects return, including row, row mapping, and 
    69scalar values""" 
    70 
    71 
    72_R = TypeVar("_R", bound=_RowData) 
    73_T = TypeVar("_T", bound=Any) 
    74_Ts = TypeVarTuple("_Ts") 
    75 
    76_InterimRowType = Union[_R, TupleAny] 
    77"""a catchall "anything" kind of return type that can be applied 
    78across all the result types 
    79 
    80""" 
    81 
    82_InterimSupportsScalarsRowType = Union[Row[Unpack[TupleAny]], Any] 
    83 
    84_ProcessorsType = Sequence[Optional["_ResultProcessorType[Any]"]] 
    85_TupleGetterType = Callable[[Sequence[Any]], Sequence[Any]] 
    86_UniqueFilterType = Callable[[Any], Any] 
    87_UniqueFilterStateType = Tuple[Set[Any], Optional[_UniqueFilterType]] 
    88 
    89 
    90class ResultMetaData: 
    91    """Base for metadata about result rows.""" 
    92 
    93    __slots__ = () 
    94 
    95    _tuplefilter: Optional[_TupleGetterType] = None 
    96    _translated_indexes: Optional[Sequence[int]] = None 
    97    _unique_filters: Optional[Sequence[Callable[[Any], Any]]] = None 
    98    _keymap: _KeyMapType 
    99    _keys: Sequence[str] 
    100    _processors: Optional[_ProcessorsType] 
    101    _key_to_index: Dict[_KeyType, int] 
    102 
    103    @property 
    104    def keys(self) -> RMKeyView: 
    105        return RMKeyView(self) 
    106 
    107    def _has_key(self, key: object) -> bool: 
    108        raise NotImplementedError() 
    109 
    110    def _for_freeze(self) -> ResultMetaData: 
    111        raise NotImplementedError() 
    112 
    113    @overload 
    114    def _key_fallback( 
    115        self, key: Any, err: Optional[Exception], raiseerr: Literal[True] = ... 
    116    ) -> NoReturn: ... 
    117 
    118    @overload 
    119    def _key_fallback( 
    120        self, 
    121        key: Any, 
    122        err: Optional[Exception], 
    123        raiseerr: Literal[False] = ..., 
    124    ) -> None: ... 
    125 
    126    @overload 
    127    def _key_fallback( 
    128        self, key: Any, err: Optional[Exception], raiseerr: bool = ... 
    129    ) -> Optional[NoReturn]: ... 
    130 
    131    def _key_fallback( 
    132        self, key: Any, err: Optional[Exception], raiseerr: bool = True 
    133    ) -> Optional[NoReturn]: 
    134        assert raiseerr 
    135        raise KeyError(key) from err 
    136 
    137    def _raise_for_ambiguous_column_name( 
    138        self, rec: _KeyMapRecType 
    139    ) -> NoReturn: 
    140        raise NotImplementedError( 
    141            "ambiguous column name logic is implemented for " 
    142            "CursorResultMetaData" 
    143        ) 
    144 
    145    def _index_for_key( 
    146        self, key: _KeyIndexType, raiseerr: bool 
    147    ) -> Optional[int]: 
    148        raise NotImplementedError() 
    149 
    150    def _indexes_for_keys( 
    151        self, keys: Sequence[_KeyIndexType] 
    152    ) -> Sequence[int]: 
    153        raise NotImplementedError() 
    154 
    155    def _metadata_for_keys( 
    156        self, keys: Sequence[_KeyIndexType] 
    157    ) -> Iterator[_KeyMapRecType]: 
    158        raise NotImplementedError() 
    159 
    160    def _reduce(self, keys: Sequence[_KeyIndexType]) -> ResultMetaData: 
    161        raise NotImplementedError() 
    162 
    163    def _getter( 
    164        self, key: Any, raiseerr: bool = True 
    165    ) -> Optional[Callable[[Row[Unpack[TupleAny]]], Any]]: 
    166        index = self._index_for_key(key, raiseerr) 
    167 
    168        if index is not None: 
    169            return operator.itemgetter(index) 
    170        else: 
    171            return None 
    172 
    173    def _row_as_tuple_getter( 
    174        self, keys: Sequence[_KeyIndexType] 
    175    ) -> _TupleGetterType: 
    176        indexes = self._indexes_for_keys(keys) 
    177        return tuplegetter(*indexes) 
    178 
    179    def _make_key_to_index( 
    180        self, keymap: Mapping[_KeyType, Sequence[Any]], index: int 
    181    ) -> Dict[_KeyType, int]: 
    182        return { 
    183            key: rec[index] 
    184            for key, rec in keymap.items() 
    185            if rec[index] is not None 
    186        } 
    187 
    188    def _key_not_found(self, key: Any, attr_error: bool) -> NoReturn: 
    189        if key in self._keymap: 
    190            # the index must be none in this case 
    191            self._raise_for_ambiguous_column_name(self._keymap[key]) 
    192        else: 
    193            # unknown key 
    194            if attr_error: 
    195                try: 
    196                    self._key_fallback(key, None) 
    197                except KeyError as ke: 
    198                    raise AttributeError(ke.args[0]) from ke 
    199            else: 
    200                self._key_fallback(key, None) 
    201 
    202    @property 
    203    def _effective_processors(self) -> Optional[_ProcessorsType]: 
    204        if not self._processors or NONE_SET.issuperset(self._processors): 
    205            return None 
    206        else: 
    207            return self._processors 
    208 
    209 
    210class RMKeyView(typing.KeysView[Any]): 
    211    __slots__ = ("_parent", "_keys") 
    212 
    213    _parent: ResultMetaData 
    214    _keys: Sequence[str] 
    215 
    216    def __init__(self, parent: ResultMetaData): 
    217        self._parent = parent 
    218        self._keys = [k for k in parent._keys if k is not None] 
    219 
    220    def __len__(self) -> int: 
    221        return len(self._keys) 
    222 
    223    def __repr__(self) -> str: 
    224        return "{0.__class__.__name__}({0._keys!r})".format(self) 
    225 
    226    def __iter__(self) -> Iterator[str]: 
    227        return iter(self._keys) 
    228 
    229    def __contains__(self, item: Any) -> bool: 
    230        if isinstance(item, int): 
    231            return False 
    232 
    233        # note this also includes special key fallback behaviors 
    234        # which also don't seem to be tested in test_resultset right now 
    235        return self._parent._has_key(item) 
    236 
    237    def __eq__(self, other: Any) -> bool: 
    238        return list(other) == list(self) 
    239 
    240    def __ne__(self, other: Any) -> bool: 
    241        return list(other) != list(self) 
    242 
    243 
    244class SimpleResultMetaData(ResultMetaData): 
    245    """result metadata for in-memory collections.""" 
    246 
    247    __slots__ = ( 
    248        "_keys", 
    249        "_keymap", 
    250        "_processors", 
    251        "_tuplefilter", 
    252        "_translated_indexes", 
    253        "_unique_filters", 
    254        "_key_to_index", 
    255    ) 
    256 
    257    _keys: Sequence[str] 
    258 
    259    def __init__( 
    260        self, 
    261        keys: Sequence[str], 
    262        extra: Optional[Sequence[Any]] = None, 
    263        _processors: Optional[_ProcessorsType] = None, 
    264        _tuplefilter: Optional[_TupleGetterType] = None, 
    265        _translated_indexes: Optional[Sequence[int]] = None, 
    266        _unique_filters: Optional[Sequence[Callable[[Any], Any]]] = None, 
    267    ): 
    268        self._keys = list(keys) 
    269        self._tuplefilter = _tuplefilter 
    270        self._translated_indexes = _translated_indexes 
    271        self._unique_filters = _unique_filters 
    272        if extra: 
    273            assert len(self._keys) == len(extra) 
    274            recs_names = [ 
    275                ( 
    276                    (name,) + (extras if extras else ()), 
    277                    (index, name, extras), 
    278                ) 
    279                for index, (name, extras) in enumerate(zip(self._keys, extra)) 
    280            ] 
    281        else: 
    282            recs_names = [ 
    283                ((name,), (index, name, ())) 
    284                for index, name in enumerate(self._keys) 
    285            ] 
    286 
    287        self._keymap = {key: rec for keys, rec in recs_names for key in keys} 
    288 
    289        self._processors = _processors 
    290 
    291        self._key_to_index = self._make_key_to_index(self._keymap, 0) 
    292 
    293    def _has_key(self, key: object) -> bool: 
    294        return key in self._keymap 
    295 
    296    def _for_freeze(self) -> ResultMetaData: 
    297        unique_filters = self._unique_filters 
    298        if unique_filters and self._tuplefilter: 
    299            unique_filters = self._tuplefilter(unique_filters) 
    300 
    301        # TODO: are we freezing the result with or without uniqueness 
    302        # applied? 
    303        return SimpleResultMetaData( 
    304            self._keys, 
    305            extra=[self._keymap[key][2] for key in self._keys], 
    306            _unique_filters=unique_filters, 
    307        ) 
    308 
    309    def __getstate__(self) -> Dict[str, Any]: 
    310        return { 
    311            "_keys": self._keys, 
    312            "_translated_indexes": self._translated_indexes, 
    313        } 
    314 
    315    def __setstate__(self, state: Dict[str, Any]) -> None: 
    316        if state["_translated_indexes"]: 
    317            _translated_indexes = state["_translated_indexes"] 
    318            _tuplefilter = tuplegetter(*_translated_indexes) 
    319        else: 
    320            _translated_indexes = _tuplefilter = None 
    321        self.__init__(  # type: ignore 
    322            state["_keys"], 
    323            _translated_indexes=_translated_indexes, 
    324            _tuplefilter=_tuplefilter, 
    325        ) 
    326 
    327    def _index_for_key(self, key: Any, raiseerr: bool = True) -> int: 
    328        if isinstance(key, int): 
    329            key = self._keys[key] 
    330        try: 
    331            rec = self._keymap[key] 
    332        except KeyError as ke: 
    333            rec = self._key_fallback(key, ke, raiseerr) 
    334 
    335        return rec[0]  # type: ignore[no-any-return] 
    336 
    337    def _indexes_for_keys(self, keys: Sequence[Any]) -> Sequence[int]: 
    338        return [self._keymap[key][0] for key in keys] 
    339 
    340    def _metadata_for_keys( 
    341        self, keys: Sequence[Any] 
    342    ) -> Iterator[_KeyMapRecType]: 
    343        for key in keys: 
    344            if isinstance(key, int): 
    345                key = self._keys[key] 
    346 
    347            try: 
    348                rec = self._keymap[key] 
    349            except KeyError as ke: 
    350                rec = self._key_fallback(key, ke, True) 
    351 
    352            yield rec 
    353 
    354    def _reduce(self, keys: Sequence[Any]) -> ResultMetaData: 
    355        try: 
    356            metadata_for_keys = [ 
    357                self._keymap[self._keys[key] if isinstance(key, int) else key] 
    358                for key in keys 
    359            ] 
    360        except KeyError as ke: 
    361            self._key_fallback(ke.args[0], ke, True) 
    362 
    363        indexes: Sequence[int] 
    364        new_keys: Sequence[str] 
    365        extra: Sequence[Any] 
    366        indexes, new_keys, extra = zip(*metadata_for_keys) 
    367 
    368        if self._translated_indexes: 
    369            indexes = [self._translated_indexes[idx] for idx in indexes] 
    370 
    371        tup = tuplegetter(*indexes) 
    372 
    373        new_metadata = SimpleResultMetaData( 
    374            new_keys, 
    375            extra=extra, 
    376            _tuplefilter=tup, 
    377            _translated_indexes=indexes, 
    378            _processors=self._processors, 
    379            _unique_filters=self._unique_filters, 
    380        ) 
    381 
    382        return new_metadata 
    383 
    384 
    385def result_tuple( 
    386    fields: Sequence[str], extra: Optional[Any] = None 
    387) -> Callable[[Iterable[Any]], Row[Unpack[TupleAny]]]: 
    388    parent = SimpleResultMetaData(fields, extra) 
    389    return functools.partial( 
    390        Row, parent, parent._effective_processors, parent._key_to_index 
    391    ) 
    392 
    393 
    394# a symbol that indicates to internal Result methods that 
    395# "no row is returned".  We can't use None for those cases where a scalar 
    396# filter is applied to rows. 
    397class _NoRow(Enum): 
    398    _NO_ROW = 0 
    399 
    400 
    401_NO_ROW = _NoRow._NO_ROW 
    402 
    403 
    404class ResultInternal(InPlaceGenerative, Generic[_R]): 
    405    __slots__ = () 
    406 
    407    _real_result: Optional[Result[Unpack[TupleAny]]] = None 
    408    _generate_rows: bool = True 
    409    _row_logging_fn: Optional[Callable[[Any], Any]] 
    410 
    411    _unique_filter_state: Optional[_UniqueFilterStateType] = None 
    412    _post_creational_filter: Optional[Callable[[Any], Any]] = None 
    413    _is_cursor = False 
    414 
    415    _metadata: ResultMetaData 
    416 
    417    _source_supports_scalars: bool 
    418 
    419    def _fetchiter_impl( 
    420        self, 
    421    ) -> Iterator[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    422        raise NotImplementedError() 
    423 
    424    def _fetchone_impl( 
    425        self, hard_close: bool = False 
    426    ) -> Optional[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    427        raise NotImplementedError() 
    428 
    429    def _fetchmany_impl( 
    430        self, size: Optional[int] = None 
    431    ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    432        raise NotImplementedError() 
    433 
    434    def _fetchall_impl( 
    435        self, 
    436    ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    437        raise NotImplementedError() 
    438 
    439    def _soft_close(self, hard: bool = False) -> None: 
    440        raise NotImplementedError() 
    441 
    442    @HasMemoized_ro_memoized_attribute 
    443    def _row_getter(self) -> Optional[Callable[..., _R]]: 
    444        real_result: Result[Unpack[TupleAny]] = ( 
    445            self._real_result 
    446            if self._real_result 
    447            else cast("Result[Unpack[TupleAny]]", self) 
    448        ) 
    449 
    450        if real_result._source_supports_scalars: 
    451            if not self._generate_rows: 
    452                return None 
    453            else: 
    454                _proc = Row 
    455 
    456                def process_row( 
    457                    metadata: ResultMetaData, 
    458                    processors: Optional[_ProcessorsType], 
    459                    key_to_index: Dict[_KeyType, int], 
    460                    scalar_obj: Any, 
    461                ) -> Row[Unpack[TupleAny]]: 
    462                    return _proc( 
    463                        metadata, processors, key_to_index, (scalar_obj,) 
    464                    ) 
    465 
    466        else: 
    467            process_row = Row  # type: ignore 
    468 
    469        metadata = self._metadata 
    470 
    471        key_to_index = metadata._key_to_index 
    472        processors = metadata._effective_processors 
    473        tf = metadata._tuplefilter 
    474 
    475        if tf and not real_result._source_supports_scalars: 
    476            if processors: 
    477                processors = tf(processors) 
    478 
    479            _make_row_orig: Callable[..., _R] = functools.partial(  # type: ignore  # noqa E501 
    480                process_row, metadata, processors, key_to_index 
    481            ) 
    482 
    483            fixed_tf = tf 
    484 
    485            def make_row(row: _InterimRowType[Row[Unpack[TupleAny]]]) -> _R: 
    486                return _make_row_orig(fixed_tf(row)) 
    487 
    488        else: 
    489            make_row = functools.partial(  # type: ignore 
    490                process_row, metadata, processors, key_to_index 
    491            ) 
    492 
    493        if real_result._row_logging_fn: 
    494            _log_row = real_result._row_logging_fn 
    495            _make_row = make_row 
    496 
    497            def make_row(row: _InterimRowType[Row[Unpack[TupleAny]]]) -> _R: 
    498                return _log_row(_make_row(row))  # type: ignore 
    499 
    500        return make_row 
    501 
    502    @HasMemoized_ro_memoized_attribute 
    503    def _iterator_getter(self) -> Callable[..., Iterator[_R]]: 
    504        make_row = self._row_getter 
    505 
    506        post_creational_filter = self._post_creational_filter 
    507 
    508        if self._unique_filter_state: 
    509            uniques, strategy = self._unique_strategy 
    510 
    511            def iterrows(self: Result[Unpack[TupleAny]]) -> Iterator[_R]: 
    512                for raw_row in self._fetchiter_impl(): 
    513                    obj: _InterimRowType[Any] = ( 
    514                        make_row(raw_row) if make_row else raw_row 
    515                    ) 
    516                    hashed = strategy(obj) if strategy else obj 
    517                    if hashed in uniques: 
    518                        continue 
    519                    uniques.add(hashed) 
    520                    if post_creational_filter: 
    521                        obj = post_creational_filter(obj) 
    522                    yield obj  # type: ignore 
    523 
    524        else: 
    525 
    526            def iterrows(self: Result[Unpack[TupleAny]]) -> Iterator[_R]: 
    527                for raw_row in self._fetchiter_impl(): 
    528                    row: _InterimRowType[Any] = ( 
    529                        make_row(raw_row) if make_row else raw_row 
    530                    ) 
    531                    if post_creational_filter: 
    532                        row = post_creational_filter(row) 
    533                    yield row  # type: ignore 
    534 
    535        return iterrows 
    536 
    537    def _raw_all_rows(self) -> List[_R]: 
    538        make_row = self._row_getter 
    539        assert make_row is not None 
    540        rows = self._fetchall_impl() 
    541        return [make_row(row) for row in rows] 
    542 
    543    def _allrows(self) -> List[_R]: 
    544        post_creational_filter = self._post_creational_filter 
    545 
    546        make_row = self._row_getter 
    547 
    548        rows = self._fetchall_impl() 
    549        made_rows: List[_InterimRowType[_R]] 
    550        if make_row: 
    551            made_rows = [make_row(row) for row in rows] 
    552        else: 
    553            made_rows = rows  # type: ignore 
    554 
    555        interim_rows: List[_R] 
    556 
    557        if self._unique_filter_state: 
    558            uniques, strategy = self._unique_strategy 
    559 
    560            interim_rows = [ 
    561                made_row  # type: ignore 
    562                for made_row, sig_row in [ 
    563                    ( 
    564                        made_row, 
    565                        strategy(made_row) if strategy else made_row, 
    566                    ) 
    567                    for made_row in made_rows 
    568                ] 
    569                if sig_row not in uniques and not uniques.add(sig_row)  # type: ignore # noqa: E501 
    570            ] 
    571        else: 
    572            interim_rows = made_rows  # type: ignore 
    573 
    574        if post_creational_filter: 
    575            interim_rows = [ 
    576                post_creational_filter(row) for row in interim_rows 
    577            ] 
    578        return interim_rows 
    579 
    580    @HasMemoized_ro_memoized_attribute 
    581    def _onerow_getter( 
    582        self, 
    583    ) -> Callable[..., Union[Literal[_NoRow._NO_ROW], _R]]: 
    584        make_row = self._row_getter 
    585 
    586        post_creational_filter = self._post_creational_filter 
    587 
    588        if self._unique_filter_state: 
    589            uniques, strategy = self._unique_strategy 
    590 
    591            def onerow(self: Result[Unpack[TupleAny]]) -> Union[_NoRow, _R]: 
    592                _onerow = self._fetchone_impl 
    593                while True: 
    594                    row = _onerow() 
    595                    if row is None: 
    596                        return _NO_ROW 
    597                    else: 
    598                        obj: _InterimRowType[Any] = ( 
    599                            make_row(row) if make_row else row 
    600                        ) 
    601                        hashed = strategy(obj) if strategy else obj 
    602                        if hashed in uniques: 
    603                            continue 
    604                        else: 
    605                            uniques.add(hashed) 
    606                        if post_creational_filter: 
    607                            obj = post_creational_filter(obj) 
    608                        return obj  # type: ignore 
    609 
    610        else: 
    611 
    612            def onerow(self: Result[Unpack[TupleAny]]) -> Union[_NoRow, _R]: 
    613                row = self._fetchone_impl() 
    614                if row is None: 
    615                    return _NO_ROW 
    616                else: 
    617                    interim_row: _InterimRowType[Any] = ( 
    618                        make_row(row) if make_row else row 
    619                    ) 
    620                    if post_creational_filter: 
    621                        interim_row = post_creational_filter(interim_row) 
    622                    return interim_row  # type: ignore 
    623 
    624        return onerow 
    625 
    626    @HasMemoized_ro_memoized_attribute 
    627    def _manyrow_getter(self) -> Callable[..., List[_R]]: 
    628        make_row = self._row_getter 
    629 
    630        post_creational_filter = self._post_creational_filter 
    631 
    632        if self._unique_filter_state: 
    633            uniques, strategy = self._unique_strategy 
    634 
    635            def filterrows( 
    636                make_row: Optional[Callable[..., _R]], 
    637                rows: List[Any], 
    638                strategy: Optional[Callable[[List[Any]], Any]], 
    639                uniques: Set[Any], 
    640            ) -> List[_R]: 
    641                if make_row: 
    642                    rows = [make_row(row) for row in rows] 
    643 
    644                if strategy: 
    645                    made_rows = ( 
    646                        (made_row, strategy(made_row)) for made_row in rows 
    647                    ) 
    648                else: 
    649                    made_rows = ((made_row, made_row) for made_row in rows) 
    650                return [ 
    651                    made_row 
    652                    for made_row, sig_row in made_rows 
    653                    if sig_row not in uniques and not uniques.add(sig_row)  # type: ignore  # noqa: E501 
    654                ] 
    655 
    656            def manyrows( 
    657                self: ResultInternal[_R], num: Optional[int] 
    658            ) -> List[_R]: 
    659                collect: List[_R] = [] 
    660 
    661                _manyrows = self._fetchmany_impl 
    662 
    663                if num is None: 
    664                    # if None is passed, we don't know the default 
    665                    # manyrows number, DBAPI has this as cursor.arraysize 
    666                    # different DBAPIs / fetch strategies may be different. 
    667                    # do a fetch to find what the number is.  if there are 
    668                    # only fewer rows left, then it doesn't matter. 
    669                    real_result = ( 
    670                        self._real_result 
    671                        if self._real_result 
    672                        else cast("Result[Unpack[TupleAny]]", self) 
    673                    ) 
    674                    if real_result._yield_per: 
    675                        num_required = num = real_result._yield_per 
    676                    else: 
    677                        rows = _manyrows(num) 
    678                        num = len(rows) 
    679                        assert make_row is not None 
    680                        collect.extend( 
    681                            filterrows(make_row, rows, strategy, uniques) 
    682                        ) 
    683                        num_required = num - len(collect) 
    684                else: 
    685                    num_required = num 
    686 
    687                assert num is not None 
    688 
    689                while num_required: 
    690                    rows = _manyrows(num_required) 
    691                    if not rows: 
    692                        break 
    693 
    694                    collect.extend( 
    695                        filterrows(make_row, rows, strategy, uniques) 
    696                    ) 
    697                    num_required = num - len(collect) 
    698 
    699                if post_creational_filter: 
    700                    collect = [post_creational_filter(row) for row in collect] 
    701                return collect 
    702 
    703        else: 
    704 
    705            def manyrows( 
    706                self: ResultInternal[_R], num: Optional[int] 
    707            ) -> List[_R]: 
    708                if num is None: 
    709                    real_result = ( 
    710                        self._real_result 
    711                        if self._real_result 
    712                        else cast("Result[Unpack[TupleAny]]", self) 
    713                    ) 
    714                    num = real_result._yield_per 
    715 
    716                rows: List[_InterimRowType[Any]] = self._fetchmany_impl(num) 
    717                if make_row: 
    718                    rows = [make_row(row) for row in rows] 
    719                if post_creational_filter: 
    720                    rows = [post_creational_filter(row) for row in rows] 
    721                return rows  # type: ignore 
    722 
    723        return manyrows 
    724 
    725    @overload 
    726    def _only_one_row( 
    727        self: ResultInternal[Row[_T, Unpack[TupleAny]]], 
    728        raise_for_second_row: bool, 
    729        raise_for_none: bool, 
    730        scalar: Literal[True], 
    731    ) -> _T: ... 
    732 
    733    @overload 
    734    def _only_one_row( 
    735        self, 
    736        raise_for_second_row: bool, 
    737        raise_for_none: Literal[True], 
    738        scalar: bool, 
    739    ) -> _R: ... 
    740 
    741    @overload 
    742    def _only_one_row( 
    743        self, 
    744        raise_for_second_row: bool, 
    745        raise_for_none: bool, 
    746        scalar: bool, 
    747    ) -> Optional[_R]: ... 
    748 
    749    def _only_one_row( 
    750        self, 
    751        raise_for_second_row: bool, 
    752        raise_for_none: bool, 
    753        scalar: bool, 
    754    ) -> Optional[_R]: 
    755        onerow = self._fetchone_impl 
    756 
    757        row: Optional[_InterimRowType[Any]] = onerow(hard_close=True) 
    758        if row is None: 
    759            if raise_for_none: 
    760                raise exc.NoResultFound( 
    761                    "No row was found when one was required" 
    762                ) 
    763            else: 
    764                return None 
    765 
    766        if scalar and self._source_supports_scalars: 
    767            self._generate_rows = False 
    768            make_row = None 
    769        else: 
    770            make_row = self._row_getter 
    771 
    772        try: 
    773            row = make_row(row) if make_row else row 
    774        except: 
    775            self._soft_close(hard=True) 
    776            raise 
    777 
    778        if raise_for_second_row: 
    779            if self._unique_filter_state: 
    780                # for no second row but uniqueness, need to essentially 
    781                # consume the entire result :( 
    782                uniques, strategy = self._unique_strategy 
    783 
    784                existing_row_hash = strategy(row) if strategy else row 
    785 
    786                while True: 
    787                    next_row: Any = onerow(hard_close=True) 
    788                    if next_row is None: 
    789                        next_row = _NO_ROW 
    790                        break 
    791 
    792                    try: 
    793                        next_row = make_row(next_row) if make_row else next_row 
    794 
    795                        if strategy: 
    796                            assert next_row is not _NO_ROW 
    797                            if existing_row_hash == strategy(next_row): 
    798                                continue 
    799                        elif row == next_row: 
    800                            continue 
    801                        # here, we have a row and it's different 
    802                        break 
    803                    except: 
    804                        self._soft_close(hard=True) 
    805                        raise 
    806            else: 
    807                next_row = onerow(hard_close=True) 
    808                if next_row is None: 
    809                    next_row = _NO_ROW 
    810 
    811            if next_row is not _NO_ROW: 
    812                self._soft_close(hard=True) 
    813                raise exc.MultipleResultsFound( 
    814                    "Multiple rows were found when exactly one was required" 
    815                    if raise_for_none 
    816                    else "Multiple rows were found when one or none " 
    817                    "was required" 
    818                ) 
    819        else: 
    820            # if we checked for second row then that would have 
    821            # closed us :) 
    822            self._soft_close(hard=True) 
    823 
    824        if not scalar: 
    825            post_creational_filter = self._post_creational_filter 
    826            if post_creational_filter: 
    827                row = post_creational_filter(row) 
    828 
    829        if scalar and make_row: 
    830            return row[0]  # type: ignore 
    831        else: 
    832            return row  # type: ignore 
    833 
    834    def _iter_impl(self) -> Iterator[_R]: 
    835        return self._iterator_getter(self) 
    836 
    837    def _next_impl(self) -> _R: 
    838        row = self._onerow_getter(self) 
    839        if row is _NO_ROW: 
    840            raise StopIteration() 
    841        else: 
    842            return row 
    843 
    844    @_generative 
    845    def _column_slices(self, indexes: Sequence[_KeyIndexType]) -> Self: 
    846        real_result = ( 
    847            self._real_result 
    848            if self._real_result 
    849            else cast("Result[Any]", self) 
    850        ) 
    851 
    852        if not real_result._source_supports_scalars or len(indexes) != 1: 
    853            self._metadata = self._metadata._reduce(indexes) 
    854 
    855        assert self._generate_rows 
    856 
    857        return self 
    858 
    859    @HasMemoized.memoized_attribute 
    860    def _unique_strategy(self) -> _UniqueFilterStateType: 
    861        assert self._unique_filter_state is not None 
    862        uniques, strategy = self._unique_filter_state 
    863 
    864        real_result = ( 
    865            self._real_result 
    866            if self._real_result is not None 
    867            else cast("Result[Unpack[TupleAny]]", self) 
    868        ) 
    869 
    870        if not strategy and self._metadata._unique_filters: 
    871            if ( 
    872                real_result._source_supports_scalars 
    873                and not self._generate_rows 
    874            ): 
    875                strategy = self._metadata._unique_filters[0] 
    876            else: 
    877                filters = self._metadata._unique_filters 
    878                if self._metadata._tuplefilter: 
    879                    filters = self._metadata._tuplefilter(filters) 
    880 
    881                strategy = operator.methodcaller("_filter_on_values", filters) 
    882        return uniques, strategy 
    883 
    884 
    885class _WithKeys: 
    886    __slots__ = () 
    887 
    888    _metadata: ResultMetaData 
    889 
    890    # used mainly to share documentation on the keys method. 
    891    def keys(self) -> RMKeyView: 
    892        """Return an iterable view which yields the string keys that would 
    893        be represented by each :class:`_engine.Row`. 
    894 
    895        The keys can represent the labels of the columns returned by a core 
    896        statement or the names of the orm classes returned by an orm 
    897        execution. 
    898 
    899        The view also can be tested for key containment using the Python 
    900        ``in`` operator, which will test both for the string keys represented 
    901        in the view, as well as for alternate keys such as column objects. 
    902 
    903        .. versionchanged:: 1.4 a key view object is returned rather than a 
    904           plain list. 
    905 
    906 
    907        """ 
    908        return self._metadata.keys 
    909 
    910 
    911class Result(_WithKeys, ResultInternal[Row[Unpack[_Ts]]]): 
    912    """Represent a set of database results. 
    913 
    914    .. versionadded:: 1.4  The :class:`_engine.Result` object provides a 
    915       completely updated usage model and calling facade for SQLAlchemy 
    916       Core and SQLAlchemy ORM.   In Core, it forms the basis of the 
    917       :class:`_engine.CursorResult` object which replaces the previous 
    918       :class:`_engine.ResultProxy` interface.   When using the ORM, a 
    919       higher level object called :class:`_engine.ChunkedIteratorResult` 
    920       is normally used. 
    921 
    922    .. note:: In SQLAlchemy 1.4 and above, this object is 
    923       used for ORM results returned by :meth:`_orm.Session.execute`, which can 
    924       yield instances of ORM mapped objects either individually or within 
    925       tuple-like rows. Note that the :class:`_engine.Result` object does not 
    926       deduplicate instances or rows automatically as is the case with the 
    927       legacy :class:`_orm.Query` object. For in-Python de-duplication of 
    928       instances or rows, use the :meth:`_engine.Result.unique` modifier 
    929       method. 
    930 
    931    .. seealso:: 
    932 
    933        :ref:`tutorial_fetching_rows` - in the :doc:`/tutorial/index` 
    934 
    935    """ 
    936 
    937    __slots__ = ("_metadata", "__dict__") 
    938 
    939    _row_logging_fn: Optional[ 
    940        Callable[[Row[Unpack[TupleAny]]], Row[Unpack[TupleAny]]] 
    941    ] = None 
    942 
    943    _source_supports_scalars: bool = False 
    944 
    945    _yield_per: Optional[int] = None 
    946 
    947    _attributes: util.immutabledict[Any, Any] = util.immutabledict() 
    948 
    949    def __init__(self, cursor_metadata: ResultMetaData): 
    950        self._metadata = cursor_metadata 
    951 
    952    def __enter__(self) -> Self: 
    953        return self 
    954 
    955    def __exit__(self, type_: Any, value: Any, traceback: Any) -> None: 
    956        self.close() 
    957 
    958    def close(self) -> None: 
    959        """close this :class:`_engine.Result`. 
    960 
    961        The behavior of this method is implementation specific, and is 
    962        not implemented by default.    The method should generally end 
    963        the resources in use by the result object and also cause any 
    964        subsequent iteration or row fetching to raise 
    965        :class:`.ResourceClosedError`. 
    966 
    967        .. versionadded:: 1.4.27 - ``.close()`` was previously not generally 
    968           available for all :class:`_engine.Result` classes, instead only 
    969           being available on the :class:`_engine.CursorResult` returned for 
    970           Core statement executions. As most other result objects, namely the 
    971           ones used by the ORM, are proxying a :class:`_engine.CursorResult` 
    972           in any case, this allows the underlying cursor result to be closed 
    973           from the outside facade for the case when the ORM query is using 
    974           the ``yield_per`` execution option where it does not immediately 
    975           exhaust and autoclose the database cursor. 
    976 
    977        """ 
    978        self._soft_close(hard=True) 
    979 
    980    @property 
    981    def _soft_closed(self) -> bool: 
    982        raise NotImplementedError() 
    983 
    984    @property 
    985    def closed(self) -> bool: 
    986        """return ``True`` if this :class:`_engine.Result` reports .closed 
    987 
    988        .. versionadded:: 1.4.43 
    989 
    990        """ 
    991        raise NotImplementedError() 
    992 
    993    @_generative 
    994    def yield_per(self, num: int) -> Self: 
    995        """Configure the row-fetching strategy to fetch ``num`` rows at a time. 
    996 
    997        This impacts the underlying behavior of the result when iterating over 
    998        the result object, or otherwise making use of  methods such as 
    999        :meth:`_engine.Result.fetchone` that return one row at a time.   Data 
    1000        from the underlying cursor or other data source will be buffered up to 
    1001        this many rows in memory, and the buffered collection will then be 
    1002        yielded out one row at a time or as many rows are requested. Each time 
    1003        the buffer clears, it will be refreshed to this many rows or as many 
    1004        rows remain if fewer remain. 
    1005 
    1006        The :meth:`_engine.Result.yield_per` method is generally used in 
    1007        conjunction with the 
    1008        :paramref:`_engine.Connection.execution_options.stream_results` 
    1009        execution option, which will allow the database dialect in use to make 
    1010        use of a server side cursor, if the DBAPI supports a specific "server 
    1011        side cursor" mode separate from its default mode of operation. 
    1012 
    1013        .. tip:: 
    1014 
    1015            Consider using the 
    1016            :paramref:`_engine.Connection.execution_options.yield_per` 
    1017            execution option, which will simultaneously set 
    1018            :paramref:`_engine.Connection.execution_options.stream_results` 
    1019            to ensure the use of server side cursors, as well as automatically 
    1020            invoke the :meth:`_engine.Result.yield_per` method to establish 
    1021            a fixed row buffer size at once. 
    1022 
    1023            The :paramref:`_engine.Connection.execution_options.yield_per` 
    1024            execution option is available for ORM operations, with 
    1025            :class:`_orm.Session`-oriented use described at 
    1026            :ref:`orm_queryguide_yield_per`. The Core-only version which works 
    1027            with :class:`_engine.Connection` is new as of SQLAlchemy 1.4.40. 
    1028 
    1029        .. versionadded:: 1.4 
    1030 
    1031        :param num: number of rows to fetch each time the buffer is refilled. 
    1032         If set to a value below 1, fetches all rows for the next buffer. 
    1033 
    1034        .. seealso:: 
    1035 
    1036            :ref:`engine_stream_results` - describes Core behavior for 
    1037            :meth:`_engine.Result.yield_per` 
    1038 
    1039            :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel` 
    1040 
    1041        """ 
    1042        self._yield_per = num 
    1043        return self 
    1044 
    1045    @_generative 
    1046    def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self: 
    1047        """Apply unique filtering to the objects returned by this 
    1048        :class:`_engine.Result`. 
    1049 
    1050        When this filter is applied with no arguments, the rows or objects 
    1051        returned will filtered such that each row is returned uniquely. The 
    1052        algorithm used to determine this uniqueness is by default the Python 
    1053        hashing identity of the whole tuple.   In some cases a specialized 
    1054        per-entity hashing scheme may be used, such as when using the ORM, a 
    1055        scheme is applied which  works against the primary key identity of 
    1056        returned objects. 
    1057 
    1058        The unique filter is applied **after all other filters**, which means 
    1059        if the columns returned have been refined using a method such as the 
    1060        :meth:`_engine.Result.columns` or :meth:`_engine.Result.scalars` 
    1061        method, the uniquing is applied to **only the column or columns 
    1062        returned**.   This occurs regardless of the order in which these 
    1063        methods have been called upon the :class:`_engine.Result` object. 
    1064 
    1065        The unique filter also changes the calculus used for methods like 
    1066        :meth:`_engine.Result.fetchmany` and :meth:`_engine.Result.partitions`. 
    1067        When using :meth:`_engine.Result.unique`, these methods will continue 
    1068        to yield the number of rows or objects requested, after uniquing 
    1069        has been applied.  However, this necessarily impacts the buffering 
    1070        behavior of the underlying cursor or datasource, such that multiple 
    1071        underlying calls to ``cursor.fetchmany()`` may be necessary in order 
    1072        to accumulate enough objects in order to provide a unique collection 
    1073        of the requested size. 
    1074 
    1075        :param strategy: a callable that will be applied to rows or objects 
    1076         being iterated, which should return an object that represents the 
    1077         unique value of the row.   A Python ``set()`` is used to store 
    1078         these identities.   If not passed, a default uniqueness strategy 
    1079         is used which may have been assembled by the source of this 
    1080         :class:`_engine.Result` object. 
    1081 
    1082        """ 
    1083        self._unique_filter_state = (set(), strategy) 
    1084        return self 
    1085 
    1086    def columns(self, *col_expressions: _KeyIndexType) -> Self: 
    1087        r"""Establish the columns that should be returned in each row. 
    1088 
    1089        This method may be used to limit the columns returned as well 
    1090        as to reorder them.   The given list of expressions are normally 
    1091        a series of integers or string key names.   They may also be 
    1092        appropriate :class:`.ColumnElement` objects which correspond to 
    1093        a given statement construct. 
    1094 
    1095        .. versionchanged:: 2.0  Due to a bug in 1.4, the 
    1096           :meth:`_engine.Result.columns` method had an incorrect behavior 
    1097           where calling upon the method with just one index would cause the 
    1098           :class:`_engine.Result` object to yield scalar values rather than 
    1099           :class:`_engine.Row` objects.   In version 2.0, this behavior 
    1100           has been corrected such that calling upon 
    1101           :meth:`_engine.Result.columns` with a single index will 
    1102           produce a :class:`_engine.Result` object that continues 
    1103           to yield :class:`_engine.Row` objects, which include 
    1104           only a single column. 
    1105 
    1106        E.g.:: 
    1107 
    1108            statement = select(table.c.x, table.c.y, table.c.z) 
    1109            result = connection.execute(statement) 
    1110 
    1111            for z, y in result.columns("z", "y"): 
    1112                ... 
    1113 
    1114        Example of using the column objects from the statement itself:: 
    1115 
    1116            for z, y in result.columns( 
    1117                statement.selected_columns.c.z, statement.selected_columns.c.y 
    1118            ): 
    1119                ... 
    1120 
    1121        .. versionadded:: 1.4 
    1122 
    1123        :param \*col_expressions: indicates columns to be returned.  Elements 
    1124         may be integer row indexes, string column names, or appropriate 
    1125         :class:`.ColumnElement` objects corresponding to a select construct. 
    1126 
    1127        :return: this :class:`_engine.Result` object with the modifications 
    1128         given. 
    1129 
    1130        """ 
    1131        return self._column_slices(col_expressions) 
    1132 
    1133    @overload 
    1134    def scalars(self: Result[_T, Unpack[TupleAny]]) -> ScalarResult[_T]: ... 
    1135 
    1136    @overload 
    1137    def scalars( 
    1138        self: Result[_T, Unpack[TupleAny]], index: Literal[0] 
    1139    ) -> ScalarResult[_T]: ... 
    1140 
    1141    @overload 
    1142    def scalars(self, index: _KeyIndexType = 0) -> ScalarResult[Any]: ... 
    1143 
    1144    def scalars(self, index: _KeyIndexType = 0) -> ScalarResult[Any]: 
    1145        """Return a :class:`_engine.ScalarResult` filtering object which 
    1146        will return single elements rather than :class:`_row.Row` objects. 
    1147 
    1148        E.g.:: 
    1149 
    1150            >>> result = conn.execute(text("select int_id from table")) 
    1151            >>> result.scalars().all() 
    1152            [1, 2, 3] 
    1153 
    1154        When results are fetched from the :class:`_engine.ScalarResult` 
    1155        filtering object, the single column-row that would be returned by the 
    1156        :class:`_engine.Result` is instead returned as the column's value. 
    1157 
    1158        .. versionadded:: 1.4 
    1159 
    1160        :param index: integer or row key indicating the column to be fetched 
    1161         from each row, defaults to ``0`` indicating the first column. 
    1162 
    1163        :return: a new :class:`_engine.ScalarResult` filtering object referring 
    1164         to this :class:`_engine.Result` object. 
    1165 
    1166        """ 
    1167        return ScalarResult(self, index) 
    1168 
    1169    def _getter( 
    1170        self, key: _KeyIndexType, raiseerr: bool = True 
    1171    ) -> Optional[Callable[[Row[Unpack[TupleAny]]], Any]]: 
    1172        """return a callable that will retrieve the given key from a 
    1173        :class:`_engine.Row`. 
    1174 
    1175        """ 
    1176        if self._source_supports_scalars: 
    1177            raise NotImplementedError( 
    1178                "can't use this function in 'only scalars' mode" 
    1179            ) 
    1180        return self._metadata._getter(key, raiseerr) 
    1181 
    1182    def _tuple_getter(self, keys: Sequence[_KeyIndexType]) -> _TupleGetterType: 
    1183        """return a callable that will retrieve the given keys from a 
    1184        :class:`_engine.Row`. 
    1185 
    1186        """ 
    1187        if self._source_supports_scalars: 
    1188            raise NotImplementedError( 
    1189                "can't use this function in 'only scalars' mode" 
    1190            ) 
    1191        return self._metadata._row_as_tuple_getter(keys) 
    1192 
    1193    def mappings(self) -> MappingResult: 
    1194        """Apply a mappings filter to returned rows, returning an instance of 
    1195        :class:`_engine.MappingResult`. 
    1196 
    1197        When this filter is applied, fetching rows will return 
    1198        :class:`_engine.RowMapping` objects instead of :class:`_engine.Row` 
    1199        objects. 
    1200 
    1201        .. versionadded:: 1.4 
    1202 
    1203        :return: a new :class:`_engine.MappingResult` filtering object 
    1204         referring to this :class:`_engine.Result` object. 
    1205 
    1206        """ 
    1207 
    1208        return MappingResult(self) 
    1209 
    1210    @property 
    1211    @deprecated( 
    1212        "2.1.0", 
    1213        "The :attr:`.Result.t` method is deprecated, :class:`.Row` " 
    1214        "now behaves like a tuple and can unpack types directly.", 
    1215    ) 
    1216    def t(self) -> TupleResult[Tuple[Unpack[_Ts]]]: 
    1217        """Apply a "typed tuple" typing filter to returned rows. 
    1218 
    1219        The :attr:`_engine.Result.t` attribute is a synonym for 
    1220        calling the :meth:`_engine.Result.tuples` method. 
    1221 
    1222        .. versionadded:: 2.0 
    1223 
    1224        .. seealso:: 
    1225 
    1226            :ref:`change_10635` - describes a migration path from this 
    1227            workaround for SQLAlchemy 2.1. 
    1228 
    1229        """ 
    1230        return self  # type: ignore 
    1231 
    1232    @deprecated( 
    1233        "2.1.0", 
    1234        "The :meth:`.Result.tuples` method is deprecated, :class:`.Row` " 
    1235        "now behaves like a tuple and can unpack types directly.", 
    1236    ) 
    1237    def tuples(self) -> TupleResult[Tuple[Unpack[_Ts]]]: 
    1238        """Apply a "typed tuple" typing filter to returned rows. 
    1239 
    1240        This method returns the same :class:`_engine.Result` object 
    1241        at runtime, 
    1242        however annotates as returning a :class:`_engine.TupleResult` object 
    1243        that will indicate to :pep:`484` typing tools that plain typed 
    1244        ``Tuple`` instances are returned rather than rows.  This allows 
    1245        tuple unpacking and ``__getitem__`` access of :class:`_engine.Row` 
    1246        objects to by typed, for those cases where the statement invoked 
    1247        itself included typing information. 
    1248 
    1249        .. versionadded:: 2.0 
    1250 
    1251        :return: the :class:`_engine.TupleResult` type at typing time. 
    1252 
    1253        .. seealso:: 
    1254 
    1255            :ref:`change_10635` - describes a migration path from this 
    1256            workaround for SQLAlchemy 2.1. 
    1257 
    1258            :attr:`_engine.Result.t` - shorter synonym 
    1259 
    1260            :attr:`_engine.Row._t` - :class:`_engine.Row` version 
    1261 
    1262        """ 
    1263 
    1264        return self  # type: ignore 
    1265 
    1266    def _raw_row_iterator(self) -> Iterator[_RowData]: 
    1267        """Return a safe iterator that yields raw row data. 
    1268 
    1269        This is used by the :meth:`_engine.Result.merge` method 
    1270        to merge multiple compatible results together. 
    1271 
    1272        """ 
    1273        raise NotImplementedError() 
    1274 
    1275    def __iter__(self) -> Iterator[Row[Unpack[_Ts]]]: 
    1276        return self._iter_impl() 
    1277 
    1278    def __next__(self) -> Row[Unpack[_Ts]]: 
    1279        return self._next_impl() 
    1280 
    1281    def partitions( 
    1282        self, size: Optional[int] = None 
    1283    ) -> Iterator[Sequence[Row[Unpack[_Ts]]]]: 
    1284        """Iterate through sub-lists of rows of the size given. 
    1285 
    1286        Each list will be of the size given, excluding the last list to 
    1287        be yielded, which may have a small number of rows.  No empty 
    1288        lists will be yielded. 
    1289 
    1290        The result object is automatically closed when the iterator 
    1291        is fully consumed. 
    1292 
    1293        Note that the backend driver will usually buffer the entire result 
    1294        ahead of time unless the 
    1295        :paramref:`.Connection.execution_options.stream_results` execution 
    1296        option is used indicating that the driver should not pre-buffer 
    1297        results, if possible.   Not all drivers support this option and 
    1298        the option is silently ignored for those who do not. 
    1299 
    1300        When using the ORM, the :meth:`_engine.Result.partitions` method 
    1301        is typically more effective from a memory perspective when it is 
    1302        combined with use of the 
    1303        :ref:`yield_per execution option <orm_queryguide_yield_per>`, 
    1304        which instructs both the DBAPI driver to use server side cursors, 
    1305        if available, as well as instructs the ORM loading internals to only 
    1306        build a certain amount of ORM objects from a result at a time before 
    1307        yielding them out. 
    1308 
    1309        .. versionadded:: 1.4 
    1310 
    1311        :param size: indicate the maximum number of rows to be present 
    1312         in each list yielded.  If None, makes use of the value set by 
    1313         the :meth:`_engine.Result.yield_per`, method, if it were called, 
    1314         or the :paramref:`_engine.Connection.execution_options.yield_per` 
    1315         execution option, which is equivalent in this regard.  If 
    1316         yield_per weren't set, it makes use of the 
    1317         :meth:`_engine.Result.fetchmany` default, which may be backend 
    1318         specific and not well defined. 
    1319 
    1320        :return: iterator of lists 
    1321 
    1322        .. seealso:: 
    1323 
    1324            :ref:`engine_stream_results` 
    1325 
    1326            :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel` 
    1327 
    1328        """ 
    1329 
    1330        getter = self._manyrow_getter 
    1331 
    1332        while True: 
    1333            partition = getter(self, size) 
    1334            if partition: 
    1335                yield partition 
    1336            else: 
    1337                break 
    1338 
    1339    def fetchall(self) -> Sequence[Row[Unpack[_Ts]]]: 
    1340        """A synonym for the :meth:`_engine.Result.all` method.""" 
    1341 
    1342        return self._allrows() 
    1343 
    1344    def fetchone(self) -> Optional[Row[Unpack[_Ts]]]: 
    1345        """Fetch one row. 
    1346 
    1347        When all rows are exhausted, returns None. 
    1348 
    1349        This method is provided for backwards compatibility with 
    1350        SQLAlchemy 1.x.x. 
    1351 
    1352        To fetch the first row of a result only, use the 
    1353        :meth:`_engine.Result.first` method.  To iterate through all 
    1354        rows, iterate the :class:`_engine.Result` object directly. 
    1355 
    1356        :return: a :class:`_engine.Row` object if no filters are applied, 
    1357         or ``None`` if no rows remain. 
    1358 
    1359        """ 
    1360        row = self._onerow_getter(self) 
    1361        if row is _NO_ROW: 
    1362            return None 
    1363        else: 
    1364            return row 
    1365 
    1366    def fetchmany( 
    1367        self, size: Optional[int] = None 
    1368    ) -> Sequence[Row[Unpack[_Ts]]]: 
    1369        """Fetch many rows. 
    1370 
    1371        When all rows are exhausted, returns an empty sequence. 
    1372 
    1373        This method is provided for backwards compatibility with 
    1374        SQLAlchemy 1.x.x. 
    1375 
    1376        To fetch rows in groups, use the :meth:`_engine.Result.partitions` 
    1377        method. 
    1378 
    1379        :return: a sequence of :class:`_engine.Row` objects. 
    1380 
    1381        .. seealso:: 
    1382 
    1383            :meth:`_engine.Result.partitions` 
    1384 
    1385        """ 
    1386 
    1387        return self._manyrow_getter(self, size) 
    1388 
    1389    def all(self) -> Sequence[Row[Unpack[_Ts]]]: 
    1390        """Return all rows in a sequence. 
    1391 
    1392        Closes the result set after invocation.   Subsequent invocations 
    1393        will return an empty sequence. 
    1394 
    1395        .. versionadded:: 1.4 
    1396 
    1397        :return: a sequence of :class:`_engine.Row` objects. 
    1398 
    1399        .. seealso:: 
    1400 
    1401            :ref:`engine_stream_results` - How to stream a large result set 
    1402            without loading it completely in python. 
    1403 
    1404        """ 
    1405 
    1406        return self._allrows() 
    1407 
    1408    def first(self) -> Optional[Row[Unpack[_Ts]]]: 
    1409        """Fetch the first row or ``None`` if no row is present. 
    1410 
    1411        Closes the result set and discards remaining rows. 
    1412 
    1413        .. note::  This method returns one **row**, e.g. tuple, by default. 
    1414           To return exactly one single scalar value, that is, the first 
    1415           column of the first row, use the 
    1416           :meth:`_engine.Result.scalar` method, 
    1417           or combine :meth:`_engine.Result.scalars` and 
    1418           :meth:`_engine.Result.first`. 
    1419 
    1420           Additionally, in contrast to the behavior of the legacy  ORM 
    1421           :meth:`_orm.Query.first` method, **no limit is applied** to the 
    1422           SQL query which was invoked to produce this 
    1423           :class:`_engine.Result`; 
    1424           for a DBAPI driver that buffers results in memory before yielding 
    1425           rows, all rows will be sent to the Python process and all but 
    1426           the first row will be discarded. 
    1427 
    1428           .. seealso:: 
    1429 
    1430                :ref:`migration_20_unify_select` 
    1431 
    1432        :return: a :class:`_engine.Row` object, or None 
    1433         if no rows remain. 
    1434 
    1435        .. seealso:: 
    1436 
    1437            :meth:`_engine.Result.scalar` 
    1438 
    1439            :meth:`_engine.Result.one` 
    1440 
    1441        """ 
    1442 
    1443        return self._only_one_row( 
    1444            raise_for_second_row=False, raise_for_none=False, scalar=False 
    1445        ) 
    1446 
    1447    def one_or_none(self) -> Optional[Row[Unpack[_Ts]]]: 
    1448        """Return at most one result or raise an exception. 
    1449 
    1450        Returns ``None`` if the result has no rows. 
    1451        Raises :class:`.MultipleResultsFound` 
    1452        if multiple rows are returned. 
    1453 
    1454        .. versionadded:: 1.4 
    1455 
    1456        :return: The first :class:`_engine.Row` or ``None`` if no row 
    1457         is available. 
    1458 
    1459        :raises: :class:`.MultipleResultsFound` 
    1460 
    1461        .. seealso:: 
    1462 
    1463            :meth:`_engine.Result.first` 
    1464 
    1465            :meth:`_engine.Result.one` 
    1466 
    1467        """ 
    1468        return self._only_one_row( 
    1469            raise_for_second_row=True, raise_for_none=False, scalar=False 
    1470        ) 
    1471 
    1472    def scalar_one(self: Result[_T, Unpack[TupleAny]]) -> _T: 
    1473        """Return exactly one scalar result or raise an exception. 
    1474 
    1475        This is equivalent to calling :meth:`_engine.Result.scalars` and 
    1476        then :meth:`_engine.ScalarResult.one`. 
    1477 
    1478        .. seealso:: 
    1479 
    1480            :meth:`_engine.ScalarResult.one` 
    1481 
    1482            :meth:`_engine.Result.scalars` 
    1483 
    1484        """ 
    1485        return self._only_one_row( 
    1486            raise_for_second_row=True, raise_for_none=True, scalar=True 
    1487        ) 
    1488 
    1489    def scalar_one_or_none(self: Result[_T, Unpack[TupleAny]]) -> Optional[_T]: 
    1490        """Return exactly one scalar result or ``None``. 
    1491 
    1492        This is equivalent to calling :meth:`_engine.Result.scalars` and 
    1493        then :meth:`_engine.ScalarResult.one_or_none`. 
    1494 
    1495        .. seealso:: 
    1496 
    1497            :meth:`_engine.ScalarResult.one_or_none` 
    1498 
    1499            :meth:`_engine.Result.scalars` 
    1500 
    1501        """ 
    1502        return self._only_one_row( 
    1503            raise_for_second_row=True, raise_for_none=False, scalar=True 
    1504        ) 
    1505 
    1506    def one(self) -> Row[Unpack[_Ts]]: 
    1507        """Return exactly one row or raise an exception. 
    1508 
    1509        Raises :class:`_exc.NoResultFound` if the result returns no 
    1510        rows, or :class:`_exc.MultipleResultsFound` if multiple rows 
    1511        would be returned. 
    1512 
    1513        .. note::  This method returns one **row**, e.g. tuple, by default. 
    1514           To return exactly one single scalar value, that is, the first 
    1515           column of the first row, use the 
    1516           :meth:`_engine.Result.scalar_one` method, or combine 
    1517           :meth:`_engine.Result.scalars` and 
    1518           :meth:`_engine.Result.one`. 
    1519 
    1520        .. versionadded:: 1.4 
    1521 
    1522        :return: The first :class:`_engine.Row`. 
    1523 
    1524        :raises: :class:`.MultipleResultsFound`, :class:`.NoResultFound` 
    1525 
    1526        .. seealso:: 
    1527 
    1528            :meth:`_engine.Result.first` 
    1529 
    1530            :meth:`_engine.Result.one_or_none` 
    1531 
    1532            :meth:`_engine.Result.scalar_one` 
    1533 
    1534        """ 
    1535        return self._only_one_row( 
    1536            raise_for_second_row=True, raise_for_none=True, scalar=False 
    1537        ) 
    1538 
    1539    def scalar(self: Result[_T, Unpack[TupleAny]]) -> Optional[_T]: 
    1540        """Fetch the first column of the first row, and close the result set. 
    1541 
    1542        Returns ``None`` if there are no rows to fetch. 
    1543 
    1544        No validation is performed to test if additional rows remain. 
    1545 
    1546        After calling this method, the object is fully closed, 
    1547        e.g. the :meth:`_engine.CursorResult.close` 
    1548        method will have been called. 
    1549 
    1550        :return: a Python scalar value, or ``None`` if no rows remain. 
    1551 
    1552        """ 
    1553        return self._only_one_row( 
    1554            raise_for_second_row=False, raise_for_none=False, scalar=True 
    1555        ) 
    1556 
    1557    def freeze(self) -> FrozenResult[Unpack[_Ts]]: 
    1558        """Return a callable object that will produce copies of this 
    1559        :class:`_engine.Result` when invoked. 
    1560 
    1561        The callable object returned is an instance of 
    1562        :class:`_engine.FrozenResult`. 
    1563 
    1564        This is used for result set caching.  The method must be called 
    1565        on the result when it has been unconsumed, and calling the method 
    1566        will consume the result fully.   When the :class:`_engine.FrozenResult` 
    1567        is retrieved from a cache, it can be called any number of times where 
    1568        it will produce a new :class:`_engine.Result` object each time 
    1569        against its stored set of rows. 
    1570 
    1571        .. seealso:: 
    1572 
    1573            :ref:`do_orm_execute_re_executing` - example usage within the 
    1574            ORM to implement a result-set cache. 
    1575 
    1576        """ 
    1577 
    1578        return FrozenResult(self) 
    1579 
    1580    def merge( 
    1581        self, *others: Result[Unpack[TupleAny]] 
    1582    ) -> MergedResult[Unpack[TupleAny]]: 
    1583        """Merge this :class:`_engine.Result` with other compatible result 
    1584        objects. 
    1585 
    1586        The object returned is an instance of :class:`_engine.MergedResult`, 
    1587        which will be composed of iterators from the given result 
    1588        objects. 
    1589 
    1590        The new result will use the metadata from this result object. 
    1591        The subsequent result objects must be against an identical 
    1592        set of result / cursor metadata, otherwise the behavior is 
    1593        undefined. 
    1594 
    1595        """ 
    1596        return MergedResult(self._metadata, (self,) + others) 
    1597 
    1598 
    1599class FilterResult(ResultInternal[_R]): 
    1600    """A wrapper for a :class:`_engine.Result` that returns objects other than 
    1601    :class:`_engine.Row` objects, such as dictionaries or scalar objects. 
    1602 
    1603    :class:`_engine.FilterResult` is the common base for additional result 
    1604    APIs including :class:`_engine.MappingResult`, 
    1605    :class:`_engine.ScalarResult` and :class:`_engine.AsyncResult`. 
    1606 
    1607    """ 
    1608 
    1609    __slots__ = ( 
    1610        "_real_result", 
    1611        "_post_creational_filter", 
    1612        "_metadata", 
    1613        "_unique_filter_state", 
    1614        "__dict__", 
    1615    ) 
    1616 
    1617    _post_creational_filter: Optional[Callable[[Any], Any]] 
    1618 
    1619    _real_result: Result[Unpack[TupleAny]] 
    1620 
    1621    def __enter__(self) -> Self: 
    1622        return self 
    1623 
    1624    def __exit__(self, type_: Any, value: Any, traceback: Any) -> None: 
    1625        self._real_result.__exit__(type_, value, traceback) 
    1626 
    1627    @_generative 
    1628    def yield_per(self, num: int) -> Self: 
    1629        """Configure the row-fetching strategy to fetch ``num`` rows at a time. 
    1630 
    1631        The :meth:`_engine.FilterResult.yield_per` method is a pass through 
    1632        to the :meth:`_engine.Result.yield_per` method.  See that method's 
    1633        documentation for usage notes. 
    1634 
    1635        .. versionadded:: 1.4.40 - added :meth:`_engine.FilterResult.yield_per` 
    1636           so that the method is available on all result set implementations 
    1637 
    1638        .. seealso:: 
    1639 
    1640            :ref:`engine_stream_results` - describes Core behavior for 
    1641            :meth:`_engine.Result.yield_per` 
    1642 
    1643            :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel` 
    1644 
    1645        """ 
    1646        self._real_result = self._real_result.yield_per(num) 
    1647        return self 
    1648 
    1649    def _soft_close(self, hard: bool = False) -> None: 
    1650        self._real_result._soft_close(hard=hard) 
    1651 
    1652    @property 
    1653    def _soft_closed(self) -> bool: 
    1654        return self._real_result._soft_closed 
    1655 
    1656    @property 
    1657    def closed(self) -> bool: 
    1658        """Return ``True`` if the underlying :class:`_engine.Result` reports 
    1659        closed 
    1660 
    1661        .. versionadded:: 1.4.43 
    1662 
    1663        """ 
    1664        return self._real_result.closed 
    1665 
    1666    def close(self) -> None: 
    1667        """Close this :class:`_engine.FilterResult`. 
    1668 
    1669        .. versionadded:: 1.4.43 
    1670 
    1671        """ 
    1672        self._real_result.close() 
    1673 
    1674    @property 
    1675    def _attributes(self) -> Dict[Any, Any]: 
    1676        return self._real_result._attributes 
    1677 
    1678    def _fetchiter_impl( 
    1679        self, 
    1680    ) -> Iterator[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    1681        return self._real_result._fetchiter_impl() 
    1682 
    1683    def _fetchone_impl( 
    1684        self, hard_close: bool = False 
    1685    ) -> Optional[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    1686        return self._real_result._fetchone_impl(hard_close=hard_close) 
    1687 
    1688    def _fetchall_impl( 
    1689        self, 
    1690    ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    1691        return self._real_result._fetchall_impl() 
    1692 
    1693    def _fetchmany_impl( 
    1694        self, size: Optional[int] = None 
    1695    ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    1696        return self._real_result._fetchmany_impl(size=size) 
    1697 
    1698 
    1699class ScalarResult(FilterResult[_R]): 
    1700    """A wrapper for a :class:`_engine.Result` that returns scalar values 
    1701    rather than :class:`_row.Row` values. 
    1702 
    1703    The :class:`_engine.ScalarResult` object is acquired by calling the 
    1704    :meth:`_engine.Result.scalars` method. 
    1705 
    1706    A special limitation of :class:`_engine.ScalarResult` is that it has 
    1707    no ``fetchone()`` method; since the semantics of ``fetchone()`` are that 
    1708    the ``None`` value indicates no more results, this is not compatible 
    1709    with :class:`_engine.ScalarResult` since there is no way to distinguish 
    1710    between ``None`` as a row value versus ``None`` as an indicator.  Use 
    1711    ``next(result)`` to receive values individually. 
    1712 
    1713    """ 
    1714 
    1715    __slots__ = () 
    1716 
    1717    _generate_rows = False 
    1718 
    1719    _post_creational_filter: Optional[Callable[[Any], Any]] 
    1720 
    1721    def __init__( 
    1722        self, real_result: Result[Unpack[TupleAny]], index: _KeyIndexType 
    1723    ): 
    1724        self._real_result = real_result 
    1725 
    1726        if real_result._source_supports_scalars: 
    1727            self._metadata = real_result._metadata 
    1728            self._post_creational_filter = None 
    1729        else: 
    1730            self._metadata = real_result._metadata._reduce([index]) 
    1731            self._post_creational_filter = operator.itemgetter(0) 
    1732 
    1733        self._unique_filter_state = real_result._unique_filter_state 
    1734 
    1735    def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self: 
    1736        """Apply unique filtering to the objects returned by this 
    1737        :class:`_engine.ScalarResult`. 
    1738 
    1739        See :meth:`_engine.Result.unique` for usage details. 
    1740 
    1741        """ 
    1742        self._unique_filter_state = (set(), strategy) 
    1743        return self 
    1744 
    1745    def partitions(self, size: Optional[int] = None) -> Iterator[Sequence[_R]]: 
    1746        """Iterate through sub-lists of elements of the size given. 
    1747 
    1748        Equivalent to :meth:`_engine.Result.partitions` except that 
    1749        scalar values, rather than :class:`_engine.Row` objects, 
    1750        are returned. 
    1751 
    1752        """ 
    1753 
    1754        getter = self._manyrow_getter 
    1755 
    1756        while True: 
    1757            partition = getter(self, size) 
    1758            if partition: 
    1759                yield partition 
    1760            else: 
    1761                break 
    1762 
    1763    def fetchall(self) -> Sequence[_R]: 
    1764        """A synonym for the :meth:`_engine.ScalarResult.all` method.""" 
    1765 
    1766        return self._allrows() 
    1767 
    1768    def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]: 
    1769        """Fetch many objects. 
    1770 
    1771        Equivalent to :meth:`_engine.Result.fetchmany` except that 
    1772        scalar values, rather than :class:`_engine.Row` objects, 
    1773        are returned. 
    1774 
    1775        """ 
    1776        return self._manyrow_getter(self, size) 
    1777 
    1778    def all(self) -> Sequence[_R]: 
    1779        """Return all scalar values in a sequence. 
    1780 
    1781        Equivalent to :meth:`_engine.Result.all` except that 
    1782        scalar values, rather than :class:`_engine.Row` objects, 
    1783        are returned. 
    1784 
    1785        """ 
    1786        return self._allrows() 
    1787 
    1788    def __iter__(self) -> Iterator[_R]: 
    1789        return self._iter_impl() 
    1790 
    1791    def __next__(self) -> _R: 
    1792        return self._next_impl() 
    1793 
    1794    def first(self) -> Optional[_R]: 
    1795        """Fetch the first object or ``None`` if no object is present. 
    1796 
    1797        Equivalent to :meth:`_engine.Result.first` except that 
    1798        scalar values, rather than :class:`_engine.Row` objects, 
    1799        are returned. 
    1800 
    1801 
    1802        """ 
    1803        return self._only_one_row( 
    1804            raise_for_second_row=False, raise_for_none=False, scalar=False 
    1805        ) 
    1806 
    1807    def one_or_none(self) -> Optional[_R]: 
    1808        """Return at most one object or raise an exception. 
    1809 
    1810        Equivalent to :meth:`_engine.Result.one_or_none` except that 
    1811        scalar values, rather than :class:`_engine.Row` objects, 
    1812        are returned. 
    1813 
    1814        """ 
    1815        return self._only_one_row( 
    1816            raise_for_second_row=True, raise_for_none=False, scalar=False 
    1817        ) 
    1818 
    1819    def one(self) -> _R: 
    1820        """Return exactly one object or raise an exception. 
    1821 
    1822        Equivalent to :meth:`_engine.Result.one` except that 
    1823        scalar values, rather than :class:`_engine.Row` objects, 
    1824        are returned. 
    1825 
    1826        """ 
    1827        return self._only_one_row( 
    1828            raise_for_second_row=True, raise_for_none=True, scalar=False 
    1829        ) 
    1830 
    1831 
    1832class TupleResult(FilterResult[_R], util.TypingOnly): 
    1833    """A :class:`_engine.Result` that's typed as returning plain 
    1834    Python tuples instead of rows. 
    1835 
    1836    Since :class:`_engine.Row` acts like a tuple in every way already, 
    1837    this class is a typing only class, regular :class:`_engine.Result` is 
    1838    still used at runtime. 
    1839 
    1840    """ 
    1841 
    1842    __slots__ = () 
    1843 
    1844    if TYPE_CHECKING: 
    1845 
    1846        def partitions( 
    1847            self, size: Optional[int] = None 
    1848        ) -> Iterator[Sequence[_R]]: 
    1849            """Iterate through sub-lists of elements of the size given. 
    1850 
    1851            Equivalent to :meth:`_engine.Result.partitions` except that 
    1852            tuple values, rather than :class:`_engine.Row` objects, 
    1853            are returned. 
    1854 
    1855            """ 
    1856            ... 
    1857 
    1858        def fetchone(self) -> Optional[_R]: 
    1859            """Fetch one tuple. 
    1860 
    1861            Equivalent to :meth:`_engine.Result.fetchone` except that 
    1862            tuple values, rather than :class:`_engine.Row` 
    1863            objects, are returned. 
    1864 
    1865            """ 
    1866            ... 
    1867 
    1868        def fetchall(self) -> Sequence[_R]: 
    1869            """A synonym for the :meth:`_engine.ScalarResult.all` method.""" 
    1870            ... 
    1871 
    1872        def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]: 
    1873            """Fetch many objects. 
    1874 
    1875            Equivalent to :meth:`_engine.Result.fetchmany` except that 
    1876            tuple values, rather than :class:`_engine.Row` objects, 
    1877            are returned. 
    1878 
    1879            """ 
    1880            ... 
    1881 
    1882        def all(self) -> Sequence[_R]:  # noqa: A001 
    1883            """Return all scalar values in a sequence. 
    1884 
    1885            Equivalent to :meth:`_engine.Result.all` except that 
    1886            tuple values, rather than :class:`_engine.Row` objects, 
    1887            are returned. 
    1888 
    1889            """ 
    1890            ... 
    1891 
    1892        def __iter__(self) -> Iterator[_R]: ... 
    1893 
    1894        def __next__(self) -> _R: ... 
    1895 
    1896        def first(self) -> Optional[_R]: 
    1897            """Fetch the first object or ``None`` if no object is present. 
    1898 
    1899            Equivalent to :meth:`_engine.Result.first` except that 
    1900            tuple values, rather than :class:`_engine.Row` objects, 
    1901            are returned. 
    1902 
    1903 
    1904            """ 
    1905            ... 
    1906 
    1907        def one_or_none(self) -> Optional[_R]: 
    1908            """Return at most one object or raise an exception. 
    1909 
    1910            Equivalent to :meth:`_engine.Result.one_or_none` except that 
    1911            tuple values, rather than :class:`_engine.Row` objects, 
    1912            are returned. 
    1913 
    1914            """ 
    1915            ... 
    1916 
    1917        def one(self) -> _R: 
    1918            """Return exactly one object or raise an exception. 
    1919 
    1920            Equivalent to :meth:`_engine.Result.one` except that 
    1921            tuple values, rather than :class:`_engine.Row` objects, 
    1922            are returned. 
    1923 
    1924            """ 
    1925            ... 
    1926 
    1927        @overload 
    1928        def scalar_one(self: TupleResult[Tuple[_T]]) -> _T: ... 
    1929 
    1930        @overload 
    1931        def scalar_one(self) -> Any: ... 
    1932 
    1933        def scalar_one(self) -> Any: 
    1934            """Return exactly one scalar result or raise an exception. 
    1935 
    1936            This is equivalent to calling :meth:`_engine.Result.scalars` 
    1937            and then :meth:`_engine.ScalarResult.one`. 
    1938 
    1939            .. seealso:: 
    1940 
    1941                :meth:`_engine.ScalarResult.one` 
    1942 
    1943                :meth:`_engine.Result.scalars` 
    1944 
    1945            """ 
    1946            ... 
    1947 
    1948        @overload 
    1949        def scalar_one_or_none( 
    1950            self: TupleResult[Tuple[_T]], 
    1951        ) -> Optional[_T]: ... 
    1952 
    1953        @overload 
    1954        def scalar_one_or_none(self) -> Optional[Any]: ... 
    1955 
    1956        def scalar_one_or_none(self) -> Optional[Any]: 
    1957            """Return exactly one or no scalar result. 
    1958 
    1959            This is equivalent to calling :meth:`_engine.Result.scalars` 
    1960            and then :meth:`_engine.ScalarResult.one_or_none`. 
    1961 
    1962            .. seealso:: 
    1963 
    1964                :meth:`_engine.ScalarResult.one_or_none` 
    1965 
    1966                :meth:`_engine.Result.scalars` 
    1967 
    1968            """ 
    1969            ... 
    1970 
    1971        @overload 
    1972        def scalar(self: TupleResult[Tuple[_T]]) -> Optional[_T]: ... 
    1973 
    1974        @overload 
    1975        def scalar(self) -> Any: ... 
    1976 
    1977        def scalar(self) -> Any: 
    1978            """Fetch the first column of the first row, and close the result 
    1979            set. 
    1980 
    1981            Returns ``None`` if there are no rows to fetch. 
    1982 
    1983            No validation is performed to test if additional rows remain. 
    1984 
    1985            After calling this method, the object is fully closed, 
    1986            e.g. the :meth:`_engine.CursorResult.close` 
    1987            method will have been called. 
    1988 
    1989            :return: a Python scalar value , or ``None`` if no rows remain. 
    1990 
    1991            """ 
    1992            ... 
    1993 
    1994 
    1995class MappingResult(_WithKeys, FilterResult[RowMapping]): 
    1996    """A wrapper for a :class:`_engine.Result` that returns dictionary values 
    1997    rather than :class:`_engine.Row` values. 
    1998 
    1999    The :class:`_engine.MappingResult` object is acquired by calling the 
    2000    :meth:`_engine.Result.mappings` method. 
    2001 
    2002    """ 
    2003 
    2004    __slots__ = () 
    2005 
    2006    _generate_rows = True 
    2007 
    2008    _post_creational_filter = operator.attrgetter("_mapping") 
    2009 
    2010    def __init__(self, result: Result[Unpack[TupleAny]]): 
    2011        self._real_result = result 
    2012        self._unique_filter_state = result._unique_filter_state 
    2013        self._metadata = result._metadata 
    2014        if result._source_supports_scalars: 
    2015            self._metadata = self._metadata._reduce([0]) 
    2016 
    2017    def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self: 
    2018        """Apply unique filtering to the objects returned by this 
    2019        :class:`_engine.MappingResult`. 
    2020 
    2021        See :meth:`_engine.Result.unique` for usage details. 
    2022 
    2023        """ 
    2024        self._unique_filter_state = (set(), strategy) 
    2025        return self 
    2026 
    2027    def columns(self, *col_expressions: _KeyIndexType) -> Self: 
    2028        """Establish the columns that should be returned in each row.""" 
    2029        return self._column_slices(col_expressions) 
    2030 
    2031    def partitions( 
    2032        self, size: Optional[int] = None 
    2033    ) -> Iterator[Sequence[RowMapping]]: 
    2034        """Iterate through sub-lists of elements of the size given. 
    2035 
    2036        Equivalent to :meth:`_engine.Result.partitions` except that 
    2037        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row` 
    2038        objects, are returned. 
    2039 
    2040        """ 
    2041 
    2042        getter = self._manyrow_getter 
    2043 
    2044        while True: 
    2045            partition = getter(self, size) 
    2046            if partition: 
    2047                yield partition 
    2048            else: 
    2049                break 
    2050 
    2051    def fetchall(self) -> Sequence[RowMapping]: 
    2052        """A synonym for the :meth:`_engine.MappingResult.all` method.""" 
    2053 
    2054        return self._allrows() 
    2055 
    2056    def fetchone(self) -> Optional[RowMapping]: 
    2057        """Fetch one object. 
    2058 
    2059        Equivalent to :meth:`_engine.Result.fetchone` except that 
    2060        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row` 
    2061        objects, are returned. 
    2062 
    2063        """ 
    2064 
    2065        row = self._onerow_getter(self) 
    2066        if row is _NO_ROW: 
    2067            return None 
    2068        else: 
    2069            return row 
    2070 
    2071    def fetchmany(self, size: Optional[int] = None) -> Sequence[RowMapping]: 
    2072        """Fetch many objects. 
    2073 
    2074        Equivalent to :meth:`_engine.Result.fetchmany` except that 
    2075        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row` 
    2076        objects, are returned. 
    2077 
    2078        """ 
    2079 
    2080        return self._manyrow_getter(self, size) 
    2081 
    2082    def all(self) -> Sequence[RowMapping]: 
    2083        """Return all scalar values in a sequence. 
    2084 
    2085        Equivalent to :meth:`_engine.Result.all` except that 
    2086        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row` 
    2087        objects, are returned. 
    2088 
    2089        """ 
    2090 
    2091        return self._allrows() 
    2092 
    2093    def __iter__(self) -> Iterator[RowMapping]: 
    2094        return self._iter_impl() 
    2095 
    2096    def __next__(self) -> RowMapping: 
    2097        return self._next_impl() 
    2098 
    2099    def first(self) -> Optional[RowMapping]: 
    2100        """Fetch the first object or ``None`` if no object is present. 
    2101 
    2102        Equivalent to :meth:`_engine.Result.first` except that 
    2103        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row` 
    2104        objects, are returned. 
    2105 
    2106 
    2107        """ 
    2108        return self._only_one_row( 
    2109            raise_for_second_row=False, raise_for_none=False, scalar=False 
    2110        ) 
    2111 
    2112    def one_or_none(self) -> Optional[RowMapping]: 
    2113        """Return at most one object or raise an exception. 
    2114 
    2115        Equivalent to :meth:`_engine.Result.one_or_none` except that 
    2116        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row` 
    2117        objects, are returned. 
    2118 
    2119        """ 
    2120        return self._only_one_row( 
    2121            raise_for_second_row=True, raise_for_none=False, scalar=False 
    2122        ) 
    2123 
    2124    def one(self) -> RowMapping: 
    2125        """Return exactly one object or raise an exception. 
    2126 
    2127        Equivalent to :meth:`_engine.Result.one` except that 
    2128        :class:`_engine.RowMapping` values, rather than :class:`_engine.Row` 
    2129        objects, are returned. 
    2130 
    2131        """ 
    2132        return self._only_one_row( 
    2133            raise_for_second_row=True, raise_for_none=True, scalar=False 
    2134        ) 
    2135 
    2136 
    2137class FrozenResult(Generic[Unpack[_Ts]]): 
    2138    """Represents a :class:`_engine.Result` object in a "frozen" state suitable 
    2139    for caching. 
    2140 
    2141    The :class:`_engine.FrozenResult` object is returned from the 
    2142    :meth:`_engine.Result.freeze` method of any :class:`_engine.Result` 
    2143    object. 
    2144 
    2145    A new iterable :class:`_engine.Result` object is generated from a fixed 
    2146    set of data each time the :class:`_engine.FrozenResult` is invoked as 
    2147    a callable:: 
    2148 
    2149 
    2150        result = connection.execute(query) 
    2151 
    2152        frozen = result.freeze() 
    2153 
    2154        unfrozen_result_one = frozen() 
    2155 
    2156        for row in unfrozen_result_one: 
    2157            print(row) 
    2158 
    2159        unfrozen_result_two = frozen() 
    2160        rows = unfrozen_result_two.all() 
    2161 
    2162        # ... etc 
    2163 
    2164    .. versionadded:: 1.4 
    2165 
    2166    .. seealso:: 
    2167 
    2168        :ref:`do_orm_execute_re_executing` - example usage within the 
    2169        ORM to implement a result-set cache. 
    2170 
    2171        :func:`_orm.loading.merge_frozen_result` - ORM function to merge 
    2172        a frozen result back into a :class:`_orm.Session`. 
    2173 
    2174    """ 
    2175 
    2176    data: Sequence[Any] 
    2177 
    2178    def __init__(self, result: Result[Unpack[_Ts]]): 
    2179        self.metadata = result._metadata._for_freeze() 
    2180        self._source_supports_scalars = result._source_supports_scalars 
    2181        self._attributes = result._attributes 
    2182 
    2183        if self._source_supports_scalars: 
    2184            self.data = list(result._raw_row_iterator()) 
    2185        else: 
    2186            self.data = result.fetchall() 
    2187 
    2188    def _rewrite_rows(self) -> Sequence[Sequence[Any]]: 
    2189        # used only by the orm fn merge_frozen_result 
    2190        if self._source_supports_scalars: 
    2191            return [[elem] for elem in self.data] 
    2192        else: 
    2193            return [list(row) for row in self.data] 
    2194 
    2195    def with_new_rows( 
    2196        self, tuple_data: Sequence[Row[Unpack[_Ts]]] 
    2197    ) -> FrozenResult[Unpack[_Ts]]: 
    2198        fr = FrozenResult.__new__(FrozenResult) 
    2199        fr.metadata = self.metadata 
    2200        fr._attributes = self._attributes 
    2201        fr._source_supports_scalars = self._source_supports_scalars 
    2202 
    2203        if self._source_supports_scalars: 
    2204            fr.data = [d[0] for d in tuple_data]  # type: ignore[misc] 
    2205        else: 
    2206            fr.data = tuple_data 
    2207        return fr 
    2208 
    2209    def __call__(self) -> Result[Unpack[_Ts]]: 
    2210        result: IteratorResult[Unpack[_Ts]] = IteratorResult( 
    2211            self.metadata, iter(self.data) 
    2212        ) 
    2213        result._attributes = self._attributes 
    2214        result._source_supports_scalars = self._source_supports_scalars 
    2215        return result 
    2216 
    2217 
    2218class IteratorResult(Result[Unpack[_Ts]]): 
    2219    """A :class:`_engine.Result` that gets data from a Python iterator of 
    2220    :class:`_engine.Row` objects or similar row-like data. 
    2221 
    2222    .. versionadded:: 1.4 
    2223 
    2224    """ 
    2225 
    2226    _hard_closed = False 
    2227    _soft_closed = False 
    2228 
    2229    def __init__( 
    2230        self, 
    2231        cursor_metadata: ResultMetaData, 
    2232        iterator: Iterator[_InterimSupportsScalarsRowType], 
    2233        raw: Optional[Result[Any]] = None, 
    2234        _source_supports_scalars: bool = False, 
    2235    ): 
    2236        self._metadata = cursor_metadata 
    2237        self.iterator = iterator 
    2238        self.raw = raw 
    2239        self._source_supports_scalars = _source_supports_scalars 
    2240 
    2241    @property 
    2242    def closed(self) -> bool: 
    2243        """Return ``True`` if this :class:`_engine.IteratorResult` has 
    2244        been closed 
    2245 
    2246        .. versionadded:: 1.4.43 
    2247 
    2248        """ 
    2249        return self._hard_closed 
    2250 
    2251    def _soft_close(self, hard: bool = False, **kw: Any) -> None: 
    2252        if hard: 
    2253            self._hard_closed = True 
    2254        if self.raw is not None: 
    2255            self.raw._soft_close(hard=hard, **kw) 
    2256        self.iterator = iter([]) 
    2257        self._reset_memoizations() 
    2258        self._soft_closed = True 
    2259 
    2260    def _raise_hard_closed(self) -> NoReturn: 
    2261        raise exc.ResourceClosedError("This result object is closed.") 
    2262 
    2263    def _raw_row_iterator(self) -> Iterator[_RowData]: 
    2264        return self.iterator 
    2265 
    2266    def _fetchiter_impl(self) -> Iterator[_InterimSupportsScalarsRowType]: 
    2267        if self._hard_closed: 
    2268            self._raise_hard_closed() 
    2269        return self.iterator 
    2270 
    2271    def _fetchone_impl( 
    2272        self, hard_close: bool = False 
    2273    ) -> Optional[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    2274        if self._hard_closed: 
    2275            self._raise_hard_closed() 
    2276 
    2277        row = next(self.iterator, _NO_ROW) 
    2278        if row is _NO_ROW: 
    2279            self._soft_close(hard=hard_close) 
    2280            return None 
    2281        else: 
    2282            return row 
    2283 
    2284    def _fetchall_impl( 
    2285        self, 
    2286    ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    2287        if self._hard_closed: 
    2288            self._raise_hard_closed() 
    2289        try: 
    2290            return list(self.iterator) 
    2291        finally: 
    2292            self._soft_close() 
    2293 
    2294    def _fetchmany_impl( 
    2295        self, size: Optional[int] = None 
    2296    ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    2297        if self._hard_closed: 
    2298            self._raise_hard_closed() 
    2299 
    2300        return list(itertools.islice(self.iterator, 0, size)) 
    2301 
    2302 
    2303def null_result() -> IteratorResult[Any]: 
    2304    return IteratorResult(SimpleResultMetaData([]), iter([])) 
    2305 
    2306 
    2307class ChunkedIteratorResult(IteratorResult[Unpack[_Ts]]): 
    2308    """An :class:`_engine.IteratorResult` that works from an 
    2309    iterator-producing callable. 
    2310 
    2311    The given ``chunks`` argument is a function that is given a number of rows 
    2312    to return in each chunk, or ``None`` for all rows.  The function should 
    2313    then return an un-consumed iterator of lists, each list of the requested 
    2314    size. 
    2315 
    2316    The function can be called at any time again, in which case it should 
    2317    continue from the same result set but adjust the chunk size as given. 
    2318 
    2319    .. versionadded:: 1.4 
    2320 
    2321    """ 
    2322 
    2323    def __init__( 
    2324        self, 
    2325        cursor_metadata: ResultMetaData, 
    2326        chunks: Callable[ 
    2327            [Optional[int]], Iterator[Sequence[_InterimRowType[_R]]] 
    2328        ], 
    2329        source_supports_scalars: bool = False, 
    2330        raw: Optional[Result[Any]] = None, 
    2331        dynamic_yield_per: bool = False, 
    2332    ): 
    2333        self._metadata = cursor_metadata 
    2334        self.chunks = chunks 
    2335        self._source_supports_scalars = source_supports_scalars 
    2336        self.raw = raw 
    2337        self.iterator = itertools.chain.from_iterable(self.chunks(None)) 
    2338        self.dynamic_yield_per = dynamic_yield_per 
    2339 
    2340    @_generative 
    2341    def yield_per(self, num: int) -> Self: 
    2342        # TODO: this throws away the iterator which may be holding 
    2343        # onto a chunk.   the yield_per cannot be changed once any 
    2344        # rows have been fetched.   either find a way to enforce this, 
    2345        # or we can't use itertools.chain and will instead have to 
    2346        # keep track. 
    2347 
    2348        self._yield_per = num 
    2349        self.iterator = itertools.chain.from_iterable(self.chunks(num)) 
    2350        return self 
    2351 
    2352    def _soft_close(self, hard: bool = False, **kw: Any) -> None: 
    2353        super()._soft_close(hard=hard, **kw) 
    2354        self.chunks = lambda size: []  # type: ignore 
    2355 
    2356    def _fetchmany_impl( 
    2357        self, size: Optional[int] = None 
    2358    ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]: 
    2359        if self.dynamic_yield_per: 
    2360            self.iterator = itertools.chain.from_iterable(self.chunks(size)) 
    2361        return super()._fetchmany_impl(size=size) 
    2362 
    2363 
    2364class MergedResult(IteratorResult[Unpack[_Ts]]): 
    2365    """A :class:`_engine.Result` that is merged from any number of 
    2366    :class:`_engine.Result` objects. 
    2367 
    2368    Returned by the :meth:`_engine.Result.merge` method. 
    2369 
    2370    .. versionadded:: 1.4 
    2371 
    2372    """ 
    2373 
    2374    closed = False 
    2375    rowcount: Optional[int] 
    2376 
    2377    def __init__( 
    2378        self, 
    2379        cursor_metadata: ResultMetaData, 
    2380        results: Sequence[Result[Unpack[_Ts]]], 
    2381    ): 
    2382        self._results = results 
    2383        super().__init__( 
    2384            cursor_metadata, 
    2385            itertools.chain.from_iterable( 
    2386                r._raw_row_iterator() for r in results 
    2387            ), 
    2388        ) 
    2389 
    2390        self._unique_filter_state = results[0]._unique_filter_state 
    2391        self._yield_per = results[0]._yield_per 
    2392 
    2393        # going to try something w/ this in next rev 
    2394        self._source_supports_scalars = results[0]._source_supports_scalars 
    2395 
    2396        self._attributes = self._attributes.merge_with( 
    2397            *[r._attributes for r in results] 
    2398        ) 
    2399 
    2400    def _soft_close(self, hard: bool = False, **kw: Any) -> None: 
    2401        for r in self._results: 
    2402            r._soft_close(hard=hard, **kw) 
    2403        if hard: 
    2404            self.closed = True