You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					621 lines
				
				18 KiB
			
		
		
			
		
	
	
					621 lines
				
				18 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								# engine/row.py
							 | 
						||
| 
								 | 
							
								# Copyright (C) 2005-2022 the SQLAlchemy authors and contributors
							 | 
						||
| 
								 | 
							
								# <see AUTHORS file>
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# This module is part of SQLAlchemy and is released under
							 | 
						||
| 
								 | 
							
								# the MIT License: https://www.opensource.org/licenses/mit-license.php
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""Define row constructs including :class:`.Row`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import operator
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from .. import util
							 | 
						||
| 
								 | 
							
								from ..sql import util as sql_util
							 | 
						||
| 
								 | 
							
								from ..util.compat import collections_abc
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								MD_INDEX = 0  # integer index in cursor.description
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# This reconstructor is necessary so that pickles with the C extension or
							 | 
						||
| 
								 | 
							
								# without use the same Binary format.
							 | 
						||
| 
								 | 
							
								try:
							 | 
						||
| 
								 | 
							
								    # We need a different reconstructor on the C extension so that we can
							 | 
						||
| 
								 | 
							
								    # add extra checks that fields have correctly been initialized by
							 | 
						||
| 
								 | 
							
								    # __setstate__.
							 | 
						||
| 
								 | 
							
								    from sqlalchemy.cresultproxy import safe_rowproxy_reconstructor
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # The extra function embedding is needed so that the
							 | 
						||
| 
								 | 
							
								    # reconstructor function has the same signature whether or not
							 | 
						||
| 
								 | 
							
								    # the extension is present.
							 | 
						||
| 
								 | 
							
								    def rowproxy_reconstructor(cls, state):
							 | 
						||
| 
								 | 
							
								        return safe_rowproxy_reconstructor(cls, state)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								except ImportError:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def rowproxy_reconstructor(cls, state):
							 | 
						||
| 
								 | 
							
								        obj = cls.__new__(cls)
							 | 
						||
| 
								 | 
							
								        obj.__setstate__(state)
							 | 
						||
| 
								 | 
							
								        return obj
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								KEY_INTEGER_ONLY = 0
							 | 
						||
| 
								 | 
							
								"""__getitem__ only allows integer values, raises TypeError otherwise"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								KEY_OBJECTS_ONLY = 1
							 | 
						||
| 
								 | 
							
								"""__getitem__ only allows string/object values, raises TypeError otherwise"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								KEY_OBJECTS_BUT_WARN = 2
							 | 
						||
| 
								 | 
							
								"""__getitem__ allows integer or string/object values, but emits a 2.0
							 | 
						||
| 
								 | 
							
								deprecation warning if string/object is passed"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								KEY_OBJECTS_NO_WARN = 3
							 | 
						||
| 
								 | 
							
								"""__getitem__ allows integer or string/object values with no warnings
							 | 
						||
| 
								 | 
							
								or errors."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								try:
							 | 
						||
| 
								 | 
							
								    from sqlalchemy.cresultproxy import BaseRow
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _baserow_usecext = True
							 | 
						||
| 
								 | 
							
								except ImportError:
							 | 
						||
| 
								 | 
							
								    _baserow_usecext = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    class BaseRow(object):
							 | 
						||
| 
								 | 
							
								        __slots__ = ("_parent", "_data", "_keymap", "_key_style")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __init__(self, parent, processors, keymap, key_style, data):
							 | 
						||
