Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/row.py: 67%
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
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
1# engine/row.py
2# Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
8"""Define row constructs including :class:`.Row`."""
10from __future__ import annotations
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 Sequence
26from typing import Tuple
27from typing import TYPE_CHECKING
29from ._row_cy import BaseRow as BaseRow
30from ..sql import util as sql_util
31from ..util import deprecated
32from ..util.typing import TypeVarTuple
33from ..util.typing import Unpack
35if TYPE_CHECKING:
36 from typing import Tuple as _RowBase
38 from .result import _KeyType
39 from .result import _ProcessorsType
40 from .result import RMKeyView
41else:
42 _RowBase = Sequence
45_Ts = TypeVarTuple("_Ts")
48class Row(BaseRow, _RowBase[Unpack[_Ts]], Generic[Unpack[_Ts]]):
49 """Represent a single result row.
51 The :class:`.Row` object represents a row of a database result. It is
52 typically associated in the 1.x series of SQLAlchemy with the
53 :class:`_engine.CursorResult` object, however is also used by the ORM for
54 tuple-like results as of SQLAlchemy 1.4.
56 The :class:`.Row` object seeks to act as much like a Python named
57 tuple as possible. For mapping (i.e. dictionary) behavior on a row,
58 such as testing for containment of keys, refer to the :attr:`.Row._mapping`
59 attribute.
61 .. seealso::
63 :ref:`tutorial_selecting_data` - includes examples of selecting
64 rows from SELECT statements.
66 .. versionchanged:: 1.4
68 Renamed ``RowProxy`` to :class:`.Row`. :class:`.Row` is no longer a
69 "proxy" object in that it contains the final form of data within it,
70 and now acts mostly like a named tuple. Mapping-like functionality is
71 moved to the :attr:`.Row._mapping` attribute. See
72 :ref:`change_4710_core` for background on this change.
74 """
76 __slots__ = ()
78 def __setattr__(self, name: str, value: Any) -> NoReturn:
79 raise AttributeError("can't set attribute")
81 def __delattr__(self, name: str) -> NoReturn:
82 raise AttributeError("can't delete attribute")
84 @deprecated(
85 "2.1.0",
86 "The :meth:`.Row._tuple` method is deprecated, :class:`.Row` "
87 "now behaves like a tuple and can unpack types directly.",
88 )
89 def _tuple(self) -> Tuple[Unpack[_Ts]]:
90 """Return a 'tuple' form of this :class:`.Row`.
92 At runtime, this method returns "self"; the :class:`.Row` object is
93 already a named tuple. However, at the typing level, if this
94 :class:`.Row` is typed, the "tuple" return type will be a :pep:`484`
95 ``Tuple`` datatype that contains typing information about individual
96 elements, supporting typed unpacking and attribute access.
98 .. versionadded:: 2.0.19 - The :meth:`.Row._tuple` method supersedes
99 the previous :meth:`.Row.tuple` method, which is now underscored
100 to avoid name conflicts with column names in the same way as other
101 named-tuple methods on :class:`.Row`.
103 .. seealso::
105 :ref:`change_10635` - describes a migration path from this
106 workaround for SQLAlchemy 2.1.
108 :attr:`.Row._t` - shorthand attribute notation
110 :meth:`.Result.tuples`
113 """
114 return self
116 @deprecated(
117 "2.0.19",
118 "The :meth:`.Row.tuple` method is deprecated in favor of "
119 ":meth:`.Row._tuple`; all :class:`.Row` "
120 "methods and library-level attributes are intended to be underscored "
121 "to avoid name conflicts. Please use :meth:`Row._tuple`.",
122 )
123 def tuple(self) -> Tuple[Unpack[_Ts]]:
124 """Return a 'tuple' form of this :class:`.Row`.
126 .. versionadded:: 2.0
128 .. seealso::
130 :ref:`change_10635` - describes a migration path from this
131 workaround for SQLAlchemy 2.1.
133 """
134 return self._tuple()
136 @property
137 @deprecated(
138 "2.1.0",
139 "The :attr:`.Row._t` attribute is deprecated, :class:`.Row` "
140 "now behaves like a tuple and can unpack types directly.",
141 )
142 def _t(self) -> Tuple[Unpack[_Ts]]:
143 """A synonym for :meth:`.Row._tuple`.
145 .. versionadded:: 2.0.19 - The :attr:`.Row._t` attribute supersedes
146 the previous :attr:`.Row.t` attribute, which is now underscored
147 to avoid name conflicts with column names in the same way as other
148 named-tuple methods on :class:`.Row`.
150 .. seealso::
152 :ref:`change_10635` - describes a migration path from this
153 workaround for SQLAlchemy 2.1.
155 :attr:`.Result.t`
156 """
157 return self
159 @property
160 @deprecated(
161 "2.0.19",
162 "The :attr:`.Row.t` attribute is deprecated in favor of "
163 ":attr:`.Row._t`; all :class:`.Row` "
164 "methods and library-level attributes are intended to be underscored "
165 "to avoid name conflicts. Please use :attr:`Row._t`.",
166 )
167 def t(self) -> Tuple[Unpack[_Ts]]:
168 """A synonym for :meth:`.Row._tuple`.
170 .. versionadded:: 2.0
172 .. seealso::
174 :ref:`change_10635` - describes a migration path from this
175 workaround for SQLAlchemy 2.1.
177 """
178 return self._t
180 @property
181 def _mapping(self) -> RowMapping:
182 """Return a :class:`.RowMapping` for this :class:`.Row`.
184 This object provides a consistent Python mapping (i.e. dictionary)
185 interface for the data contained within the row. The :class:`.Row`
186 by itself behaves like a named tuple.
188 .. seealso::
190 :attr:`.Row._fields`
192 .. versionadded:: 1.4
194 """
195 return RowMapping(self._parent, None, self._key_to_index, self._data)
197 def _filter_on_values(
198 self, processor: Optional[_ProcessorsType]
199 ) -> Row[Unpack[_Ts]]:
200 return Row(self._parent, processor, self._key_to_index, self._data)
202 if not TYPE_CHECKING:
204 def _special_name_accessor(name: str) -> Any:
205 """Handle ambiguous names such as "count" and "index" """
207 @property
208 def go(self: Row) -> Any:
209 if self._parent._has_key(name):
210 return self.__getattr__(name)
211 else:
213 def meth(*arg: Any, **kw: Any) -> Any:
214 return getattr(collections_abc.Sequence, name)(
215 self, *arg, **kw
216 )
218 return meth
220 return go
222 count = _special_name_accessor("count")
223 index = _special_name_accessor("index")
225 def __contains__(self, key: Any) -> bool:
226 return key in self._data
228 def _op(self, other: Any, op: Callable[[Any, Any], bool]) -> bool:
229 return (
230 op(self._to_tuple_instance(), other._to_tuple_instance())
231 if isinstance(other, Row)
232 else op(self._to_tuple_instance(), other)
233 )
235 __hash__ = BaseRow.__hash__
237 def __lt__(self, other: Any) -> bool:
238 return self._op(other, operator.lt)
240 def __le__(self, other: Any) -> bool:
241 return self._op(other, operator.le)
243 def __ge__(self, other: Any) -> bool:
244 return self._op(other, operator.ge)
246 def __gt__(self, other: Any) -> bool:
247 return self._op(other, operator.gt)
249 def __eq__(self, other: Any) -> bool:
250 return self._op(other, operator.eq)
252 def __ne__(self, other: Any) -> bool:
253 return self._op(other, operator.ne)
255 def __repr__(self) -> str:
256 return repr(sql_util._repr_row(self))
258 @property
259 def _fields(self) -> Tuple[str, ...]:
260 """Return a tuple of string keys as represented by this
261 :class:`.Row`.
263 The keys can represent the labels of the columns returned by a core
264 statement or the names of the orm classes returned by an orm
265 execution.
267 This attribute is analogous to the Python named tuple ``._fields``
268 attribute.
270 .. versionadded:: 1.4
272 .. seealso::
274 :attr:`.Row._mapping`
276 """
277 return tuple([k for k in self._parent.keys if k is not None])
279 def _asdict(self) -> Dict[str, Any]:
280 """Return a new dict which maps field names to their corresponding
281 values.
283 This method is analogous to the Python named tuple ``._asdict()``
284 method, and works by applying the ``dict()`` constructor to the
285 :attr:`.Row._mapping` attribute.
287 .. versionadded:: 1.4
289 .. seealso::
291 :attr:`.Row._mapping`
293 """
294 return dict(self._mapping)
297BaseRowProxy = BaseRow
298RowProxy = Row
301class ROMappingView(ABC):
302 __slots__ = ()
304 _items: Sequence[Any]
305 _mapping: Mapping["_KeyType", Any]
307 def __init__(
308 self, mapping: Mapping["_KeyType", Any], items: Sequence[Any]
309 ):
310 self._mapping = mapping # type: ignore[misc]
311 self._items = items # type: ignore[misc]
313 def __len__(self) -> int:
314 return len(self._items)
316 def __repr__(self) -> str:
317 return "{0.__class__.__name__}({0._mapping!r})".format(self)
319 def __iter__(self) -> Iterator[Any]:
320 return iter(self._items)
322 def __contains__(self, item: Any) -> bool:
323 return item in self._items
325 def __eq__(self, other: Any) -> bool:
326 return list(other) == list(self)
328 def __ne__(self, other: Any) -> bool:
329 return list(other) != list(self)
332class ROMappingKeysValuesView(
333 ROMappingView, typing.KeysView["_KeyType"], typing.ValuesView[Any]
334):
335 __slots__ = ("_items",) # mapping slot is provided by KeysView
338class ROMappingItemsView(ROMappingView, typing.ItemsView["_KeyType", Any]):
339 __slots__ = ("_items",) # mapping slot is provided by ItemsView
342class RowMapping(BaseRow, typing.Mapping["_KeyType", Any]):
343 """A ``Mapping`` that maps column names and objects to :class:`.Row`
344 values.
346 The :class:`.RowMapping` is available from a :class:`.Row` via the
347 :attr:`.Row._mapping` attribute, as well as from the iterable interface
348 provided by the :class:`.MappingResult` object returned by the
349 :meth:`_engine.Result.mappings` method.
351 :class:`.RowMapping` supplies Python mapping (i.e. dictionary) access to
352 the contents of the row. This includes support for testing of
353 containment of specific keys (string column names or objects), as well
354 as iteration of keys, values, and items::
356 for row in result:
357 if 'a' in row._mapping:
358 print("Column 'a': %s" % row._mapping['a'])
360 print("Column b: %s" % row._mapping[table.c.b])
363 .. versionadded:: 1.4 The :class:`.RowMapping` object replaces the
364 mapping-like access previously provided by a database result row,
365 which now seeks to behave mostly like a named tuple.
367 """
369 __slots__ = ()
371 if TYPE_CHECKING:
373 def __getitem__(self, key: _KeyType) -> Any: ...
375 else:
376 __getitem__ = BaseRow._get_by_key_impl_mapping
378 def _values_impl(self) -> List[Any]:
379 return list(self._data)
381 def __iter__(self) -> Iterator[str]:
382 return (k for k in self._parent.keys if k is not None)
384 def __len__(self) -> int:
385 return len(self._data)
387 def __contains__(self, key: object) -> bool:
388 return self._parent._has_key(key)
390 def __repr__(self) -> str:
391 return repr(dict(self))
393 def items(self) -> ROMappingItemsView:
394 """Return a view of key/value tuples for the elements in the
395 underlying :class:`.Row`.
397 """
398 return ROMappingItemsView(
399 self, [(key, self[key]) for key in self.keys()]
400 )
402 def keys(self) -> RMKeyView:
403 """Return a view of 'keys' for string column names represented
404 by the underlying :class:`.Row`.
406 """
408 return self._parent.keys
410 def values(self) -> ROMappingKeysValuesView:
411 """Return a view of values for the values represented in the
412 underlying :class:`.Row`.
414 """
415 return ROMappingKeysValuesView(self, self._values_impl())