SQLAlchemy 2.1.0rc1__cp315-cp315-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. sqlalchemy/__init__.py +299 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +171 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +248 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +29 -0
  8. sqlalchemy/dialects/mssql/__init__.py +88 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4833 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +345 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +242 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +130 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +697 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +260 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +241 -0
  21. sqlalchemy/dialects/mysql/base.py +3896 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +107 -0
  23. sqlalchemy/dialects/mysql/dml.py +279 -0
  24. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  25. sqlalchemy/dialects/mysql/expression.py +146 -0
  26. sqlalchemy/dialects/mysql/json.py +92 -0
  27. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  28. sqlalchemy/dialects/mysql/mariadbconnector.py +314 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +291 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +318 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +188 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +157 -0
  34. sqlalchemy/dialects/mysql/reflection.py +724 -0
  35. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  36. sqlalchemy/dialects/mysql/types.py +845 -0
  37. sqlalchemy/dialects/oracle/__init__.py +85 -0
  38. sqlalchemy/dialects/oracle/base.py +3847 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1736 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +157 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +898 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +366 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +170 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +232 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1318 -0
  50. sqlalchemy/dialects/postgresql/base.py +5935 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +599 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +422 -0
  55. sqlalchemy/dialects/postgresql/json.py +411 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +535 -0
  57. sqlalchemy/dialects/postgresql/operators.py +129 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +655 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +345 -0
  60. sqlalchemy/dialects/postgresql/provision.py +202 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +800 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +62 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +59 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +375 -0
  68. sqlalchemy/dialects/sqlite/base.py +3103 -0
  69. sqlalchemy/dialects/sqlite/dml.py +314 -0
  70. sqlalchemy/dialects/sqlite/json.py +134 -0
  71. sqlalchemy/dialects/sqlite/provision.py +237 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +166 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +959 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp315-win32.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp315-win32.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +711 -0
  80. sqlalchemy/engine/_row_cy.cp315-win32.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp315-win32.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3357 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2425 -0
  88. sqlalchemy/engine/default.py +2627 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3636 -0
  91. sqlalchemy/engine/mock.py +133 -0
  92. sqlalchemy/engine/processors.py +83 -0
  93. sqlalchemy/engine/reflection.py +2141 -0
  94. sqlalchemy/engine/result.py +2012 -0
  95. sqlalchemy/engine/row.py +397 -0
  96. sqlalchemy/engine/strategies.py +16 -0
  97. sqlalchemy/engine/url.py +922 -0
  98. sqlalchemy/engine/util.py +164 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +675 -0
  102. sqlalchemy/event/base.py +473 -0
  103. sqlalchemy/event/legacy.py +259 -0
  104. sqlalchemy/event/registry.py +391 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +939 -0
  107. sqlalchemy/ext/__init__.py +10 -0
  108. sqlalchemy/ext/associationproxy.py +2073 -0
  109. sqlalchemy/ext/asyncio/__init__.py +29 -0
  110. sqlalchemy/ext/asyncio/base.py +281 -0
  111. sqlalchemy/ext/asyncio/engine.py +1487 -0
  112. sqlalchemy/ext/asyncio/exc.py +21 -0
  113. sqlalchemy/ext/asyncio/result.py +994 -0
  114. sqlalchemy/ext/asyncio/scoping.py +1679 -0
  115. sqlalchemy/ext/asyncio/session.py +2006 -0
  116. sqlalchemy/ext/automap.py +1702 -0
  117. sqlalchemy/ext/baked.py +558 -0
  118. sqlalchemy/ext/compiler.py +601 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +561 -0
  121. sqlalchemy/ext/horizontal_shard.py +481 -0
  122. sqlalchemy/ext/hybrid.py +1877 -0
  123. sqlalchemy/ext/indexable.py +364 -0
  124. sqlalchemy/ext/instrumentation.py +450 -0
  125. sqlalchemy/ext/mutable.py +1081 -0
  126. sqlalchemy/ext/orderinglist.py +440 -0
  127. sqlalchemy/ext/serializer.py +184 -0
  128. sqlalchemy/future/__init__.py +17 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +188 -0
  131. sqlalchemy/log.py +279 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +180 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +991 -0
  137. sqlalchemy/orm/bulk_persistence.py +2168 -0
  138. sqlalchemy/orm/clsregistry.py +630 -0
  139. sqlalchemy/orm/collections.py +1569 -0
  140. sqlalchemy/orm/context.py +3475 -0
  141. sqlalchemy/orm/decl_api.py +2283 -0
  142. sqlalchemy/orm/decl_base.py +2320 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +306 -0
  146. sqlalchemy/orm/evaluator.py +378 -0
  147. sqlalchemy/orm/events.py +3387 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +749 -0
  151. sqlalchemy/orm/interfaces.py +1595 -0
  152. sqlalchemy/orm/loading.py +1712 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4465 -0
  155. sqlalchemy/orm/path_registry.py +907 -0
  156. sqlalchemy/orm/persistence.py +1790 -0
  157. sqlalchemy/orm/properties.py +972 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3608 -0
  160. sqlalchemy/orm/scoping.py +2233 -0
  161. sqlalchemy/orm/session.py +5468 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3552 -0
  165. sqlalchemy/orm/strategy_options.py +2648 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +797 -0
  168. sqlalchemy/orm/util.py +2461 -0
  169. sqlalchemy/orm/writeonly.py +701 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1540 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +583 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +75 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +402 -0
  178. sqlalchemy/sql/_cache_key_cy.cp315-win32.pyd +0 -0
  179. sqlalchemy/sql/_cache_key_cy.py +363 -0
  180. sqlalchemy/sql/_dml_constructors.py +132 -0
  181. sqlalchemy/sql/_elements_constructors.py +2190 -0
  182. sqlalchemy/sql/_orm_types.py +19 -0
  183. sqlalchemy/sql/_selectable_constructors.py +840 -0
  184. sqlalchemy/sql/_typing.py +500 -0
  185. sqlalchemy/sql/_util_cy.cp315-win32.pyd +0 -0
  186. sqlalchemy/sql/_util_cy.pxd +11 -0
  187. sqlalchemy/sql/_util_cy.py +127 -0
  188. sqlalchemy/sql/annotation.py +590 -0
  189. sqlalchemy/sql/base.py +2702 -0
  190. sqlalchemy/sql/cache_key.py +915 -0
  191. sqlalchemy/sql/coercions.py +1373 -0
  192. sqlalchemy/sql/compiler.py +8453 -0
  193. sqlalchemy/sql/crud.py +1816 -0
  194. sqlalchemy/sql/ddl.py +1962 -0
  195. sqlalchemy/sql/default_comparator.py +660 -0
  196. sqlalchemy/sql/dml.py +2018 -0
  197. sqlalchemy/sql/elements.py +6057 -0
  198. sqlalchemy/sql/events.py +458 -0
  199. sqlalchemy/sql/expression.py +171 -0
  200. sqlalchemy/sql/functions.py +2380 -0
  201. sqlalchemy/sql/lambdas.py +1442 -0
  202. sqlalchemy/sql/naming.py +204 -0
  203. sqlalchemy/sql/operators.py +2909 -0
  204. sqlalchemy/sql/roles.py +332 -0
  205. sqlalchemy/sql/schema.py +7075 -0
  206. sqlalchemy/sql/selectable.py +7634 -0
  207. sqlalchemy/sql/sqltypes.py +4130 -0
  208. sqlalchemy/sql/traversals.py +1041 -0
  209. sqlalchemy/sql/type_api.py +2450 -0
  210. sqlalchemy/sql/util.py +1496 -0
  211. sqlalchemy/sql/visitors.py +1153 -0
  212. sqlalchemy/testing/__init__.py +97 -0
  213. sqlalchemy/testing/assertions.py +1007 -0
  214. sqlalchemy/testing/assertsql.py +519 -0
  215. sqlalchemy/testing/asyncio.py +128 -0
  216. sqlalchemy/testing/cancellation.py +237 -0
  217. sqlalchemy/testing/config.py +440 -0
  218. sqlalchemy/testing/engines.py +482 -0
  219. sqlalchemy/testing/entities.py +117 -0
  220. sqlalchemy/testing/exclusions.py +501 -0
  221. sqlalchemy/testing/fixtures/__init__.py +30 -0
  222. sqlalchemy/testing/fixtures/base.py +426 -0
  223. sqlalchemy/testing/fixtures/mypy.py +247 -0
  224. sqlalchemy/testing/fixtures/orm.py +227 -0
  225. sqlalchemy/testing/fixtures/sql.py +538 -0
  226. sqlalchemy/testing/pickleable.py +155 -0
  227. sqlalchemy/testing/plugin/__init__.py +6 -0
  228. sqlalchemy/testing/plugin/bootstrap.py +50 -0
  229. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  230. sqlalchemy/testing/plugin/pytestplugin.py +896 -0
  231. sqlalchemy/testing/profiles_file.py +350 -0
  232. sqlalchemy/testing/profiling.py +294 -0
  233. sqlalchemy/testing/provision.py +633 -0
  234. sqlalchemy/testing/requirements.py +1971 -0
  235. sqlalchemy/testing/schema.py +198 -0
  236. sqlalchemy/testing/suite/__init__.py +19 -0
  237. sqlalchemy/testing/suite/test_cte.py +237 -0
  238. sqlalchemy/testing/suite/test_ddl.py +420 -0
  239. sqlalchemy/testing/suite/test_dialect.py +776 -0
  240. sqlalchemy/testing/suite/test_insert.py +630 -0
  241. sqlalchemy/testing/suite/test_reflection.py +3815 -0
  242. sqlalchemy/testing/suite/test_results.py +660 -0
  243. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  244. sqlalchemy/testing/suite/test_select.py +2112 -0
  245. sqlalchemy/testing/suite/test_sequence.py +317 -0
  246. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  247. sqlalchemy/testing/suite/test_types.py +2271 -0
  248. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  249. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  250. sqlalchemy/testing/util.py +575 -0
  251. sqlalchemy/testing/warnings.py +52 -0
  252. sqlalchemy/types.py +75 -0
  253. sqlalchemy/util/__init__.py +165 -0
  254. sqlalchemy/util/_collections.py +688 -0
  255. sqlalchemy/util/_collections_cy.cp315-win32.pyd +0 -0
  256. sqlalchemy/util/_collections_cy.pxd +8 -0
  257. sqlalchemy/util/_collections_cy.py +516 -0
  258. sqlalchemy/util/_has_cython.py +48 -0
  259. sqlalchemy/util/_immutabledict_cy.cp315-win32.pyd +0 -0
  260. sqlalchemy/util/_immutabledict_cy.py +240 -0
  261. sqlalchemy/util/compat.py +298 -0
  262. sqlalchemy/util/concurrency.py +272 -0
  263. sqlalchemy/util/cython.py +95 -0
  264. sqlalchemy/util/deprecations.py +401 -0
  265. sqlalchemy/util/langhelpers.py +2797 -0
  266. sqlalchemy/util/preloaded.py +153 -0
  267. sqlalchemy/util/queue.py +304 -0
  268. sqlalchemy/util/tool_support.py +202 -0
  269. sqlalchemy/util/topological.py +120 -0
  270. sqlalchemy/util/typing.py +709 -0
  271. sqlalchemy-2.1.0rc1.dist-info/METADATA +270 -0
  272. sqlalchemy-2.1.0rc1.dist-info/RECORD +276 -0
  273. sqlalchemy-2.1.0rc1.dist-info/WHEEL +5 -0
  274. sqlalchemy-2.1.0rc1.dist-info/licenses/AUTHORS +30 -0
  275. sqlalchemy-2.1.0rc1.dist-info/licenses/LICENSE +19 -0
  276. sqlalchemy-2.1.0rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2012 @@