| 
								 | 
							
								            """Row objects are constructed by CursorResult objects."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            object.__setattr__(self, "_parent", parent)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if processors:
							 | 
						||
| 
								 | 
							
								                object.__setattr__(
							 | 
						||
| 
								 | 
							
								                    self,
							 | 
						||
| 
								 | 
							
								                    "_data",
							 | 
						||
| 
								 | 
							
								                    tuple(
							 | 
						||
| 
								 | 
							
								                        [
							 | 
						||
| 
								 | 
							
								                            proc(value) if proc else value
							 | 
						||
| 
								 | 
							
								                            for proc, value in zip(processors, data)
							 | 
						||
| 
								 | 
							
								                        ]
							 | 
						||
| 
								 | 
							
								                    ),
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                object.__setattr__(self, "_data", tuple(data))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            object.__setattr__(self, "_keymap", keymap)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            object.__setattr__(self, "_key_style", key_style)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __reduce__(self):
							 | 
						||
| 
								 | 
							
								            return (
							 | 
						||
| 
								 | 
							
								                rowproxy_reconstructor,
							 | 
						||
| 
								 | 
							
								                (self.__class__, self.__getstate__()),
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def _filter_on_values(self, filters):
							 | 
						||
| 
								 | 
							
								            return Row(
							 | 
						||
| 
								 | 
							
								                self._parent,
							 | 
						||
| 
								 | 
							
								                filters,
							 | 
						||
| 
								 | 
							
								                self._keymap,
							 | 
						||
| 
								 | 
							
								                self._key_style,
							 | 
						||
| 
								 | 
							
								                self._data,
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def _values_impl(self):
							 | 
						||
| 
								 | 
							
								            return list(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __iter__(self):
							 | 
						||
| 
								 | 
							
								            return iter(self._data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __len__(self):
							 | 
						||
| 
								 | 
							
								            return len(self._data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __hash__(self):
							 | 
						||
| 
								 | 
							
								            return hash(self._data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def _get_by_int_impl(self, key):
							 | 
						||
| 
								 | 
							
								            return self._data[key]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def _get_by_key_impl(self, key):
							 | 
						||
| 
								 | 
							
								            if int in key.__class__.__mro__:
							 | 
						||
| 
								 | 
							
								                return self._data[key]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if self._key_style == KEY_INTEGER_ONLY:
							 | 
						||
| 
								 | 
							
								                self._parent._raise_for_nonint(key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            # the following is all LegacyRow support.   none of this
							 | 
						||
| 
								 | 
							
								            # should be called if not LegacyRow
							 | 
						||
| 
								 | 
							
								            # assert isinstance(self, LegacyRow)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                rec = self._keymap[key]
							 | 
						||
| 
								 | 
							
								            except KeyError as ke:
							 | 
						||
| 
								 | 
							
								                rec = self._parent._key_fallback(key, ke)
							 | 
						||
| 
								 | 
							
								            except TypeError:
							 | 
						||
| 
								 | 
							
								                if isinstance(key, slice):
							 | 
						||
| 
								 | 
							
								                    return tuple(self._data[key])
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    raise
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            mdindex = rec[MD_INDEX]
							 | 
						||
| 
								 | 
							
								            if mdindex is None:
							 | 
						||
| 
								 | 
							
								                self._parent._raise_for_ambiguous_column_name(rec)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            elif self._key_style == KEY_OBJECTS_BUT_WARN and mdindex != key:
							 | 
						||
| 
								 | 
							
								                self._parent._warn_for_nonint(key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return self._data[mdindex]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # The original 1.4 plan was that Row would not allow row["str"]
							 | 
						||
| 
								 | 
							
								        # access, however as the C extensions were inadvertently allowing
							 | 
						||
| 
								 | 
							
								        # this coupled with the fact that orm Session sets future=True,
							 | 
						||
| 
								 | 
							
								        # this allows a softer upgrade path.  see #6218
							 | 
						||
| 
								 | 
							
								        __getitem__ = _get_by_key_impl
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def _get_by_key_impl_mapping(self, key):
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                rec = self._keymap[key]
							 | 
						||
| 
								 | 
							
								            except KeyError as ke:
							 | 
						||
| 
								 | 
							
								                rec = self._parent._key_fallback(key, ke)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            mdindex = rec[MD_INDEX]
							 | 
						||
| 
								 | 
							
								            if mdindex is None:
							 | 
						||
| 
								 | 
							
								                self._parent._raise_for_ambiguous_column_name(rec)
							 | 
						||
| 
								 | 
							
								            elif (
							 | 
						||
| 
								 | 
							
								                self._key_style == KEY_OBJECTS_ONLY
							 | 
						||
| 
								 | 
							
								                and int in key.__class__.__mro__
							 | 
						||
| 
								 | 
							
								            ):
							 | 
						||
| 
								 | 
							
								                raise KeyError(key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return self._data[mdindex]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def __getattr__(self, name):
							 | 
						||
| 
								 | 
							
								            try:
							 | 
						||
| 
								 | 
							
								                return self._get_by_key_impl_mapping(name)
							 | 
						||
| 
								 | 
							
								            except KeyError as e:
							 | 
						||
| 
								 | 
							
								                util.raise_(AttributeError(e.args[0]), replace_context=e)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Row(BaseRow, collections_abc.Sequence):
							 | 
						||
| 
								 | 
							
								    """Represent a single result row.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The :class:`.Row` object represents a row of a database result.  It is
							 | 
						||
