Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/row.py: 65%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

145 statements  

1# engine/row.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 row constructs including :class:`.Row`.""" 

9 

10from __future__ import annotations 

11 

12from abc import ABC 

13import collections.abc as collections_abc 

14import operator 

15import typing 

16from typing import Any 

17from typing import Callable 

18from typing import Dict 

19from typing import Generic 

20from typing import Iterator 

21from typing import List 

22from typing import Mapping 

23from typing import NoReturn 

24from typing import Optional 

25from typing import overload 

26from typing import Sequence 

27from typing import Tuple 

28from typing import TYPE_CHECKING 

29from typing import TypeVar 

30from typing import Union 

31 

32from ..sql import util as sql_util 

33from ..util import deprecated 

34from ..util._has_cy import HAS_CYEXTENSION 

35 

36if TYPE_CHECKING or not HAS_CYEXTENSION: 

37 from ._py_row import BaseRow as BaseRow 

38else: 

39 from sqlalchemy.cyextension.resultproxy import BaseRow as BaseRow 

40 

41if TYPE_CHECKING: 

42 from .result import _KeyType 

43 from .result import _ProcessorsType 

44 from .result import RMKeyView 

45 

46_T = TypeVar("_T", bound=Any) 

47_TP = TypeVar("_TP", bound=Tuple[Any, ...]) 

48 

49 

50class Row(BaseRow, Sequence[Any], Generic[_TP]): 

51 """Represent a single result row. 

52 

53 The :class:`.Row` object represents a row of a database result. It is 

54 typically associated in the 1.x series of SQLAlchemy with the 

55 :class:`_engine.CursorResult` object, however is also used by the ORM for 

56 tuple-like results as of SQLAlchemy 1.4. 

57 

58 The :class:`.Row` object seeks to act as much like a Python named 

59 tuple as possible. For mapping (i.e. dictionary) behavior on a row, 

60 such as testing for containment of keys, refer to the :attr:`.Row._mapping` 

61 attribute. 

62 

63 .. seealso:: 

64 

65 :ref:`tutorial_selecting_data` - includes examples of selecting 

66 rows from SELECT statements. 

67 

68 .. versionchanged:: 1.4 

69 

70 Renamed ``RowProxy`` to :class:`.Row`. :class:`.Row` is no longer a 

71 "proxy" object in that it contains the final form of data within it, 

72 and now acts mostly like a named tuple. Mapping-like functionality is 

73 moved to the :attr:`.Row._mapping` attribute. See 

74 :ref:`change_4710_core` for background on this change. 

75 

76 """ 

77 

78 __slots__ = () 

79 

80 def __setattr__(self, name: str, value: Any) -> NoReturn: 

81 raise AttributeError("can't set attribute") 

82 

83 def __delattr__(self, name: str) -> NoReturn: 

84 raise AttributeError("can't delete attribute") 

85 

86 def _tuple(self) -> _TP: 

87 """Return a 'tuple' form of this :class:`.Row`. 

88 

89 At runtime, this method returns "self"; the :class:`.Row` object is 

90 already a named tuple. However, at the typing level, if this 

91 :class:`.Row` is typed, the "tuple" return type will be a :pep:`484` 

92 ``Tuple`` datatype that contains typing information about individual 

93 elements, supporting typed unpacking and attribute access. 

94 

95 .. versionadded:: 2.0.19 - The :meth:`.Row._tuple` method supersedes 

96 the previous :meth:`.Row.tuple` method, which is now underscored 

97 to avoid name conflicts with column names in the same way as other 

98 named-tuple methods on :class:`.Row`. 

99 

100 .. seealso:: 

101 

102 :attr:`.Row._t` - shorthand attribute notation 

103 

104 :meth:`.Result.tuples` 

105 

106 

107 """ 

108 return self # type: ignore 

109 

110 @deprecated( 

111 "2.0.19", 

112 "The :meth:`.Row.tuple` method is deprecated in favor of " 

113 ":meth:`.Row._tuple`; all :class:`.Row` " 

114 "methods and library-level attributes are intended to be underscored " 

115 "to avoid name conflicts. Please use :meth:`Row._tuple`.", 

116 ) 

117 def tuple(self) -> _TP: 

118 """Return a 'tuple' form of this :class:`.Row`. 

119 

120 .. versionadded:: 2.0 

121 

122 """ 

123 return self._tuple() 

124 

125 @property 

126 def _t(self) -> _TP: 