1
+ # engine/result.py
2
+ # Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+
8
+ """Define generic result set constructs."""
9
+
10
+ from __future__ import annotations
11
+
12
+ import functools
13
+ import itertools
14
+ import operator
15
+ import typing
16
+ from typing import Any
17
+ from typing import Callable
18
+ from typing import cast
19
+ from typing import Dict
20
+ from typing import Generic
21
+ from typing import Iterable
22
+ from typing import Iterator
23
+ from typing import List
24
+ from typing import Literal
25
+ from typing import Mapping
26
+ from typing import NoReturn
27
+ from typing import Optional
28
+ from typing import overload
29
+ from typing import Sequence
30
+ from typing import Tuple
31
+ from typing import TYPE_CHECKING
32
+ from typing import Union
33
+
34
+ from ._result_cy import _InterimRowType
35
+ from ._result_cy import _NO_ROW as _NO_ROW
36
+ from ._result_cy import _R as _R
37
+ from ._result_cy import _RowData
38
+ from ._result_cy import _T
39
+ from ._result_cy import _UniqueFilterType as _UniqueFilterType
40
+ from ._result_cy import BaseResultInternal
41
+ from ._util_cy import tuplegetter as tuplegetter
42
+ from .row import Row
43
+ from .row import RowMapping
44
+ from .. import exc
45
+ from .. import util
46
+ from ..sql.base import _generative
47
+ from ..sql.base import InPlaceGenerative
48
+ from ..util import deprecated
49
+ from ..util import NONE_SET
50
+ from ..util.typing import Never
51
+ from ..util.typing import Self
52
+ from ..util.typing import TupleAny
53
+ from ..util.typing import TypeVarTuple
54
+ from ..util.typing import Unpack
55
+
56
+ if typing.TYPE_CHECKING:
57
+ from typing import Type
58
+
59
+ from .. import inspection
60
+ from ..sql import roles
61
+ from ..sql._typing import _HasClauseElement
62
+ from ..sql.elements import SQLCoreOperations
63
+ from ..sql.type_api import _ResultProcessorType
64
+
65
+ _KeyType = Union[
66
+ str,
67
+ "SQLCoreOperations[Any]",
68
+ "roles.TypedColumnsClauseRole[Any]",
69
+ "roles.ColumnsClauseRole",
70
+ "Type[Any]",
71
+ "inspection.Inspectable[_HasClauseElement[Any]]",
72
+ ]
73
+ _KeyIndexType = Union[_KeyType, int]
74
+
75
+ # is overridden in cursor using _CursorKeyMapRecType
76
+ _KeyMapRecType = Any
77
+
78
+ _KeyMapType = Mapping[_KeyType, _KeyMapRecType]
79
+
80
+
81
+ _Ts = TypeVarTuple("_Ts")
82
+
83
+
84
+ _InterimSupportsScalarsRowType = Union[Row[Unpack[TupleAny]], Any]
85
+
86
+ _ProcessorsType = Sequence[Optional["_ResultProcessorType[Any]"]]
87
+ _TupleGetterType = Callable[[Sequence[Any]], Sequence[Any]]
88
+
89
+
90
+ class 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
+ _create_unique_filters: Optional[
98
+ Callable[["Result[Any]"], Sequence[Optional[Callable[[Any], Any]]]]
99
+ ] = None
100
+ _keymap: _KeyMapType
101
+ _keys: Sequence[str]
102
+ _processors: Optional[_ProcessorsType]
103
+ _key_to_index: Dict[_KeyType, int]
104
+
105
+ @property
106
+ def keys(self) -> RMKeyView:
107
+ return RMKeyView(self)
108
+
109
+ def _has_key(self, key: object) -> bool:
110
+ raise NotImplementedError()
111
+
112
+ def _for_freeze(self) -> ResultMetaData:
113
+ raise NotImplementedError()
114
+
115
+ @overload
116
+ def _key_fallback(
117
+ self, key: Any, err: Optional[Exception], raiseerr: Literal[True] = ...
118
+ ) -> NoReturn: ...
119
+
120
+ @overload
121
+ def _key_fallback(
122
+ self,
123
+ key: Any,
124
+ err: Optional[Exception],
125
+ raiseerr: Literal[False] = ...,
126
+ ) -> None: ...
127
+
128
+ @overload
129
+ def _key_fallback(
130
+ self, key: Any, err: Optional[Exception], raiseerr: bool = ...
131
+ ) -> Optional[NoReturn]: ...
132
+
133
+ def _key_fallback(
134
+ self, key: Any, err: Optional[Exception], raiseerr: bool = True
135
+ ) -> Optional[NoReturn]:
136
+ assert raiseerr
137
+ raise KeyError(key) from err
138
+
139
+ def _raise_for_ambiguous_column_name(
140
+ self, rec: _KeyMapRecType
141
+ ) -> NoReturn:
142
+ raise NotImplementedError(
143
+ "ambiguous column name logic is implemented for "
144
+ "CursorResultMetaData"
145
+ )
146
+
147
+ def _index_for_key(
148
+ self, key: _KeyIndexType, raiseerr: bool
149
+ ) -> Optional[int]:
150
+ raise NotImplementedError()
151
+
152
+ def _indexes_for_keys(
153
+ self, keys: Sequence[_KeyIndexType]
154
+ ) -> Sequence[int]:
155
+ raise NotImplementedError()
156
+
157
+ def _metadata_for_keys(
158
+ self, keys: Sequence[_KeyIndexType]
159
+ ) -> Iterator[_KeyMapRecType]:
160
+ raise NotImplementedError()
161
+
162
+ def _reduce(self, keys: Sequence[_KeyIndexType]) -> ResultMetaData:
163
+ raise NotImplementedError()
164
+
165
+ def _getter(
166
+ self, key: Any, raiseerr: bool = True
167
+ ) -> Optional[Callable[[Row[Unpack[TupleAny]]], Any]]:
168
+ index = self._index_for_key(key, raiseerr)
169
+
170
+ if index is not None:
171
+ return operator.itemgetter(index)
172
+ else:
173
+ return None
174
+
175
+ def _row_as_tuple_getter(
176
+ self, keys: Sequence[_KeyIndexType]
177
+ ) -> _TupleGetterType:
178
+ indexes = self._indexes_for_keys(keys)
179
+ return tuplegetter(*indexes)
180
+
181
+ def _make_key_to_index(
182
+ self, keymap: Mapping[_KeyType, Sequence[Any]], index: int
183
+ ) -> Dict[_KeyType, int]:
184
+ return {
185
+ key: rec[index]
186
+ for key, rec in keymap.items()
187
+ if rec[index] is not None
188
+ }
189
+
190
+ def _key_not_found(self, key: Any, attr_error: bool) -> NoReturn:
191
+ if key in self._keymap:
192
+ # the index must be none in this case
193
+ self._raise_for_ambiguous_column_name(self._keymap[key])
194
+ else:
195
+ # unknown key
196
+ if attr_error:
197
+ try:
198
+ self._key_fallback(key, None)
199
+ except KeyError as ke:
200
+ raise AttributeError(ke.args[0]) from ke
201
+ else:
202
+ self._key_fallback(key, None)
203
+
204
+ @property
205
+ def _effective_processors(self) -> Optional[_ProcessorsType]:
206
+ if not self._processors or NONE_SET.issuperset(self._processors):
207
+ return None
208
+ else:
209
+ return self._processors
210
+
211
+
212
+ class RMKeyView(typing.KeysView[Any]):
213
+ __slots__ = ("_parent", "_keys")
214
+
215
+ _parent: ResultMetaData
216
+ _keys: Sequence[str]
217
+
218
+ def __init__(self, parent: ResultMetaData):
219
+ self._parent = parent
220
+ self._keys = [k for k in parent._keys if k is not None]
221
+
222
+ def __len__(self) -> int:
223
+ return len(self._keys)
224
+
225
+ def __repr__(self) -> str:
226
+ return "{0.__class__.__name__}({0._keys!r})".format(self)
227
+
228
+ def __iter__(self) -> Iterator[str]:
229
+ return iter(self._keys)
230
+
231
+ def __contains__(self, item: Any) -> bool:
232
+ if isinstance(item, int):
233
+ return False
234
+
235
+ # note this also includes special key fallback behaviors
236
+ # which also don't seem to be tested in test_resultset right now
237
+ return self._parent._has_key(item)
238
+
239
+ def __eq__(self, other: Any) -> bool:
240
+ return list(other) == list(self)
241
+
242
+ def __ne__(self, other: Any) -> bool:
243
+ return list(other) != list(self)
244
+
245
+
246
+ class SimpleResultMetaData(ResultMetaData):
247
+ """result metadata for in-memory collections."""
248
+
249
+ __slots__ = (
250
+ "_keys",
251
+ "_keymap",
252
+ "_processors",
253
+ "_tuplefilter",
254
+ "_translated_indexes",
255
+ "_create_unique_filters",
256
+ "_key_to_index",
257
+ "_ambiguous_keys",
258
+ )
259
+
260
+ _keys: Sequence[str]
261
+
262
+ def __init__(
263
+ self,
264
+ keys: Sequence[str],
265
+ extra: Optional[Sequence[Any]] = None,
266
+ _processors: Optional[_ProcessorsType] = None,
267
+ _tuplefilter: Optional[_TupleGetterType] = None,
268
+ _translated_indexes: Optional[Sequence[int]] = None,
269
+ _create_unique_filters: Optional[
270
+ Callable[
271
+ [Any],
272
+ Sequence[Optional[Callable[[Any], Any]]],
273
+ ]
274
+ ] = None,
275
+ _ambiguous_keys: Optional[frozenset[str]] = None,
276
+ ):
277
+ self._keys = list(keys)
278
+ self._tuplefilter = _tuplefilter
279
+ self._translated_indexes = _translated_indexes
280
+ self._create_unique_filters = _create_unique_filters
281
+ if extra:
282
+ assert len(self._keys) == len(extra)
283
+ recs_names = [
284
+ (
285
+ (name,) + (extras if extras else ()),
286
+ (index, name, extras),
287
+ )
288
+ for index, (name, extras) in enumerate(zip(self._keys, extra))
289
+ ]
290
+ else:
291
+ recs_names = [
292
+ ((name,), (index, name, ()))
293
+ for index, name in enumerate(self._keys)
294
+ ]
295
+
296
+ self._keymap = {key: rec for keys, rec in recs_names for key in keys}
297
+
298
+ if _ambiguous_keys:
299
+ for name in _ambiguous_keys.intersection(self._keymap):
300
+ rec = self._keymap[name]
301
+ self._keymap[name] = (None,) + rec[1:]
302
+
303
+ self._processors = _processors
304
+
305
+ self._ambiguous_keys = _ambiguous_keys
306
+
307
+ self._key_to_index = self._make_key_to_index(self._keymap, 0)
308
+
309
+ def _has_key(self, key: object) -> bool:
310
+ return key in self._keymap
311
+
312
+ def _for_freeze(self) -> ResultMetaData:
313
+ # TODO: are we freezing the result with or without uniqueness
314
+ # applied?
315
+ create_unique_filters = self._create_unique_filters
316
+ if create_unique_filters is not None and self._tuplefilter is not None:
317
+ _tuplefilter = self._tuplefilter
318
+ _orig_create_unique_filters = create_unique_filters
319
+
320
+ def create_unique_filters_filtered(
321
+ result: Result[Any],
322
+ ) -> Sequence[Optional[Callable[[Any], Any]]]:
323
+ return _tuplefilter(_orig_create_unique_filters(result))
324
+
325
+ create_unique_filters = create_unique_filters_filtered
326
+
327
+ return SimpleResultMetaData(
328
+ self._keys,
329
+ extra=[self._keymap[key][2] for key in self._keys],
330
+ _create_unique_filters=create_unique_filters,
331
+ _ambiguous_keys=self._ambiguous_keys,
332
+ )
333
+
334
+ def __getstate__(self) -> Dict[str, Any]:
335
+ return {
336
+ "_keys": self._keys,
337
+ "_translated_indexes": self._translated_indexes,
338
+ "_ambiguous_keys": self._ambiguous_keys,
339
+ }
340
+
341
+ def __setstate__(self, state: Dict[str, Any]) -> None:
342
+ if state["_translated_indexes"]:
343
+ _translated_indexes = state["_translated_indexes"]
344
+ _tuplefilter = tuplegetter(*_translated_indexes)
345
+ else:
346
+ _translated_indexes = _tuplefilter = None
347
+ self.__init__( # type: ignore[misc]
348
+ state["_keys"],
349
+ _translated_indexes=_translated_indexes,
350
+ _tuplefilter=_tuplefilter,
351
+ _ambiguous_keys=state.get("_ambiguous_keys"),
352
+ )
353
+
354
+ def _index_for_key(self, key: Any, raiseerr: bool = True) -> int:
355
+ if isinstance(key, int):
356
+ key = self._keys[key]
357
+ try:
358
+ rec = self._keymap[key]
359
+ except KeyError as ke:
360
+ rec = self._key_fallback(key, ke, raiseerr)
361
+
362
+ if rec[0] is None:
363
+ self._raise_for_ambiguous_column_name(rec)
364
+ return rec[0] # type: ignore[no-any-return]
365
+
366
+ def _raise_for_ambiguous_column_name(
367
+ self, rec: _KeyMapRecType
368
+ ) -> NoReturn:
369
+ raise exc.InvalidRequestError(
370
+ "Ambiguous column name '%s' in "
371
+ "result set column descriptions" % rec[1]
372
+ )
373
+
374
+ def _indexes_for_keys(self, keys: Sequence[Any]) -> Sequence[int]:
375
+ # only used by the ORM with Column objects; does not need
376
+ # ambiguous column name support
377
+ return [self._keymap[key][0] for key in keys]
378
+
379
+ def _metadata_for_keys(
380
+ self, keys: Sequence[Any]
381
+ ) -> Iterator[_KeyMapRecType]:
382
+ for key in keys:
383
+ if isinstance(key, int):
384
+ key = self._keys[key]
385
+
386
+ try:
387
+ rec = self._keymap[key]
388
+ except KeyError as ke:
389
+ rec = self._key_fallback(key, ke, True)
390
+
391
+ if rec[0] is None:
392
+ self._raise_for_ambiguous_column_name(rec)
393
+
394
+ yield rec
395
+
396
+ def _reduce(self, keys: Sequence[Any]) -> ResultMetaData:
397
+ try:
398
+ metadata_for_keys = [
399
+ self._keymap[self._keys[key] if isinstance(key, int) else key]
400
+ for key in keys
401
+ ]
402
+ except KeyError as ke:
403
+ self._key_fallback(ke.args[0], ke, True)
404
+
405
+ indexes: Sequence[int]
406
+ new_keys: Sequence[str]
407
+ extra: Sequence[Any]
408
+ indexes, new_keys, extra = zip(*metadata_for_keys)
409
+
410
+ if self._translated_indexes:
411
+ indexes = [self._translated_indexes[idx] for idx in indexes]
412
+
413
+ tup = tuplegetter(*indexes)
414
+
415
+ new_metadata = SimpleResultMetaData(
416
+ new_keys,
417
+ extra=extra,
418
+ _tuplefilter=tup,
419
+ _translated_indexes=indexes,
420
+ _processors=self._processors,
421
+ _create_unique_filters=self._create_unique_filters,
422
+ )
423
+
424
+ return new_metadata
425
+
426
+
427
+ def result_tuple(
428
+ fields: Sequence[str], extra: Optional[Any] = None
429
+ ) -> Callable[[Iterable[Any]], Row[Unpack[TupleAny]]]:
430
+ parent = SimpleResultMetaData(fields, extra)
431
+ return functools.partial(
432
+ Row, parent, parent._effective_processors, parent._key_to_index
433
+ )
434
+
435
+
436
+ class ResultInternal(InPlaceGenerative, BaseResultInternal[_R]):
437
+ __slots__ = ()
438
+ _is_cursor = False
439
+
440
+ @_generative
441
+ def _column_slices(self, indexes: Sequence[_KeyIndexType]) -> Self:
442
+ real_result = (
443
+ self._real_result
444
+ if self._real_result
445
+ else cast("Result[Any]", self)
446
+ )
447
+
448
+ if not real_result._source_supports_scalars or len(indexes) != 1:
449
+ self._metadata = self._metadata._reduce(indexes)
450
+
451
+ assert self._generate_rows
452
+
453
+ return self
454
+
455
+
456
+ class _WithKeys:
457
+ __slots__ = ()
458
+
459
+ _metadata: ResultMetaData
460
+
461
+ # used mainly to share documentation on the keys method.
462
+ def keys(self) -> RMKeyView:
463
+ """Return an iterable view which yields the string keys that would
464
+ be represented by each :class:`_engine.Row`.
465
+
466
+ The keys can represent the labels of the columns returned by a core
467
+ statement or the names of the orm classes returned by an orm
468
+ execution.
469
+
470
+ The view also can be tested for key containment using the Python
471
+ ``in`` operator, which will test both for the string keys represented
472
+ in the view, as well as for alternate keys such as column objects.
473
+
474
+ .. versionchanged:: 1.4 a key view object is returned rather than a
475
+ plain list.
476
+
477
+
478
+ """
479
+ return self._metadata.keys
480
+
481
+
482
+ class Result(_WithKeys, ResultInternal[Row[Unpack[_Ts]]]):
483
+ """Represent a set of database results.
484
+
485
+ .. versionadded:: 1.4 The :class:`_engine.Result` object provides a
486
+ completely updated usage model and calling facade for SQLAlchemy
487
+ Core and SQLAlchemy ORM. In Core, it forms the basis of the
488
+ :class:`_engine.CursorResult` object which replaces the previous
489
+ :class:`_engine.ResultProxy` interface. When using the ORM, a
490
+ higher level object called :class:`_engine.ChunkedIteratorResult`
491
+ is normally used.
492
+
493
+ .. note:: In SQLAlchemy 1.4 and above, this object is
494
+ used for ORM results returned by :meth:`_orm.Session.execute`, which can
495
+ yield instances of ORM mapped objects either individually or within
496
+ tuple-like rows. Note that the :class:`_engine.Result` object does not
497
+ deduplicate instances or rows automatically as is the case with the
498
+ legacy :class:`_orm.Query` object. For in-Python de-duplication of
499
+ instances or rows, use the :meth:`_engine.Result.unique` modifier
500
+ method.
501
+
502
+ .. seealso::
503
+
504
+ :ref:`tutorial_fetching_rows` - in the :doc:`/tutorial/index`
505
+
506
+ """
507
+
508
+ __slots__ = ("_metadata", "__dict__")
509
+
510
+ _row_logging_fn: Optional[
511
+ Callable[[Row[Unpack[TupleAny]]], Row[Unpack[TupleAny]]]
512
+ ] = None
513
+
514
+ _source_supports_scalars: bool = False
515
+
516
+ _yield_per: Optional[int] = None
517
+
518
+ _attributes: util.immutabledict[Any, Any] = util.immutabledict()
519
+
520
+ def __init__(self, cursor_metadata: ResultMetaData):
521
+ self._metadata = cursor_metadata
522
+
523
+ def __enter__(self) -> Self:
524
+ return self
525
+
526
+ def __exit__(self, type_: Any, value: Any, traceback: Any) -> None:
527
+ self.close()
528
+
529
+ def close(self) -> None:
530
+ """Hard close this :class:`_engine.Result`.
531
+
532
+ The behavior of this method is implementation specific, and is
533
+ not implemented by default. The method should generally end
534
+ the resources in use by the result object and also cause any
535
+ subsequent iteration or row fetching to raise
536
+ :class:`.ResourceClosedError`.
537
+
538
+ .. versionadded:: 1.4.27 - ``.close()`` was previously not generally
539
+ available for all :class:`_engine.Result` classes, instead only
540
+ being available on the :class:`_engine.CursorResult` returned for
541
+ Core statement executions. As most other result objects, namely the
542
+ ones used by the ORM, are proxying a :class:`_engine.CursorResult`
543
+ in any case, this allows the underlying cursor result to be closed
544
+ from the outside facade for the case when the ORM query is using
545
+ the ``yield_per`` execution option where it does not immediately
546
+ exhaust and autoclose the database cursor.
547
+
548
+ """
549
+ self._soft_close(hard=True)
550
+
551
+ @property
552
+ def _soft_closed(self) -> bool:
553
+ raise NotImplementedError()
554
+
555
+ @property
556
+ def closed(self) -> bool:
557
+ """Return ``True`` if this :class:`_engine.Result` was **hard closed**
558
+ by explicitly calling the :meth:`close` method.
559
+
560
+ The attribute is **not** True if the :class:`_engine.Result` was only
561
+ **soft closed**; a "soft close" is the style of close that takes place
562
+ for example when the :class:`.CursorResult` is returned for a DML
563
+ only statement without RETURNING, or when all result rows are fetched.
564
+
565
+ .. seealso::
566
+
567
+ :attr:`.CursorResult.returns_rows` - attribute specific to
568
+ :class:`.CursorResult` which indicates if the result is one that
569
+ may return zero or more rows
570
+
571
+ """
572
+ raise NotImplementedError()
573
+
574
+ @_generative
575
+ def yield_per(self, num: int) -> Self:
576
+ """Configure the row-fetching strategy to fetch ``num`` rows at a time.
577
+
578
+ This impacts the underlying behavior of the result when iterating over
579
+ the result object, or otherwise making use of methods such as
580
+ :meth:`_engine.Result.fetchone` that return one row at a time. Data
581
+ from the underlying cursor or other data source will be buffered up to
582
+ this many rows in memory, and the buffered collection will then be
583
+ yielded out one row at a time or as many rows are requested. Each time
584
+ the buffer clears, it will be refreshed to this many rows or as many
585
+ rows remain if fewer remain.
586
+
587
+ The :meth:`_engine.Result.yield_per` method is generally used in
588
+ conjunction with the
589
+ :paramref:`_engine.Connection.execution_options.stream_results`
590
+ execution option, which will allow the database dialect in use to make
591
+ use of a server side cursor, if the DBAPI supports a specific "server
592
+ side cursor" mode separate from its default mode of operation.
593
+
594
+ .. tip::
595
+
596
+ Consider using the
597
+ :paramref:`_engine.Connection.execution_options.yield_per`
598
+ execution option, which will simultaneously set
599
+ :paramref:`_engine.Connection.execution_options.stream_results`
600
+ to ensure the use of server side cursors, as well as automatically
601
+ invoke the :meth:`_engine.Result.yield_per` method to establish
602
+ a fixed row buffer size at once.
603
+
604
+ The :paramref:`_engine.Connection.execution_options.yield_per`
605
+ execution option is available for ORM operations, with
606
+ :class:`_orm.Session`-oriented use described at
607
+ :ref:`orm_queryguide_yield_per`. The Core-only version which works
608
+ with :class:`_engine.Connection` is new as of SQLAlchemy 1.4.40.
609
+
610
+ .. versionadded:: 1.4
611
+
612
+ :param num: number of rows to fetch each time the buffer is refilled.
613
+ If set to a value below 1, fetches all rows for the next buffer.
614
+
615
+ .. seealso::
616
+
617
+ :ref:`engine_stream_results` - describes Core behavior for
618
+ :meth:`_engine.Result.yield_per`
619
+
620
+ :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel`
621
+
622
+ """
623
+ self._yield_per = num
624
+ return self
625
+
626
+ @_generative
627
+ def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self:
628
+ """Apply unique filtering to the objects returned by this
629
+ :class:`_engine.Result`.
630
+
631
+ When this filter is applied with no arguments, the rows or objects
632
+ returned will filtered such that each row is returned uniquely. The
633
+ algorithm used to determine this uniqueness is by default the Python
634
+ hashing identity of the whole tuple. In some cases a specialized
635
+ per-entity hashing scheme may be used, such as when using the ORM, a
636
+ scheme is applied which works against the primary key identity of
637
+ returned objects.
638
+
639
+ The unique filter is applied **after all other filters**, which means
640
+ if the columns returned have been refined using a method such as the
641
+ :meth:`_engine.Result.columns` or :meth:`_engine.Result.scalars`
642
+ method, the uniquing is applied to **only the column or columns
643
+ returned**. This occurs regardless of the order in which these
644
+ methods have been called upon the :class:`_engine.Result` object.
645
+
646
+ The unique filter also changes the calculus used for methods like
647
+ :meth:`_engine.Result.fetchmany` and :meth:`_engine.Result.partitions`.
648
+ When using :meth:`_engine.Result.unique`, these methods will continue
649
+ to yield the number of rows or objects requested, after uniquing
650
+ has been applied. However, this necessarily impacts the buffering
651
+ behavior of the underlying cursor or datasource, such that multiple
652
+ underlying calls to ``cursor.fetchmany()`` may be necessary in order
653
+ to accumulate enough objects in order to provide a unique collection
654
+ of the requested size.
655
+
656
+ :param strategy: a callable that will be applied to rows or objects
657
+ being iterated, which should return an object that represents the
658
+ unique value of the row. A Python ``set()`` is used to store
659
+ these identities. If not passed, a default uniqueness strategy
660
+ is used which may have been assembled by the source of this
661
+ :class:`_engine.Result` object.
662
+
663
+ """
664
+ self._unique_filter_state = (set(), strategy)
665
+ return self
666
+
667
+ def columns(self, *col_expressions: _KeyIndexType) -> Self:
668
+ r"""Establish the columns that should be returned in each row.
669
+
670
+ This method may be used to limit the columns returned as well
671
+ as to reorder them. The given list of expressions are normally
672
+ a series of integers or string key names. They may also be
673
+ appropriate :class:`.ColumnElement` objects which correspond to
674
+ a given statement construct.
675
+
676
+ .. versionchanged:: 2.0 Due to a bug in 1.4, the
677
+ :meth:`_engine.Result.columns` method had an incorrect behavior
678
+ where calling upon the method with just one index would cause the
679
+ :class:`_engine.Result` object to yield scalar values rather than
680
+ :class:`_engine.Row` objects. In version 2.0, this behavior
681
+ has been corrected such that calling upon
682
+ :meth:`_engine.Result.columns` with a single index will
683
+ produce a :class:`_engine.Result` object that continues
684
+ to yield :class:`_engine.Row` objects, which include
685
+ only a single column.
686
+
687
+ E.g.::
688
+
689
+ statement = select(table.c.x, table.c.y, table.c.z)
690
+ result = connection.execute(statement)
691
+
692
+ for z, y in result.columns("z", "y"):
693
+ ...
694
+
695
+ Example of using the column objects from the statement itself::
696
+
697
+ for z, y in result.columns(
698
+ statement.selected_columns.c.z, statement.selected_columns.c.y
699
+ ):
700
+ ...
701
+
702
+ .. versionadded:: 1.4
703
+
704
+ :param \*col_expressions: indicates columns to be returned. Elements
705
+ may be integer row indexes, string column names, or appropriate
706
+ :class:`.ColumnElement` objects corresponding to a select construct.
707
+
708
+ :return: this :class:`_engine.Result` object with the modifications
709
+ given.
710
+
711
+ """
712
+ return self._column_slices(col_expressions)
713
+
714
+ @overload
715
+ def scalars(self: Result[_T, Unpack[TupleAny]]) -> ScalarResult[_T]: ...
716
+
717
+ @overload
718
+ def scalars(
719
+ self: Result[_T, Unpack[TupleAny]], index: Literal[0]
720
+ ) -> ScalarResult[_T]: ...
721
+
722
+ @overload
723
+ def scalars(self, index: _KeyIndexType = 0) -> ScalarResult[Any]: ...
724
+
725
+ def scalars(self, index: _KeyIndexType = 0) -> ScalarResult[Any]:
726
+ """Return a :class:`_engine.ScalarResult` filtering object which
727
+ will return single elements rather than :class:`_row.Row` objects.
728
+
729
+ E.g.::
730
+
731
+ >>> result = conn.execute(text("select int_id from table"))
732
+ >>> result.scalars().all()
733
+ [1, 2, 3]
734
+
735
+ When results are fetched from the :class:`_engine.ScalarResult`
736
+ filtering object, the single column-row that would be returned by the
737
+ :class:`_engine.Result` is instead returned as the column's value.
738
+
739
+ .. versionadded:: 1.4
740
+
741
+ :param index: integer or row key indicating the column to be fetched
742
+ from each row, defaults to ``0`` indicating the first column.
743
+
744
+ :return: a new :class:`_engine.ScalarResult` filtering object referring
745
+ to this :class:`_engine.Result` object.
746
+
747
+ """
748
+ return ScalarResult(self, index)
749
+
750
+ def _getter(
751
+ self, key: _KeyIndexType, raiseerr: bool = True
752
+ ) -> Optional[Callable[[Row[Unpack[TupleAny]]], Any]]:
753
+ """return a callable that will retrieve the given key from a
754
+ :class:`_engine.Row`.
755
+
756
+ """
757
+ if self._source_supports_scalars:
758
+ raise NotImplementedError(
759
+ "can't use this function in 'only scalars' mode"
760
+ )
761
+ return self._metadata._getter(key, raiseerr)
762
+
763
+ def _tuple_getter(self, keys: Sequence[_KeyIndexType]) -> _TupleGetterType:
764
+ """return a callable that will retrieve the given keys from a
765
+ :class:`_engine.Row`.
766
+
767
+ """
768
+ if self._source_supports_scalars:
769
+ raise NotImplementedError(
770
+ "can't use this function in 'only scalars' mode"
771
+ )
772
+ return self._metadata._row_as_tuple_getter(keys)
773
+
774
+ def mappings(self) -> MappingResult:
775
+ """Apply a mappings filter to returned rows, returning an instance of
776
+ :class:`_engine.MappingResult`.
777
+
778
+ When this filter is applied, fetching rows will return
779
+ :class:`_engine.RowMapping` objects instead of :class:`_engine.Row`
780
+ objects.
781
+
782
+ .. versionadded:: 1.4
783
+
784
+ :return: a new :class:`_engine.MappingResult` filtering object
785
+ referring to this :class:`_engine.Result` object.
786
+
787
+ """
788
+
789
+ return MappingResult(self)
790
+
791
+ @property
792
+ @deprecated(
793
+ "2.1.0",
794
+ "The :attr:`.Result.t` method is deprecated, :class:`.Row` "
795
+ "now behaves like a tuple and can unpack types directly.",
796
+ )
797
+ def t(self) -> TupleResult[Tuple[Unpack[_Ts]]]:
798
+ """Apply a "typed tuple" typing filter to returned rows.
799
+
800
+ The :attr:`_engine.Result.t` attribute is a synonym for
801
+ calling the :meth:`_engine.Result.tuples` method.
802
+
803
+ .. versionadded:: 2.0
804
+
805
+ .. seealso::
806
+
807
+ :ref:`change_10635` - describes a migration path from this
808
+ workaround for SQLAlchemy 2.1.
809
+
810
+ """
811
+ return self # type: ignore[return-value]
812
+
813
+ @deprecated(
814
+ "2.1.0",
815
+ "The :meth:`.Result.tuples` method is deprecated, :class:`.Row` "
816
+ "now behaves like a tuple and can unpack types directly.",
817
+ )
818
+ def tuples(self) -> TupleResult[Tuple[Unpack[_Ts]]]:
819
+ """Apply a "typed tuple" typing filter to returned rows.
820
+
821
+ This method returns the same :class:`_engine.Result` object
822
+ at runtime,
823
+ however annotates as returning a :class:`_engine.TupleResult` object
824
+ that will indicate to :pep:`484` typing tools that plain typed
825
+ ``Tuple`` instances are returned rather than rows. This allows
826
+ tuple unpacking and ``__getitem__`` access of :class:`_engine.Row`
827
+ objects to by typed, for those cases where the statement invoked
828
+ itself included typing information.
829
+
830
+ .. versionadded:: 2.0
831
+
832
+ :return: the :class:`_engine.TupleResult` type at typing time.
833
+
834
+ .. seealso::
835
+
836
+ :ref:`change_10635` - describes a migration path from this
837
+ workaround for SQLAlchemy 2.1.
838
+
839
+ :attr:`_engine.Result.t` - shorter synonym
840
+
841
+ :attr:`_engine.Row._t` - :class:`_engine.Row` version
842
+
843
+ """
844
+
845
+ return self # type: ignore[return-value]
846
+
847
+ def _raw_row_iterator(self) -> Iterator[_RowData]:
848
+ """Return a safe iterator that yields raw row data.
849
+
850
+ This is used by the :meth:`_engine.Result.merge` method
851
+ to merge multiple compatible results together.
852
+
853
+ """
854
+ raise NotImplementedError()
855
+
856
+ def __iter__(self) -> Iterator[Row[Unpack[_Ts]]]:
857
+ return self._iter_impl()
858
+
859
+ def __next__(self) -> Row[Unpack[_Ts]]:
860
+ return self._next_impl()
861
+
862
+ def partitions(
863
+ self, size: Optional[int] = None
864
+ ) -> Iterator[Sequence[Row[Unpack[_Ts]]]]:
865
+ """Iterate through sub-lists of rows of the size given.
866
+
867
+ Each list will be of the size given, excluding the last list to
868
+ be yielded, which may have a small number of rows. No empty
869
+ lists will be yielded.
870
+
871
+ The result object is automatically closed when the iterator
872
+ is fully consumed.
873
+
874
+ Note that the backend driver will usually buffer the entire result
875
+ ahead of time unless the
876
+ :paramref:`.Connection.execution_options.stream_results` execution
877
+ option is used indicating that the driver should not pre-buffer
878
+ results, if possible. Not all drivers support this option and
879
+ the option is silently ignored for those who do not.
880
+
881
+ When using the ORM, the :meth:`_engine.Result.partitions` method
882
+ is typically more effective from a memory perspective when it is
883
+ combined with use of the
884
+ :ref:`yield_per execution option <orm_queryguide_yield_per>`,
885
+ which instructs both the DBAPI driver to use server side cursors,
886
+ if available, as well as instructs the ORM loading internals to only
887
+ build a certain amount of ORM objects from a result at a time before
888
+ yielding them out.
889
+
890
+ .. versionadded:: 1.4
891
+
892
+ :param size: indicate the maximum number of rows to be present
893
+ in each list yielded. If None, makes use of the value set by
894
+ the :meth:`_engine.Result.yield_per`, method, if it were called,
895
+ or the :paramref:`_engine.Connection.execution_options.yield_per`
896
+ execution option, which is equivalent in this regard. If
897
+ yield_per weren't set, it makes use of the
898
+ :meth:`_engine.Result.fetchmany` default, which may be backend
899
+ specific and not well defined.
900
+
901
+ :return: iterator of lists
902
+
903
+ .. seealso::
904
+
905
+ :ref:`engine_stream_results`
906
+
907
+ :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel`
908
+
909
+ """
910
+
911
+ getter = self._manyrow_getter
912
+
913
+ while True:
914
+ partition = getter(self, size)
915
+ if partition:
916
+ yield partition
917
+ else:
918
+ break
919
+
920
+ def fetchall(self) -> Sequence[Row[Unpack[_Ts]]]:
921
+ """A synonym for the :meth:`_engine.Result.all` method."""
922
+
923
+ return self._allrows()
924
+
925
+ def fetchone(self) -> Optional[Row[Unpack[_Ts]]]:
926
+ """Fetch one row.
927
+
928
+ When all rows are exhausted, returns None.
929
+
930
+ This method is provided for backwards compatibility with
931
+ SQLAlchemy 1.x.x.
932
+
933
+ To fetch the first row of a result only, use the
934
+ :meth:`_engine.Result.first` method. To iterate through all
935
+ rows, iterate the :class:`_engine.Result` object directly.
936
+
937
+ :return: a :class:`_engine.Row` object if no filters are applied,
938
+ or ``None`` if no rows remain.
939
+
940
+ """
941
+ row = self._onerow_getter(self)
942
+ if row is _NO_ROW:
943
+ return None
944
+ else:
945
+ return row
946
+
947
+ def fetchmany(
948
+ self, size: Optional[int] = None
949
+ ) -> Sequence[Row[Unpack[_Ts]]]:
950
+ """Fetch many rows.
951
+
952
+ When all rows are exhausted, returns an empty sequence.
953
+
954
+ This method is provided for backwards compatibility with
955
+ SQLAlchemy 1.x.x.
956
+
957
+ To fetch rows in groups, use the :meth:`_engine.Result.partitions`
958
+ method.
959
+
960
+ :return: a sequence of :class:`_engine.Row` objects.
961
+
962
+ .. seealso::
963
+
964
+ :meth:`_engine.Result.partitions`
965
+
966
+ """
967
+
968
+ return self._manyrow_getter(self, size)
969
+
970
+ def all(self) -> Sequence[Row[Unpack[_Ts]]]:
971
+ """Return all rows in a sequence.
972
+
973
+ Closes the result set after invocation. Subsequent invocations
974
+ will return an empty sequence.
975
+
976
+ .. versionadded:: 1.4
977
+
978
+ :return: a sequence of :class:`_engine.Row` objects.
979
+
980
+ .. seealso::
981
+
982
+ :ref:`engine_stream_results` - How to stream a large result set
983
+ without loading it completely in python.
984
+
985
+ """
986
+
987
+ return self._allrows()
988
+
989
+ def first(self) -> Optional[Row[Unpack[_Ts]]]:
990
+ """Fetch the first row or ``None`` if no row is present.
991
+
992
+ Closes the result set and discards remaining rows.
993
+
994
+ .. note:: This method returns one **row**, e.g. tuple, by default.
995
+ To return exactly one single scalar value, that is, the first
996
+ column of the first row, use the
997
+ :meth:`_engine.Result.scalar` method,
998
+ or combine :meth:`_engine.Result.scalars` and
999
+ :meth:`_engine.Result.first`.
1000
+
1001
+ Additionally, in contrast to the behavior of the legacy ORM
1002
+ :meth:`_orm.Query.first` method, **no limit is applied** to the
1003
+ SQL query which was invoked to produce this
1004
+ :class:`_engine.Result`;
1005
+ for a DBAPI driver that buffers results in memory before yielding
1006
+ rows, all rows will be sent to the Python process and all but
1007
+ the first row will be discarded.
1008
+
1009
+ .. seealso::
1010
+
1011
+ :ref:`migration_20_unify_select`
1012
+
1013
+ :return: a :class:`_engine.Row` object, or None
1014
+ if no rows remain.
1015
+
1016
+ .. seealso::
1017
+
1018
+ :meth:`_engine.Result.scalar`
1019
+
1020
+ :meth:`_engine.Result.one`
1021
+
1022
+ """
1023
+
1024
+ return self._only_one_row(
1025
+ raise_for_second_row=False, raise_for_none=False, scalar=False
1026
+ )
1027
+
1028
+ def one_or_none(self) -> Optional[Row[Unpack[_Ts]]]:
1029
+ """Return at most one result or raise an exception.
1030
+
1031
+ Returns ``None`` if the result has no rows.
1032
+ Raises :class:`.MultipleResultsFound`
1033
+ if multiple rows are returned.
1034
+
1035
+ .. versionadded:: 1.4
1036
+
1037
+ :return: The first :class:`_engine.Row` or ``None`` if no row
1038
+ is available.
1039
+
1040
+ :raises: :class:`.MultipleResultsFound`
1041
+
1042
+ .. seealso::
1043
+
1044
+ :meth:`_engine.Result.first`
1045
+
1046
+ :meth:`_engine.Result.one`
1047
+
1048
+ """
1049
+ return self._only_one_row(
1050
+ raise_for_second_row=True, raise_for_none=False, scalar=False
1051
+ )
1052
+
1053
+ def scalar_one(self: Result[_T, Unpack[TupleAny]]) -> _T:
1054
+ """Return exactly one scalar result or raise an exception.
1055
+
1056
+ This is equivalent to calling :meth:`_engine.Result.scalars` and
1057
+ then :meth:`_engine.ScalarResult.one`.
1058
+
1059
+ .. seealso::
1060
+
1061
+ :meth:`_engine.ScalarResult.one`
1062
+
1063
+ :meth:`_engine.Result.scalars`
1064
+
1065
+ """
1066
+ return self._only_one_row(
1067
+ raise_for_second_row=True, raise_for_none=True, scalar=True
1068
+ )
1069
+
1070
+ def scalar_one_or_none(self: Result[_T, Unpack[TupleAny]]) -> Optional[_T]:
1071
+ """Return exactly one scalar result or ``None``.
1072
+
1073
+ This is equivalent to calling :meth:`_engine.Result.scalars` and
1074
+ then :meth:`_engine.ScalarResult.one_or_none`.
1075
+
1076
+ .. seealso::
1077
+
1078
+ :meth:`_engine.ScalarResult.one_or_none`
1079
+
1080
+ :meth:`_engine.Result.scalars`
1081
+
1082
+ """
1083
+ return self._only_one_row(
1084
+ raise_for_second_row=True, raise_for_none=False, scalar=True
1085
+ )
1086
+
1087
+ def one(self) -> Row[Unpack[_Ts]]:
1088
+ """Return exactly one row or raise an exception.
1089
+
1090
+ Raises :class:`_exc.NoResultFound` if the result returns no
1091
+ rows, or :class:`_exc.MultipleResultsFound` if multiple rows
1092
+ would be returned.
1093
+
1094
+ .. note:: This method returns one **row**, e.g. tuple, by default.
1095
+ To return exactly one single scalar value, that is, the first
1096
+ column of the first row, use the
1097
+ :meth:`_engine.Result.scalar_one` method, or combine
1098
+ :meth:`_engine.Result.scalars` and
1099
+ :meth:`_engine.Result.one`.
1100
+
1101
+ .. versionadded:: 1.4
1102
+
1103
+ :return: The first :class:`_engine.Row`.
1104
+
1105
+ :raises: :class:`.MultipleResultsFound`, :class:`.NoResultFound`
1106
+
1107
+ .. seealso::
1108
+
1109
+ :meth:`_engine.Result.first`
1110
+
1111
+ :meth:`_engine.Result.one_or_none`
1112
+
1113
+ :meth:`_engine.Result.scalar_one`
1114
+
1115
+ """
1116
+ return self._only_one_row(
1117
+ raise_for_second_row=True, raise_for_none=True, scalar=False
1118
+ )
1119
+
1120
+ # special case to handle mypy issue:
1121
+ # https://github.com/python/mypy/issues/20651
1122
+ @overload
1123
+ def scalar(self: Result[Never, Unpack[TupleAny]]) -> Optional[Any]:
1124
+ pass
1125
+
1126
+ @overload
1127
+ def scalar(self: Result[_T, Unpack[TupleAny]]) -> Optional[_T]:
1128
+ pass
1129
+
1130
+ def scalar(self: Result[_T, Unpack[TupleAny]]) -> Optional[_T]:
1131
+ """Fetch the first column of the first row, and close the result set.
1132
+
1133
+ Returns ``None`` if there are no rows to fetch.
1134
+
1135
+ No validation is performed to test if additional rows remain.
1136
+
1137
+ After calling this method, the object is fully closed,
1138
+ e.g. the :meth:`_engine.CursorResult.close`
1139
+ method will have been called.
1140
+
1141
+ :return: a Python scalar value, or ``None`` if no rows remain.
1142
+
1143
+ """
1144
+ return self._only_one_row(
1145
+ raise_for_second_row=False, raise_for_none=False, scalar=True
1146
+ )
1147
+
1148
+ def freeze(self) -> FrozenResult[Unpack[_Ts]]:
1149
+ """Return a callable object that will produce copies of this
1150
+ :class:`_engine.Result` when invoked.
1151
+
1152
+ The callable object returned is an instance of
1153
+ :class:`_engine.FrozenResult`.
1154
+
1155
+ This is used for result set caching. The method must be called
1156
+ on the result when it has been unconsumed, and calling the method
1157
+ will consume the result fully. When the :class:`_engine.FrozenResult`
1158
+ is retrieved from a cache, it can be called any number of times where
1159
+ it will produce a new :class:`_engine.Result` object each time
1160
+ against its stored set of rows.
1161
+
1162
+ .. seealso::
1163
+
1164
+ :ref:`do_orm_execute_re_executing` - example usage within the
1165
+ ORM to implement a result-set cache.
1166
+
1167
+ """
1168
+
1169
+ return FrozenResult(self)
1170
+
1171
+ def merge(
1172
+ self, *others: Result[Unpack[TupleAny]]
1173
+ ) -> MergedResult[Unpack[TupleAny]]:
1174
+ """Merge this :class:`_engine.Result` with other compatible result
1175
+ objects.
1176
+
1177
+ The object returned is an instance of :class:`_engine.MergedResult`,
1178
+ which will be composed of iterators from the given result
1179
+ objects.
1180
+
1181
+ The new result will use the metadata from this result object.
1182
+ The subsequent result objects must be against an identical
1183
+ set of result / cursor metadata, otherwise the behavior is
1184
+ undefined.
1185
+
1186
+ """
1187
+ return MergedResult(self._metadata, (self,) + others)
1188
+
1189
+
1190
+ class FilterResult(ResultInternal[_R]):
1191
+ """A wrapper for a :class:`_engine.Result` that returns objects other than
1192
+ :class:`_engine.Row` objects, such as dictionaries or scalar objects.
1193
+
1194
+ :class:`_engine.FilterResult` is the common base for additional result
1195
+ APIs including :class:`_engine.MappingResult`,
1196
+ :class:`_engine.ScalarResult` and :class:`_engine.AsyncResult`.
1197
+
1198
+ """
1199
+
1200
+ __slots__ = (
1201
+ "_real_result",
1202
+ "_post_creational_filter",
1203
+ "_metadata",
1204
+ "_unique_filter_state",
1205
+ "__dict__",
1206
+ )
1207
+
1208
+ _post_creational_filter: Optional[Callable[[Any], Any]]
1209
+
1210
+ _real_result: Result[Unpack[TupleAny]]
1211
+
1212
+ def __enter__(self) -> Self:
1213
+ return self
1214
+
1215
+ def __exit__(self, type_: Any, value: Any, traceback: Any) -> None:
1216
+ self._real_result.__exit__(type_, value, traceback)
1217
+
1218
+ @_generative
1219
+ def yield_per(self, num: int) -> Self:
1220
+ """Configure the row-fetching strategy to fetch ``num`` rows at a time.
1221
+
1222
+ The :meth:`_engine.FilterResult.yield_per` method is a pass through
1223
+ to the :meth:`_engine.Result.yield_per` method. See that method's
1224
+ documentation for usage notes.
1225
+
1226
+ .. versionadded:: 1.4.40 - added :meth:`_engine.FilterResult.yield_per`
1227
+ so that the method is available on all result set implementations
1228
+
1229
+ .. seealso::
1230
+
1231
+ :ref:`engine_stream_results` - describes Core behavior for
1232
+ :meth:`_engine.Result.yield_per`
1233
+
1234
+ :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel`
1235
+
1236
+ """
1237
+ self._real_result = self._real_result.yield_per(num)
1238
+ return self
1239
+
1240
+ def _soft_close(self, hard: bool = False) -> None:
1241
+ self._real_result._soft_close(hard=hard)
1242
+
1243
+ @property
1244
+ def _soft_closed(self) -> bool:
1245
+ return self._real_result._soft_closed
1246
+
1247
+ @property
1248
+ def closed(self) -> bool:
1249
+ """Return ``True`` if this :class:`_engine.Result` being
1250
+ proxied by this :class:`_engine.FilterResult` was
1251
+ **hard closed** by explicitly calling the :meth:`_engine.Result.close`
1252
+ method.
1253
+
1254
+ This is a direct proxy for the :attr:`_engine.Result.closed` attribute;
1255
+ see that attribute for details.
1256
+
1257
+ """
1258
+ return self._real_result.closed
1259
+
1260
+ def close(self) -> None:
1261
+ """Close this :class:`_engine.FilterResult`.
1262
+
1263
+ .. versionadded:: 1.4.43
1264
+
1265
+ """
1266
+ self._real_result.close()
1267
+
1268
+ @property
1269
+ def _attributes(self) -> Dict[Any, Any]:
1270
+ return self._real_result._attributes
1271
+
1272
+ def _fetchiter_impl(
1273
+ self,
1274
+ ) -> Iterator[_InterimRowType[Row[Unpack[TupleAny]]]]:
1275
+ return self._real_result._fetchiter_impl()
1276
+
1277
+ def _fetchone_impl(
1278
+ self, hard_close: bool = False
1279
+ ) -> Optional[_InterimRowType[Row[Unpack[TupleAny]]]]:
1280
+ return self._real_result._fetchone_impl(hard_close=hard_close)
1281
+
1282
+ def _fetchall_impl(
1283
+ self,
1284
+ ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]:
1285
+ return self._real_result._fetchall_impl()
1286
+
1287
+ def _fetchmany_impl(
1288
+ self, size: Optional[int] = None
1289
+ ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]:
1290
+ return self._real_result._fetchmany_impl(size=size)
1291
+
1292
+
1293
+ class ScalarResult(FilterResult[_R]):
1294
+ """A wrapper for a :class:`_engine.Result` that returns scalar values
1295
+ rather than :class:`_row.Row` values.
1296
+
1297
+ The :class:`_engine.ScalarResult` object is acquired by calling the
1298
+ :meth:`_engine.Result.scalars` method.
1299
+
1300
+ A special limitation of :class:`_engine.ScalarResult` is that it has
1301
+ no ``fetchone()`` method; since the semantics of ``fetchone()`` are that
1302
+ the ``None`` value indicates no more results, this is not compatible
1303
+ with :class:`_engine.ScalarResult` since there is no way to distinguish
1304
+ between ``None`` as a row value versus ``None`` as an indicator. Use
1305
+ ``next(result)`` to receive values individually.
1306
+
1307
+ """
1308
+
1309
+ __slots__ = ()
1310
+
1311
+ _generate_rows = False
1312
+
1313
+ _post_creational_filter: Optional[Callable[[Any], Any]]
1314
+
1315
+ def __init__(
1316
+ self, real_result: Result[Unpack[TupleAny]], index: _KeyIndexType
1317
+ ):
1318
+ self._real_result = real_result
1319
+
1320
+ if real_result._source_supports_scalars:
1321
+ self._metadata = real_result._metadata
1322
+ self._post_creational_filter = None
1323
+ else:
1324
+ self._metadata = real_result._metadata._reduce([index])
1325
+ self._post_creational_filter = operator.itemgetter(0)
1326
+
1327
+ self._unique_filter_state = real_result._unique_filter_state
1328
+
1329
+ def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self:
1330
+ """Apply unique filtering to the objects returned by this
1331
+ :class:`_engine.ScalarResult`.
1332
+
1333
+ See :meth:`_engine.Result.unique` for usage details.
1334
+
1335
+ """
1336
+ self._unique_filter_state = (set(), strategy)
1337
+ return self
1338
+
1339
+ def partitions(self, size: Optional[int] = None) -> Iterator[Sequence[_R]]:
1340
+ """Iterate through sub-lists of elements of the size given.
1341
+
1342
+ Equivalent to :meth:`_engine.Result.partitions` except that
1343
+ scalar values, rather than :class:`_engine.Row` objects,
1344
+ are returned.
1345
+
1346
+ """
1347
+
1348
+ getter = self._manyrow_getter
1349
+
1350
+ while True:
1351
+ partition = getter(self, size)
1352
+ if partition:
1353
+ yield partition
1354
+ else:
1355
+ break
1356
+
1357
+ def fetchall(self) -> Sequence[_R]:
1358
+ """A synonym for the :meth:`_engine.ScalarResult.all` method."""
1359
+
1360
+ return self._allrows()
1361
+
1362
+ def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]:
1363
+ """Fetch many objects.
1364
+
1365
+ Equivalent to :meth:`_engine.Result.fetchmany` except that
1366
+ scalar values, rather than :class:`_engine.Row` objects,
1367
+ are returned.
1368
+
1369
+ """
1370
+ return self._manyrow_getter(self, size)
1371
+
1372
+ def all(self) -> Sequence[_R]:
1373
+ """Return all scalar values in a sequence.
1374
+
1375
+ Equivalent to :meth:`_engine.Result.all` except that
1376
+ scalar values, rather than :class:`_engine.Row` objects,
1377
+ are returned.
1378
+
1379
+ """
1380
+ return self._allrows()
1381
+
1382
+ def __iter__(self) -> Iterator[_R]:
1383
+ return self._iter_impl()
1384
+
1385
+ def __next__(self) -> _R:
1386
+ return self._next_impl()
1387
+
1388
+ def first(self) -> Optional[_R]:
1389
+ """Fetch the first object or ``None`` if no object is present.
1390
+
1391
+ Equivalent to :meth:`_engine.Result.first` except that
1392
+ scalar values, rather than :class:`_engine.Row` objects,
1393
+ are returned.
1394
+
1395
+
1396
+ """
1397
+ return self._only_one_row(
1398
+ raise_for_second_row=False, raise_for_none=False, scalar=False
1399
+ )
1400
+
1401
+ def one_or_none(self) -> Optional[_R]:
1402
+ """Return at most one object or raise an exception.
1403
+
1404
+ Equivalent to :meth:`_engine.Result.one_or_none` except that
1405
+ scalar values, rather than :class:`_engine.Row` objects,
1406
+ are returned.
1407
+
1408
+ """
1409
+ return self._only_one_row(
1410
+ raise_for_second_row=True, raise_for_none=False, scalar=False
1411
+ )
1412
+
1413
+ def one(self) -> _R:
1414
+ """Return exactly one object or raise an exception.
1415
+
1416
+ Equivalent to :meth:`_engine.Result.one` except that
1417
+ scalar values, rather than :class:`_engine.Row` objects,
1418
+ are returned.
1419
+
1420
+ """
1421
+ return self._only_one_row(
1422
+ raise_for_second_row=True, raise_for_none=True, scalar=False
1423
+ )
1424
+
1425
+
1426
+ class TupleResult(FilterResult[_R], util.TypingOnly):
1427
+ """A :class:`_engine.Result` that's typed as returning plain
1428
+ Python tuples instead of rows.
1429
+
1430
+ Since :class:`_engine.Row` acts like a tuple in every way already,
1431
+ this class is a typing only class, regular :class:`_engine.Result` is
1432
+ still used at runtime.
1433
+
1434
+ """
1435
+
1436
+ __slots__ = ()
1437
+
1438
+ if TYPE_CHECKING:
1439
+
1440
+ def partitions(
1441
+ self, size: Optional[int] = None
1442
+ ) -> Iterator[Sequence[_R]]:
1443
+ """Iterate through sub-lists of elements of the size given.
1444
+
1445
+ Equivalent to :meth:`_engine.Result.partitions` except that
1446
+ tuple values, rather than :class:`_engine.Row` objects,
1447
+ are returned.
1448
+
1449
+ """
1450
+ ...
1451
+
1452
+ def fetchone(self) -> Optional[_R]:
1453
+ """Fetch one tuple.
1454
+
1455
+ Equivalent to :meth:`_engine.Result.fetchone` except that
1456
+ tuple values, rather than :class:`_engine.Row`
1457
+ objects, are returned.
1458
+
1459
+ """
1460
+ ...
1461
+
1462
+ def fetchall(self) -> Sequence[_R]:
1463
+ """A synonym for the :meth:`_engine.ScalarResult.all` method."""
1464
+ ...
1465
+
1466
+ def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]:
1467
+ """Fetch many objects.
1468
+
1469
+ Equivalent to :meth:`_engine.Result.fetchmany` except that
1470
+ tuple values, rather than :class:`_engine.Row` objects,
1471
+ are returned.
1472
+
1473
+ """
1474
+ ...
1475
+
1476
+ def all(self) -> Sequence[_R]: # noqa: A001
1477
+ """Return all scalar values in a sequence.
1478
+
1479
+ Equivalent to :meth:`_engine.Result.all` except that
1480
+ tuple values, rather than :class:`_engine.Row` objects,
1481
+ are returned.
1482
+
1483
+ """
1484
+ ...
1485
+
1486
+ def __iter__(self) -> Iterator[_R]: ...
1487
+
1488
+ def __next__(self) -> _R: ...
1489
+
1490
+ def first(self) -> Optional[_R]:
1491
+ """Fetch the first object or ``None`` if no object is present.
1492
+
1493
+ Equivalent to :meth:`_engine.Result.first` except that
1494
+ tuple values, rather than :class:`_engine.Row` objects,
1495
+ are returned.
1496
+
1497
+
1498
+ """
1499
+ ...
1500
+
1501
+ def one_or_none(self) -> Optional[_R]:
1502
+ """Return at most one object or raise an exception.
1503
+
1504
+ Equivalent to :meth:`_engine.Result.one_or_none` except that
1505
+ tuple values, rather than :class:`_engine.Row` objects,
1506
+ are returned.
1507
+
1508
+ """
1509
+ ...
1510
+
1511
+ def one(self) -> _R:
1512
+ """Return exactly one object or raise an exception.
1513
+
1514
+ Equivalent to :meth:`_engine.Result.one` except that
1515
+ tuple values, rather than :class:`_engine.Row` objects,
1516
+ are returned.
1517
+
1518
+ """
1519
+ ...
1520
+
1521
+ @overload
1522
+ def scalar_one(self: TupleResult[Tuple[_T]]) -> _T: ...
1523
+
1524
+ @overload
1525
+ def scalar_one(self) -> Any: ...
1526
+
1527
+ def scalar_one(self) -> Any:
1528
+ """Return exactly one scalar result or raise an exception.
1529
+
1530
+ This is equivalent to calling :meth:`_engine.Result.scalars`
1531
+ and then :meth:`_engine.ScalarResult.one`.
1532
+
1533
+ .. seealso::
1534
+
1535
+ :meth:`_engine.ScalarResult.one`
1536
+
1537
+ :meth:`_engine.Result.scalars`
1538
+
1539
+ """
1540
+ ...
1541
+
1542
+ @overload
1543
+ def scalar_one_or_none(
1544
+ self: TupleResult[Tuple[_T]],
1545
+ ) -> Optional[_T]: ...
1546
+
1547
+ @overload
1548
+ def scalar_one_or_none(self) -> Optional[Any]: ...
1549
+
1550
+ def scalar_one_or_none(self) -> Optional[Any]:
1551
+ """Return exactly one or no scalar result.
1552
+
1553
+ This is equivalent to calling :meth:`_engine.Result.scalars`
1554
+ and then :meth:`_engine.ScalarResult.one_or_none`.
1555
+
1556
+ .. seealso::
1557
+
1558
+ :meth:`_engine.ScalarResult.one_or_none`
1559
+
1560
+ :meth:`_engine.Result.scalars`
1561
+
1562
+ """
1563
+ ...
1564
+
1565
+ @overload
1566
+ def scalar(self: TupleResult[Tuple[_T]]) -> Optional[_T]: ...
1567
+
1568
+ @overload
1569
+ def scalar(self) -> Any: ...
1570
+
1571
+ def scalar(self) -> Any:
1572
+ """Fetch the first column of the first row, and close the result
1573
+ set.
1574
+
1575
+ Returns ``None`` if there are no rows to fetch.
1576
+
1577
+ No validation is performed to test if additional rows remain.
1578
+
1579
+ After calling this method, the object is fully closed,
1580
+ e.g. the :meth:`_engine.CursorResult.close`
1581
+ method will have been called.
1582
+
1583
+ :return: a Python scalar value , or ``None`` if no rows remain.
1584
+
1585
+ """
1586
+ ...
1587
+
1588
+
1589
+ class MappingResult(_WithKeys, FilterResult[RowMapping]):
1590
+ """A wrapper for a :class:`_engine.Result` that returns dictionary values
1591
+ rather than :class:`_engine.Row` values.
1592
+
1593
+ The :class:`_engine.MappingResult` object is acquired by calling the
1594
+ :meth:`_engine.Result.mappings` method.
1595
+
1596
+ """
1597
+
1598
+ __slots__ = ()
1599
+
1600
+ _generate_rows = True
1601
+
1602
+ _post_creational_filter = operator.attrgetter("_mapping")
1603
+
1604
+ def __init__(self, result: Result[Unpack[TupleAny]]):
1605
+ self._real_result = result
1606
+ self._unique_filter_state = result._unique_filter_state
1607
+ self._metadata = result._metadata
1608
+ if result._source_supports_scalars:
1609
+ self._metadata = self._metadata._reduce([0])
1610
+
1611
+ def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self:
1612
+ """Apply unique filtering to the objects returned by this
1613
+ :class:`_engine.MappingResult`.
1614
+
1615
+ See :meth:`_engine.Result.unique` for usage details.
1616
+
1617
+ """
1618
+ self._unique_filter_state = (set(), strategy)
1619
+ return self
1620
+
1621
+ def columns(self, *col_expressions: _KeyIndexType) -> Self:
1622
+ """Establish the columns that should be returned in each row."""
1623
+ return self._column_slices(col_expressions)
1624
+
1625
+ def partitions(
1626
+ self, size: Optional[int] = None
1627
+ ) -> Iterator[Sequence[RowMapping]]:
1628
+ """Iterate through sub-lists of elements of the size given.
1629
+
1630
+ Equivalent to :meth:`_engine.Result.partitions` except that
1631
+ :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
1632
+ objects, are returned.
1633
+
1634
+ """
1635
+
1636
+ getter = self._manyrow_getter
1637
+
1638
+ while True:
1639
+ partition = getter(self, size)
1640
+ if partition:
1641
+ yield partition
1642
+ else:
1643
+ break
1644
+
1645
+ def fetchall(self) -> Sequence[RowMapping]:
1646
+ """A synonym for the :meth:`_engine.MappingResult.all` method."""
1647
+
1648
+ return self._allrows()
1649
+
1650
+ def fetchone(self) -> Optional[RowMapping]:
1651
+ """Fetch one object.
1652
+
1653
+ Equivalent to :meth:`_engine.Result.fetchone` except that
1654
+ :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
1655
+ objects, are returned.
1656
+
1657
+ """
1658
+
1659
+ row = self._onerow_getter(self)
1660
+ if row is _NO_ROW:
1661
+ return None
1662
+ else:
1663
+ return row
1664
+
1665
+ def fetchmany(self, size: Optional[int] = None) -> Sequence[RowMapping]:
1666
+ """Fetch many objects.
1667
+
1668
+ Equivalent to :meth:`_engine.Result.fetchmany` except that
1669
+ :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
1670
+ objects, are returned.
1671
+
1672
+ """
1673
+
1674
+ return self._manyrow_getter(self, size)
1675
+
1676
+ def all(self) -> Sequence[RowMapping]:
1677
+ """Return all scalar values in a sequence.
1678
+
1679
+ Equivalent to :meth:`_engine.Result.all` except that
1680
+ :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
1681
+ objects, are returned.
1682
+
1683
+ """
1684
+
1685
+ return self._allrows()
1686
+
1687
+ def __iter__(self) -> Iterator[RowMapping]:
1688
+ return self._iter_impl()
1689
+
1690
+ def __next__(self) -> RowMapping:
1691
+ return self._next_impl()
1692
+
1693
+ def first(self) -> Optional[RowMapping]:
1694
+ """Fetch the first object or ``None`` if no object is present.
1695
+
1696
+ Equivalent to :meth:`_engine.Result.first` except that
1697
+ :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
1698
+ objects, are returned.
1699
+
1700
+
1701
+ """
1702
+ return self._only_one_row(
1703
+ raise_for_second_row=False, raise_for_none=False, scalar=False
1704
+ )
1705
+
1706
+ def one_or_none(self) -> Optional[RowMapping]:
1707
+ """Return at most one object or raise an exception.
1708
+
1709
+ Equivalent to :meth:`_engine.Result.one_or_none` except that
1710
+ :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
1711
+ objects, are returned.
1712
+
1713
+ """
1714
+ return self._only_one_row(
1715
+ raise_for_second_row=True, raise_for_none=False, scalar=False
1716
+ )
1717
+
1718
+ def one(self) -> RowMapping:
1719
+ """Return exactly one object or raise an exception.
1720
+
1721
+ Equivalent to :meth:`_engine.Result.one` except that
1722
+ :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
1723
+ objects, are returned.
1724
+
1725
+ """
1726
+ return self._only_one_row(
1727
+ raise_for_second_row=True, raise_for_none=True, scalar=False
1728
+ )
1729
+
1730
+
1731
+ class FrozenResult(Generic[Unpack[_Ts]]):
1732
+ """Represents a :class:`_engine.Result` object in a "frozen" state suitable
1733
+ for caching.
1734
+
1735
+ The :class:`_engine.FrozenResult` object is returned from the
1736
+ :meth:`_engine.Result.freeze` method of any :class:`_engine.Result`
1737
+ object.
1738
+
1739
+ A new iterable :class:`_engine.Result` object is generated from a fixed
1740
+ set of data each time the :class:`_engine.FrozenResult` is invoked as
1741
+ a callable::
1742
+
1743
+
1744
+ result = connection.execute(query)
1745
+
1746
+ frozen = result.freeze()
1747
+
1748
+ unfrozen_result_one = frozen()
1749
+
1750
+ for row in unfrozen_result_one:
1751
+ print(row)
1752
+
1753
+ unfrozen_result_two = frozen()
1754
+ rows = unfrozen_result_two.all()
1755
+
1756
+ # ... etc
1757
+
1758
+ .. versionadded:: 1.4
1759
+
1760
+ .. seealso::
1761
+
1762
+ :ref:`do_orm_execute_re_executing` - example usage within the
1763
+ ORM to implement a result-set cache.
1764
+
1765
+ :func:`_orm.loading.merge_frozen_result` - ORM function to merge
1766
+ a frozen result back into a :class:`_orm.Session`.
1767
+
1768
+ """
1769
+
1770
+ data: Sequence[Any]
1771
+
1772
+ def __init__(self, result: Result[Unpack[_Ts]]):
1773
+ self.metadata = result._metadata._for_freeze()
1774
+ self._source_supports_scalars = result._source_supports_scalars
1775
+ self._attributes = result._attributes
1776
+
1777
+ if self._source_supports_scalars:
1778
+ self.data = list(result._raw_row_iterator())
1779
+ else:
1780
+ self.data = result.fetchall()
1781
+
1782
+ def _rewrite_rows(self) -> Sequence[Sequence[Any]]:
1783
+ # used only by the orm fn merge_frozen_result
1784
+ if self._source_supports_scalars:
1785
+ return [[elem] for elem in self.data]
1786
+ else:
1787
+ return [list(row) for row in self.data]
1788
+
1789
+ def with_new_rows(
1790
+ self, tuple_data: Sequence[Row[Unpack[_Ts]]]
1791
+ ) -> FrozenResult[Unpack[_Ts]]:
1792
+ fr = FrozenResult.__new__(FrozenResult)
1793
+ fr.metadata = self.metadata
1794
+ fr._attributes = self._attributes
1795
+ fr._source_supports_scalars = self._source_supports_scalars
1796
+
1797
+ if self._source_supports_scalars:
1798
+ fr.data = [d[0] for d in tuple_data] # type: ignore[misc]
1799
+ else:
1800
+ fr.data = tuple_data
1801
+ return fr
1802
+
1803
+ def __call__(self) -> Result[Unpack[_Ts]]:
1804
+ result: IteratorResult[Unpack[_Ts]] = IteratorResult(
1805
+ self.metadata, iter(self.data)
1806
+ )
1807
+ result._attributes = self._attributes
1808
+ result._source_supports_scalars = self._source_supports_scalars
1809
+ return result
1810
+
1811
+
1812
+ class IteratorResult(Result[Unpack[_Ts]]):
1813
+ """A :class:`_engine.Result` that gets data from a Python iterator of
1814
+ :class:`_engine.Row` objects or similar row-like data.
1815
+
1816
+ .. versionadded:: 1.4
1817
+
1818
+ """
1819
+
1820
+ _hard_closed = False
1821
+ _soft_closed = False
1822
+
1823
+ def __init__(
1824
+ self,
1825
+ cursor_metadata: ResultMetaData,
1826
+ iterator: Iterator[_InterimSupportsScalarsRowType],
1827
+ raw: Optional[Result[Any]] = None,
1828
+ _source_supports_scalars: bool = False,
1829
+ context: Optional[Any] = None,
1830
+ ):
1831
+ self._metadata = cursor_metadata
1832
+ self.iterator = iterator
1833
+ self.raw = raw
1834
+ self._source_supports_scalars = _source_supports_scalars
1835
+ self.context = context
1836
+
1837
+ @property
1838
+ def closed(self) -> bool:
1839
+ """Return ``True`` if this :class:`_engine.IteratorResult` was
1840
+ **hard closed** by explicitly calling the :meth:`_engine.Result.close`
1841
+ method.
1842
+
1843
+ The attribute is **not** True if the :class:`_engine.Result` was only
1844
+ **soft closed**; a "soft close" is the style of close that takes place
1845
+ for example when the :class:`.CursorResult` is returned for a DML
1846
+ only statement without RETURNING, or when all result rows are fetched.
1847
+
1848
+ .. seealso::
1849
+
1850
+ :attr:`.CursorResult.returns_rows` - attribute specific to
1851
+ :class:`.CursorResult` which indicates if the result is one that
1852
+ may return zero or more rows
1853
+
1854
+ """
1855
+ return self._hard_closed
1856
+
1857
+ def _soft_close(self, hard: bool = False, **kw: Any) -> None:
1858
+ if hard:
1859
+ self._hard_closed = True
1860
+ if self.raw is not None:
1861
+ self.raw._soft_close(hard=hard, **kw)
1862
+ self.iterator = iter([])
1863
+ self._reset_memoizations()
1864
+ self._soft_closed = True
1865
+
1866
+ def _raise_hard_closed(self) -> NoReturn:
1867
+ raise exc.ResourceClosedError("This result object is closed.")
1868
+
1869
+ def _raw_row_iterator(self) -> Iterator[_RowData]:
1870
+ return self.iterator
1871
+
1872
+ def _fetchiter_impl(self) -> Iterator[_InterimSupportsScalarsRowType]:
1873
+ if self._hard_closed:
1874
+ self._raise_hard_closed()
1875
+ return self.iterator
1876
+
1877
+ def _fetchone_impl(
1878
+ self, hard_close: bool = False
1879
+ ) -> Optional[_InterimRowType[Row[Unpack[TupleAny]]]]:
1880
+ if self._hard_closed:
1881
+ self._raise_hard_closed()
1882
+
1883
+ row = next(self.iterator, _NO_ROW)
1884
+ if row is _NO_ROW:
1885
+ self._soft_close(hard=hard_close)
1886
+ return None
1887
+ else:
1888
+ return row
1889
+
1890
+ def _fetchall_impl(
1891
+ self,
1892
+ ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]:
1893
+ if self._hard_closed:
1894
+ self._raise_hard_closed()
1895
+ try:
1896
+ return list(self.iterator)
1897
+ finally:
1898
+ self._soft_close()
1899
+
1900
+ def _fetchmany_impl(
1901
+ self, size: Optional[int] = None
1902
+ ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]:
1903
+ if self._hard_closed:
1904
+ self._raise_hard_closed()
1905
+
1906
+ return list(itertools.islice(self.iterator, 0, size))
1907
+
1908
+
1909
+ def null_result() -> IteratorResult[Any]:
1910
+ return IteratorResult(SimpleResultMetaData([]), iter([]))
1911
+
1912
+
1913
+ class ChunkedIteratorResult(IteratorResult[Unpack[_Ts]]):
1914
+ """An :class:`_engine.IteratorResult` that works from an
1915
+ iterator-producing callable.
1916
+
1917
+ The given ``chunks`` argument is a function that is given a number of rows
1918
+ to return in each chunk, or ``None`` for all rows. The function should
1919
+ then return an un-consumed iterator of lists, each list of the requested
1920
+ size.
1921
+
1922
+ The function can be called at any time again, in which case it should
1923
+ continue from the same result set but adjust the chunk size as given.
1924
+
1925
+ .. versionadded:: 1.4
1926
+
1927
+ """
1928
+
1929
+ def __init__(
1930
+ self,
1931
+ cursor_metadata: ResultMetaData,
1932
+ chunks: Callable[
1933
+ [Optional[int]], Iterator[Sequence[_InterimRowType[_R]]]
1934
+ ],
1935
+ source_supports_scalars: bool = False,
1936
+ raw: Optional[Result[Any]] = None,
1937
+ dynamic_yield_per: bool = False,
1938
+ context: Optional[Any] = None,
1939
+ ):
1940
+ self._metadata = cursor_metadata
1941
+ self.chunks = chunks
1942
+ self._source_supports_scalars = source_supports_scalars
1943
+ self.raw = raw
1944
+ self.iterator = itertools.chain.from_iterable(self.chunks(None))
1945
+ self.dynamic_yield_per = dynamic_yield_per
1946
+ self.context = context
1947
+
1948
+ @_generative
1949
+ def yield_per(self, num: int) -> Self:
1950
+ # TODO: this throws away the iterator which may be holding
1951
+ # onto a chunk. the yield_per cannot be changed once any
1952
+ # rows have been fetched. either find a way to enforce this,
1953
+ # or we can't use itertools.chain and will instead have to
1954
+ # keep track.
1955
+
1956
+ self._yield_per = num
1957
+ self.iterator = itertools.chain.from_iterable(self.chunks(num))
1958
+ return self
1959
+
1960
+ def _soft_close(self, hard: bool = False, **kw: Any) -> None:
1961
+ super()._soft_close(hard=hard, **kw)
1962
+ self.chunks = lambda size: [] # type: ignore[assignment, return-value]
1963
+
1964
+ def _fetchmany_impl(
1965
+ self, size: Optional[int] = None
1966
+ ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]:
1967
+ if self.dynamic_yield_per:
1968
+ self.iterator = itertools.chain.from_iterable(self.chunks(size))
1969
+ return super()._fetchmany_impl(size=size)
1970
+
1971
+
1972
+ class MergedResult(IteratorResult[Unpack[_Ts]]):
1973
+ """A :class:`_engine.Result` that is merged from any number of
1974
+ :class:`_engine.Result` objects.
1975
+
1976
+ Returned by the :meth:`_engine.Result.merge` method.
1977
+
1978
+ .. versionadded:: 1.4
1979
+
1980
+ """
1981
+
1982
+ closed = False
1983
+ rowcount: Optional[int]
1984
+
1985
+ def __init__(
1986
+ self,
1987
+ cursor_metadata: ResultMetaData,
1988
+ results: Sequence[Result[Unpack[_Ts]]],
1989
+ ):
1990
+ self._results = results
1991
+ super().__init__(
1992
+ cursor_metadata,
1993
+ itertools.chain.from_iterable(
1994
+ r._raw_row_iterator() for r in results
1995
+ ),
1996
+ )
1997
+
1998
+ self._unique_filter_state = results[0]._unique_filter_state
1999
+ self._yield_per = results[0]._yield_per
2000
+
2001
+ # going to try something w/ this in next rev
2002
+ self._source_supports_scalars = results[0]._source_supports_scalars
2003
+
2004
+ self._attributes = self._attributes.merge_with(
2005
+ *[r._attributes for r in results]
2006
+ )
2007
+
2008
+ def _soft_close(self, hard: bool = False, **kw: Any) -> None:
2009
+ for r in self._results:
2010
+ r._soft_close(hard=hard, **kw)
2011
+ if hard:
2012
+ self.closed = True