| 
								 | 
							
								    typically associated in the 1.x series of SQLAlchemy with the
							 | 
						||
| 
								 | 
							
								    :class:`_engine.CursorResult` object, however is also used by the ORM for
							 | 
						||
| 
								 | 
							
								    tuple-like results as of SQLAlchemy 1.4.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The :class:`.Row` object seeks to act as much like a Python named
							 | 
						||
| 
								 | 
							
								    tuple as possible.   For mapping (i.e. dictionary) behavior on a row,
							 | 
						||
| 
								 | 
							
								    such as testing for containment of keys, refer to the :attr:`.Row._mapping`
							 | 
						||
| 
								 | 
							
								    attribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :ref:`coretutorial_selecting` - includes examples of selecting
							 | 
						||
| 
								 | 
							
								        rows from SELECT statements.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :class:`.LegacyRow` - Compatibility interface introduced in SQLAlchemy
							 | 
						||
| 
								 | 
							
								        1.4.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionchanged:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Renamed ``RowProxy`` to :class:`.Row`.  :class:`.Row` is no longer a
							 | 
						||
| 
								 | 
							
								        "proxy" object in that it contains the final form of data within it,
							 | 
						||
| 
								 | 
							
								        and now acts mostly like a named tuple.  Mapping-like functionality is
							 | 
						||
| 
								 | 
							
								        moved to the :attr:`.Row._mapping` attribute, but will remain available
							 | 
						||
| 
								 | 
							
								        in SQLAlchemy 1.x series via the :class:`.LegacyRow` class that is used
							 | 
						||
| 
								 | 
							
								        by :class:`_engine.LegacyCursorResult`.
							 | 
						||
| 
								 | 
							
								        See :ref:`change_4710_core` for background
							 | 
						||
| 
								 | 
							
								        on this change.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = ()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # in 2.0, this should be KEY_INTEGER_ONLY
							 | 
						||
| 
								 | 
							
								    _default_key_style = KEY_OBJECTS_BUT_WARN
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __setattr__(self, name, value):
							 | 
						||
| 
								 | 
							
								        raise AttributeError("can't set attribute")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __delattr__(self, name):
							 | 
						||
| 
								 | 
							
								        raise AttributeError("can't delete attribute")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def _mapping(self):
							 | 
						||