127 """A synonym for :meth:`.Row._tuple`. 

128 

129 .. versionadded:: 2.0.19 - The :attr:`.Row._t` attribute supersedes 

130 the previous :attr:`.Row.t` attribute, which is now underscored 

131 to avoid name conflicts with column names in the same way as other 

132 named-tuple methods on :class:`.Row`. 

133 

134 .. seealso:: 

135 

136 :attr:`.Result.t` 

137 """ 

138 return self # type: ignore 

139 

140 @property 

141 @deprecated( 

142 "2.0.19", 

143 "The :attr:`.Row.t` attribute is deprecated in favor of " 

144 ":attr:`.Row._t`; all :class:`.Row` " 

145 "methods and library-level attributes are intended to be underscored " 

146 "to avoid name conflicts. Please use :attr:`Row._t`.", 

147 ) 

148 def t(self) -> _TP: 

149 """A synonym for :meth:`.Row._tuple`. 

150 

151 .. versionadded:: 2.0 

152 

153 """ 

154 return self._t 

155 

156 @property 

157 def _mapping(self) -> RowMapping: 

158 """Return a :class:`.RowMapping` for this :class:`.Row`. 

159 

160 This object provides a consistent Python mapping (i.e. dictionary) 

161 interface for the data contained within the row. The :class:`.Row` 

162 by itself behaves like a named tuple. 

163 

164 .. seealso:: 

165 

166 :attr:`.Row._fields` 

167 

168 .. versionadded:: 1.4 

169 

170 """ 

171 return RowMapping(self._parent, None, self._key_to_index, self._data) 

172 

173 def _filter_on_values( 

174 self, processor: Optional[_ProcessorsType] 

175 ) -> Row[Any]: 

176 return Row(self._parent, processor, self._key_to_index, self._data) 

177 

178 if not TYPE_CHECKING: 

179 

180 def _special_name_accessor(name: str) -> Any: 

181 """Handle ambiguous names such as "count" and "index" """ 

182 

183 @property 

184 def go(self: Row) -> Any: 

185 if self._parent._has_key(name): 

186 return self.__getattr__(name) 

187 else: 

188 

189 def meth(*arg: Any, **kw: Any) -> Any: 

190 return getattr(collections_abc.Sequence, name)( 

191 self, *arg, **kw 

192 ) 

193 

194 return meth 

195 

196 return go 

197 

198 count = _special_name_accessor("count") 

199 index = _special_name_accessor("index") 

200 

201 def __contains__(self, key: Any) -> bool: 

202 return key in self._data 

203 

204 def _op(self, other: Any, op: Callable[[Any, Any], bool]) -> bool: 

205 return ( 

206 op(self._to_tuple_instance(), other._to_tuple_instance()) 

207 if isinstance(other, Row) 

208 else op(self._to_tuple_instance(), other) 

209 ) 

210 

211 __hash__ = BaseRow.__hash__ 

212 

213 if TYPE_CHECKING: 

214 

215 @overload 

216 def __getitem__(self, index: int) -> Any: ... 

217 

218 @overload 

219 def __getitem__(self, index: slice) -> Sequence[Any]: ... 

220 

221 def __getitem__(self, index: Union[int, slice]) -> Any: ... 

222 

223 def __lt__(self, other: Any) -> bool: 

224 return self._op(other, operator.lt) 

225 

226 def __le__(self, other: Any) -> bool: 

227 return self._op(other, operator.le) 

228 

229 def __ge__(self, other: Any) -> bool: 

230 return self._op(other, operator.ge) 

231 

232 def __gt__(self, other: Any) -> bool: 

233 return self._op(other, operator.gt) 

234 

235 def __eq__(self, other: Any) -> bool: 

236 return self._op(other, operator.eq) 

237 

238 def __ne__(self, other: Any) -> bool: 

239 return self._op(other, operator.ne) 

240 

241 def __repr__(self) -> str: 

242 return repr(sql_util._repr_row(self)) 

243 

244 @property 

245 def _fields(self) -> Tuple[str, ...]: 

246 """Return a tuple of string keys as represented by this 

247 :class:`.Row`. 

248 

249 The keys can represent the labels of the columns returned by a core 

250 statement or the names of the orm classes returned by an orm 

251 execution. 

252 

253 This attribute is analogous to the Python named tuple ``._fields`` 

254 attribute. 

255 

256 .. versionadded:: 1.4 

257 

258 .. seealso:: 

259 

260 :attr:`.Row._mapping` 

261 

262 """ 

263 return tuple([k for k in self._parent.keys if k is not None]) 

264 

265 def _asdict(self) -> Dict[str, Any]: 