| 
								 | 
							
								        """Return a :class:`.RowMapping` for this :class:`.Row`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This object provides a consistent Python mapping (i.e. dictionary)
							 | 
						||
| 
								 | 
							
								        interface for the data contained within the row.   The :class:`.Row`
							 | 
						||
| 
								 | 
							
								        by itself behaves like a named tuple, however in the 1.4 series of
							 | 
						||
| 
								 | 
							
								        SQLAlchemy, the :class:`.LegacyRow` class is still used by Core which
							 | 
						||
| 
								 | 
							
								        continues to have mapping-like behaviors against the row object
							 | 
						||
| 
								 | 
							
								        itself.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`.Row._fields`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return RowMapping(
							 | 
						||
| 
								 | 
							
								            self._parent,
							 | 
						||
| 
								 | 
							
								            None,
							 | 
						||
| 
								 | 
							
								            self._keymap,
							 | 
						||
| 
								 | 
							
								            RowMapping._default_key_style,
							 | 
						||
| 
								 | 
							
								            self._data,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _special_name_accessor(name):
							 | 
						||
| 
								 | 
							
								        """Handle ambiguous names such as "count" and "index" """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        @property
							 | 
						||
| 
								 | 
							
								        def go(self):
							 | 
						||
| 
								 | 
							
								            if self._parent._has_key(name):
							 | 
						||
| 
								 | 
							
								                return self.__getattr__(name)
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                def meth(*arg, **kw):
							 | 
						||
| 
								 | 
							
								                    return getattr(collections_abc.Sequence, name)(
							 | 
						||
| 
								 | 
							
								                        self, *arg, **kw
							 | 
						||
| 
								 | 
							
								                    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                return meth
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return go
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    count = _special_name_accessor("count")
							 | 
						||
| 
								 | 
							
								    index = _special_name_accessor("index")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __contains__(self, key):
							 | 
						||
| 
								 | 
							
								        return key in self._data
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __getstate__(self):
							 | 
						||
| 
								 | 
							
								        return {
							 | 
						||
| 
								 | 
							
								            "_parent": self._parent,
							 | 
						||
| 
								 | 
							
								            "_data": self._data,
							 | 
						||
| 
								 | 
							
								            "_key_style": self._key_style,
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __setstate__(self, state):
							 | 
						||
| 
								 | 
							
								        parent = state["_parent"]
							 | 
						||
| 
								 | 
							
								        object.__setattr__(self, "_parent", parent)
							 | 
						||
| 
								 | 
							
								        object.__setattr__(self, "_data", state["_data"])
							 | 
						||
| 
								 | 
							
								        object.__setattr__(self, "_keymap", parent._keymap)
							 | 
						||
| 
								 | 
							
								        object.__setattr__(self, "_key_style", state["_key_style"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _op(self, other, op):
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            op(tuple(self), tuple(other))
							 | 
						||
| 
								 | 
							
								            if isinstance(other, Row)
							 | 
						||
| 
								 | 
							
								            else op(tuple(self), other)
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __hash__ = BaseRow.__hash__
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __lt__(self, other):
							 | 
						||
| 
								 | 
							
								        return self._op(other, operator.lt)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __le__(self, other):
							 | 
						||
| 
								 | 
							
								        return self._op(other, operator.le)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __ge__(self, other):
							 | 
						||
| 
								 | 
							
								        return self._op(other, operator.ge)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __gt__(self, other):
							 | 
						||
| 
								 | 
							
								        return self._op(other, operator.gt)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __eq__(self, other):
							 | 
						||
| 
								 | 
							
								        return self._op(other, operator.eq)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __ne__(self, other):
							 | 
						||
| 
								 | 
							
								        return self._op(other, operator.ne)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __repr__(self):
							 | 
						||
| 
								 | 
							
								        return repr(sql_util._repr_row(self))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @util.deprecated_20(
							 | 
						||
| 
								 | 
							
								        ":meth:`.Row.keys`",
							 | 
						||
| 
								 | 
							
								        alternative="Use the namedtuple standard accessor "
							 | 
						||
| 
								 | 
							
								        ":attr:`.Row._fields`, or for full mapping behavior use  "
							 | 
						||
| 
								 | 
							
								        "row._mapping.keys() ",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    def keys(self):
							 | 
						||
| 
								 | 
							
								        """Return the list of keys as strings represented by this
							 | 
						||
| 
								 | 
							
								        :class:`.Row`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The keys can represent the labels of the columns returned by a core
							 | 
						||
| 
								 | 
							
								        statement or the names of the orm classes returned by an orm
							 | 
						||
| 
								 | 
							
								        execution.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method is analogous to the Python dictionary ``.keys()`` method,
							 | 
						||
| 
								 | 
							
								        except that it returns a list, not an iterator.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`.Row._fields`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`.Row._mapping`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return self._parent.keys
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def _fields(self):
							 | 
						||
| 
								 | 
							
								        """Return a tuple of string keys as represented by this
							 | 
						||
| 
								 | 
							
								        :class:`.Row`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The keys can represent the labels of the columns returned by a core
							 | 
						||
| 
								 | 
							
								        statement or the names of the orm classes returned by an orm
							 | 
						||
| 
								 | 
							
								        execution.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This attribute is analogous to the Python named tuple ``._fields``
							 | 
						||
| 
								 | 
							
								        attribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`.Row._mapping`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return tuple([k for k in self._parent.keys if k is not None])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _asdict(self):
							 | 
						||
| 
								 | 
							
								        """Return a new dict which maps field names to their corresponding
							 | 
						||
| 
								 | 
							
								        values.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method is analogous to the Python named tuple ``._asdict()``
							 | 
						||
| 
								 | 
							
								        method, and works by applying the ``dict()`` constructor to the
							 | 
						||
| 
								 | 
							
								        :attr:`.Row._mapping` attribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionadded:: 1.4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`.Row._mapping`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return dict(self._mapping)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _replace(self):
							 | 
						||
| 
								 | 
							
								        raise NotImplementedError()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def _field_defaults(self):
							 | 
						||
| 
								 | 
							
								        raise NotImplementedError()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class LegacyRow(Row):
							 | 
						||
| 
								 | 
							
								    """A subclass of :class:`.Row` that delivers 1.x SQLAlchemy behaviors
							 | 
						||
| 
								 | 
							
								    for Core.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The :class:`.LegacyRow` class is where most of the Python mapping
							 | 
						||
| 
								 | 
							
								    (i.e. dictionary-like)
							 | 
						||
| 
								 | 
							
								    behaviors are implemented for the row object.  The mapping behavior
							 | 
						||
| 
								 | 
							
								    of :class:`.Row` going forward is accessible via the :class:`.Row._mapping`
							 | 
						||
| 
								 | 
							
								    attribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 1.4 - added :class:`.LegacyRow` which encapsulates most
							 | 
						||
| 
								 | 
							
								       of the deprecated behaviors of :class:`.Row`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = ()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if util.SQLALCHEMY_WARN_20:
							 | 
						||
| 
								 | 
							
								        _default_key_style = KEY_OBJECTS_BUT_WARN
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        _default_key_style = KEY_OBJECTS_NO_WARN
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __contains__(self, key):
							 | 
						||
| 
								 | 
							
								        return self._parent._contains(key, self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # prior to #6218, LegacyRow would redirect the behavior of __getitem__
							 | 
						||
| 
								 | 
							
								    # for the non C version of BaseRow. This is now set up by Python BaseRow
							 | 
						||
| 
								 | 
							
								    # in all cases
							 | 
						||
| 
								 | 
							
								    # if not _baserow_usecext:
							 | 
						||
| 
								 | 
							
								    #    __getitem__ = BaseRow._get_by_key_impl
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @util.deprecated(
							 | 
						||
| 
								 | 
							
								        "1.4",
							 | 
						||
| 
								 | 
							
								        "The :meth:`.LegacyRow.has_key` method is deprecated and will be "
							 | 
						||
| 
								 | 
							
								        "removed in a future release.  To test for key membership, use "
							 | 
						||
| 
								 | 
							
								        "the :attr:`Row._mapping` attribute, i.e. 'key in row._mapping`.",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    def has_key(self, key):
							 | 
						||
| 
								 | 
							
								        """Return True if this :class:`.LegacyRow` contains the given key.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Through the SQLAlchemy 1.x series, the ``__contains__()`` method of
							 | 
						||