266 """Return a new dict which maps field names to their corresponding 

267 values. 

268 

269 This method is analogous to the Python named tuple ``._asdict()`` 

270 method, and works by applying the ``dict()`` constructor to the 

271 :attr:`.Row._mapping` attribute. 

272 

273 .. versionadded:: 1.4 

274 

275 .. seealso:: 

276 

277 :attr:`.Row._mapping` 

278 

279 """ 

280 return dict(self._mapping) 

281 

282 

283BaseRowProxy = BaseRow 

284RowProxy = Row 

285 

286 

287class ROMappingView(ABC): 

288 __slots__ = () 

289 

290 _items: Sequence[Any] 

291 _mapping: Mapping["_KeyType", Any] 

292 

293 def __init__( 

294 self, mapping: Mapping["_KeyType", Any], items: Sequence[Any] 

295 ): 

296 self._mapping = mapping # type: ignore[misc] 

297 self._items = items # type: ignore[misc] 

298 

299 def __len__(self) -> int: 

300 return len(self._items) 

301 

302 def __repr__(self) -> str: 

303 return "{0.__class__.__name__}({0._mapping!r})".format(self) 

304 

305 def __iter__(self) -> Iterator[Any]: 

306 return iter(self._items) 

307 

308 def __contains__(self, item: Any) -> bool: 

309 return item in self._items 

310 

311 def __eq__(self, other: Any) -> bool: 

312 return list(other) == list(self) 

313 

314 def __ne__(self, other: Any) -> bool: 

315 return list(other) != list(self) 

316 

317 

318class ROMappingKeysValuesView( 

319 ROMappingView, typing.KeysView["_KeyType"], typing.ValuesView[Any] 

320): 

321 __slots__ = ("_items",) # mapping slot is provided by KeysView 

322 

323 

324class ROMappingItemsView(ROMappingView, typing.ItemsView["_KeyType", Any]): 

325 __slots__ = ("_items",) # mapping slot is provided by ItemsView 

326 

327 

328class RowMapping(BaseRow, typing.Mapping["_KeyType", Any]): 

329 """A ``Mapping`` that maps column names and objects to :class:`.Row` 

330 values. 

331 

332 The :class:`.RowMapping` is available from a :class:`.Row` via the 

333 :attr:`.Row._mapping` attribute, as well as from the iterable interface 

334 provided by the :class:`.MappingResult` object returned by the 

335 :meth:`_engine.Result.mappings` method. 

336 

337 :class:`.RowMapping` supplies Python mapping (i.e. dictionary) access to 

338 the contents of the row. This includes support for testing of 

339 containment of specific keys (string column names or objects), as well 

340 as iteration of keys, values, and items:: 

341 

342 for row in result: 

343 if "a" in row._mapping: 

344 print("Column 'a': %s" % row._mapping["a"]) 

345 

346 print("Column b: %s" % row._mapping[table.c.b]) 

347 

348 .. versionadded:: 1.4 The :class:`.RowMapping` object replaces the 

349 mapping-like access previously provided by a database result row, 

350 which now seeks to behave mostly like a named tuple. 

351 

352 """ 

353 

354 __slots__ = () 

355 

356 if TYPE_CHECKING: 

357 

358 def __getitem__(self, key: _KeyType) -> Any: ... 

359 

360 else: 

361 __getitem__ = BaseRow._get_by_key_impl_mapping 

362 

363 def _values_impl(self) -> List[Any]: 

364 return list(self._data) 

365 

366 def __iter__(self) -> Iterator[str]: 

367 return (k for k in self._parent.keys if k is not None) 

368 

369 def __len__(self) -> int: 

370 return len(self._data) 

371 

372 def __contains__(self, key: object) -> bool: 

373 return self._parent._has_key(key) 

374 

375 def __repr__(self) -> str: 

376 return repr(dict(self)) 

377 

378 def items(self) -> ROMappingItemsView: 

379 """Return a view of key/value tuples for the elements in the 

380 underlying :class:`.Row`. 

381 

382 """ 

383 return ROMappingItemsView( 

384 self, [(key, self[key]) for key in self.keys()] 

385 ) 

386 

387 def keys(self) -> RMKeyView: 

388 """Return a view of 'keys' for string column names represented 

389 by the underlying :class:`.Row`. 

390 

391 """ 

392 

393 return self._parent.keys 

394 

395 def values(self) -> ROMappingKeysValuesView: 

396 """Return a view of values for the values represented in the 

397 underlying :class:`.Row`. 

398 

399 """ 

400 return ROMappingKeysValuesView(self, self._values_impl())