| 
								 | 
							
								        :class:`.Row` (or :class:`.LegacyRow` as of SQLAlchemy 1.4)  also links
							 | 
						||
| 
								 | 
							
								        to :meth:`.Row.has_key`, in that an expression such as ::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            "some_col" in row
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Will return True if the row contains a column named ``"some_col"``,
							 | 
						||
| 
								 | 
							
								        in the way that a Python mapping works.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        However, it is planned that the 2.0 series of SQLAlchemy will reverse
							 | 
						||
| 
								 | 
							
								        this behavior so that ``__contains__()`` will refer to a value being
							 | 
						||
| 
								 | 
							
								        present in the row, in the way that a Python tuple works.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :ref:`change_4710_core`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self._parent._has_key(key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @util.deprecated(
							 | 
						||
| 
								 | 
							
								        "1.4",
							 | 
						||
| 
								 | 
							
								        "The :meth:`.LegacyRow.items` method is deprecated and will be "
							 | 
						||
| 
								 | 
							
								        "removed in a future release.  Use the :attr:`Row._mapping` "
							 | 
						||
| 
								 | 
							
								        "attribute, i.e., 'row._mapping.items()'.",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    def items(self):
							 | 
						||
| 
								 | 
							
								        """Return a list of tuples, each tuple containing a key/value pair.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method is analogous to the Python dictionary ``.items()`` method,
							 | 
						||
| 
								 | 
							
								        except that it returns a list, not an iterator.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return [(key, self[key]) for key in self.keys()]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @util.deprecated(
							 | 
						||
| 
								 | 
							
								        "1.4",
							 | 
						||
| 
								 | 
							
								        "The :meth:`.LegacyRow.iterkeys` method is deprecated and will be "
							 | 
						||
| 
								 | 
							
								        "removed in a future release.  Use the :attr:`Row._mapping` "
							 | 
						||
| 
								 | 
							
								        "attribute, i.e., 'row._mapping.keys()'.",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    def iterkeys(self):
							 | 
						||
| 
								 | 
							
								        """Return a an iterator against the :meth:`.Row.keys` method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method is analogous to the Python-2-only dictionary
							 | 
						||
| 
								 | 
							
								        ``.iterkeys()`` method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return iter(self._parent.keys)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @util.deprecated(
							 | 
						||
| 
								 | 
							
								        "1.4",
							 | 
						||
| 
								 | 
							
								        "The :meth:`.LegacyRow.itervalues` method is deprecated and will be "
							 | 
						||
| 
								 | 
							
								        "removed in a future release.  Use the :attr:`Row._mapping` "
							 | 
						||
| 
								 | 
							
								        "attribute, i.e., 'row._mapping.values()'.",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    def itervalues(self):
							 | 
						||
| 
								 | 
							
								        """Return a an iterator against the :meth:`.Row.values` method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method is analogous to the Python-2-only dictionary
							 | 
						||
| 
								 | 
							
								        ``.itervalues()`` method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return iter(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @util.deprecated(
							 | 
						||
| 
								 | 
							
								        "1.4",
							 | 
						||
| 
								 | 
							
								        "The :meth:`.LegacyRow.values` method is deprecated and will be "
							 | 
						||
| 
								 | 
							
								        "removed in a future release.  Use the :attr:`Row._mapping` "
							 | 
						||
| 
								 | 
							
								        "attribute, i.e., 'row._mapping.values()'.",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    def values(self):
							 | 
						||
| 
								 | 
							
								        """Return the values represented by this :class:`.Row` as a list.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        This method is analogous to the Python dictionary ``.values()`` method,
							 | 
						||
| 
								 | 
							
								        except that it returns a list, not an iterator.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self._values_impl()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BaseRowProxy = BaseRow
							 | 
						||
| 
								 | 
							
								RowProxy = Row
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ROMappingView(
							 | 
						||
| 
								 | 
							
								    collections_abc.KeysView,
							 | 
						||
| 
								 | 
							
								    collections_abc.ValuesView,
							 | 
						||
| 
								 | 
							
								    collections_abc.ItemsView,
							 | 
						||
| 
								 | 
							
								):
							 | 
						||
| 
								 | 
							
								    __slots__ = (
							 | 
						||
| 
								 | 
							
								        "_mapping",
							 | 
						||
| 
								 | 
							
								        "_items",
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, mapping, items):
							 | 
						||
| 
								 | 
							
								        self._mapping = mapping
							 | 
						||
| 
								 | 
							
								        self._items = items
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __len__(self):
							 | 
						||
| 
								 | 
							
								        return len(self._items)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __repr__(self):
							 | 
						||
| 
								 | 
							
								        return "{0.__class__.__name__}({0._mapping!r})".format(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __iter__(self):
							 | 
						||
| 
								 | 
							
								        return iter(self._items)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __contains__(self, item):
							 | 
						||
| 
								 | 
							
								        return item in self._items
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __eq__(self, other):
							 | 
						||
| 
								 | 
							
								        return list(other) == list(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __ne__(self, other):
							 | 
						||
| 
								 | 
							
								        return list(other) != list(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class RowMapping(BaseRow, collections_abc.Mapping):
							 | 
						||
| 
								 | 
							
								    """A ``Mapping`` that maps column names and objects to :class:`.Row` values.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The :class:`.RowMapping` is available from a :class:`.Row` via the
							 | 
						||
| 
								 | 
							
								    :attr:`.Row._mapping` attribute, as well as from the iterable interface
							 | 
						||
| 
								 | 
							
								    provided by the :class:`.MappingResult` object returned by the
							 | 
						||
| 
								 | 
							
								    :meth:`_engine.Result.mappings` method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :class:`.RowMapping` supplies Python mapping (i.e. dictionary) access to
							 | 
						||
| 
								 | 
							
								    the  contents of the row.   This includes support for testing of
							 | 
						||
| 
								 | 
							
								    containment of specific keys (string column names or objects), as well
							 | 
						||
| 
								 | 
							
								    as iteration of keys, values, and items::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for row in result:
							 | 
						||
| 
								 | 
							
								            if 'a' in row._mapping:
							 | 
						||
| 
								 | 
							
								                print("Column 'a': %s" % row._mapping['a'])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            print("Column b: %s" % row._mapping[table.c.b])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 1.4 The :class:`.RowMapping` object replaces the
							 | 
						||
| 
								 | 
							
								       mapping-like access previously provided by a database result row,
							 | 
						||
| 
								 | 
							
								       which now seeks to behave mostly like a named tuple.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = ()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _default_key_style = KEY_OBJECTS_ONLY
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if not _baserow_usecext:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        __getitem__ = BaseRow._get_by_key_impl_mapping
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def _values_impl(self):
							 | 
						||
| 
								 | 
							
								            return list(self._data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __iter__(self):
							 | 
						||
| 
								 | 
							
								        return (k for k in self._parent.keys if k is not None)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __len__(self):
							 | 
						||
| 
								 | 
							
								        return len(self._data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __contains__(self, key):
							 | 
						||
| 
								 | 
							
								        return self._parent._has_key(key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __repr__(self):
							 | 
						||
| 
								 | 
							
								        return repr(dict(self))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def items(self):
							 | 
						||
| 
								 | 
							
								        """Return a view of key/value tuples for the elements in the
							 | 
						||
| 
								 | 
							
								        underlying :class:`.Row`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return ROMappingView(self, [(key, self[key]) for key in self.keys()])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def keys(self):
							 | 
						||
| 
								 | 
							
								        """Return a view of 'keys' for string column names represented
							 | 
						||
| 
								 | 
							
								        by the underlying :class:`.Row`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return self._parent.keys
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def values(self):
							 | 
						||
| 
								 | 
							
								        """Return a view of values for the values represented in the
							 | 
						||
| 
								 | 
							
								        underlying :class:`.Row`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return ROMappingView(self, self._values_impl())
							 |