File: row.py

package info (click to toggle)
python-astropy 1.3-8~bpo8%2B2
  • links: PTS, VCS
  • area: main
  • in suites: jessie-backports
  • size: 44,292 kB
  • sloc: ansic: 160,360; python: 137,322; sh: 11,493; lex: 7,638; yacc: 4,956; xml: 1,796; makefile: 474; cpp: 364
file content (209 lines) | stat: -rw-r--r-- 7,201 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# Licensed under a 3-clause BSD style license - see LICENSE.rst

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import collections

import numpy as np

from ..extern import six
from ..utils import deprecated
from ..utils.compat import NUMPY_LT_1_8

class Row(object):
    """A class to represent one row of a Table object.

    A Row object is returned when a Table object is indexed with an integer
    or when iterating over a table::

      >>> from astropy.table import Table
      >>> table = Table([(1, 2), (3, 4)], names=('a', 'b'),
      ...               dtype=('int32', 'int32'))
      >>> row = table[1]
      >>> row
      <Row index=1>
        a     b
      int32 int32
      ----- -----
          2     4
      >>> row['a']
      2
      >>> row[1]
      4
    """

    def __init__(self, table, index):
        self._table = table
        self._index = index

        n = len(table)
        if index < -n or index >= n:
            raise IndexError('index {0} out of range for table with length {1}'
                             .format(index, len(table)))

    def __getitem__(self, item):
        return self._table.columns[item][self._index]

    def __setitem__(self, item, val):
        self._table.columns[item][self._index] = val

    def __eq__(self, other):
        if self._table.masked:
            # Sent bug report to numpy-discussion group on 2012-Oct-21, subject:
            # "Comparing rows in a structured masked array raises exception"
            # No response, so this is still unresolved.
            raise ValueError('Unable to compare rows for masked table due to numpy.ma bug')
        return self.as_void() == other

    def __ne__(self, other):
        if self._table.masked:
            raise ValueError('Unable to compare rows for masked table due to numpy.ma bug')
        return self.as_void() != other

    def __array__(self, dtype=None):
        """Support converting Row to np.array via np.array(table).

        Coercion to a different dtype via np.array(table, dtype) is not
        supported and will raise a ValueError.

        If the parent table is masked then the mask information is dropped.
        """
        if dtype is not None:
            raise ValueError('Datatype coercion is not allowed')

        return np.asarray(self.as_void())

    def __len__(self):
        return len(self._table.columns)

    def __iter__(self):
        index = self._index
        for col in six.itervalues(self._table.columns):
            yield col[index]

    @property
    def table(self):
        return self._table

    @property
    def index(self):
        return self._index

    @property
    @deprecated('0.4', alternative=':attr:`Row.as_void`')
    def data(self):
        """
        Returns a *read-only* copy of the row values in the form of np.void or
        np.ma.mvoid objects.  This corresponds to the object types returned for
        row indexing of a pure numpy structured array or masked array. This
        method is slow and its use is deprecated.
        """
        return self.as_void()

    def as_void(self):
        """
        Returns a *read-only* copy of the row values in the form of np.void or
        np.ma.mvoid objects.  This corresponds to the object types returned for
        row indexing of a pure numpy structured array or masked array. This
        method is slow and its use is discouraged when possible.

        Returns
        -------
        void_row : np.void (unmasked) or np.ma.mvoid (masked)
            Copy of row values
        """
        index = self._index
        cols = self._table.columns.values()
        vals = tuple(np.asarray(col)[index] for col in cols)
        if self._table.masked:
            # The logic here is a little complicated to work around
            # bug in numpy < 1.8 (numpy/numpy#483).  Need to build up
            # a np.ma.mvoid object by hand.
            from .table import descr

            # Make np.void version of masks.  Use the table dtype but
            # substitute bool for data type
            masks = tuple(col.mask[index] if hasattr(col, 'mask') else False
                          for col in cols)
            descrs = (descr(col) for col in cols)
            mask_dtypes = [(name, np.bool, shape) for name, type_, shape in descrs]
            row_mask = np.array([masks], dtype=mask_dtypes)[0]

            # Make np.void version of values, and then the final mvoid row
            row_vals = np.array([vals], dtype=self.dtype)[0]
            try:
                void_row = np.ma.mvoid(data=row_vals, mask=row_mask)
            except ValueError as err:
                # Another bug (or maybe same?) that is fixed in 1.8 prevents
                # accessing a row in masked array if it has object-type members.
                # >>> x = np.ma.empty(1, dtype=[('a', 'O')])
                # >>> x['a'] = 1
                # >>> x['a'].mask = True
                # >>> x[0]
                # ValueError: Setting void-array with object members using buffer. [numpy.ma.core]
                #
                # All we do here is re-raise with a more informative message
                msg = six.text_type(err)
                if ('Setting void-array with object members' in msg and
                        NUMPY_LT_1_8):
                    raise ValueError(
                        'Cannot convert masked table row with Object type '
                        'columns using as_void(), due to a bug in Numpy '
                        '{0}.  Please upgrade to Numpy 1.8 or newer.'.format(
                            np.__version__))
                else:
                    raise
        else:
            void_row = np.array([vals], dtype=self.dtype)[0]
        return void_row

    @property
    def meta(self):
        return self._table.meta

    @property
    def columns(self):
        return self._table.columns

    @property
    def colnames(self):
        return self._table.colnames

    @property
    def dtype(self):
        return self._table.dtype

    def _base_repr_(self, html=False):
        """
        Display row as a single-line table but with appropriate header line.
        """
        index = self.index if (self.index >= 0) else self.index + len(self._table)
        table = self._table[index:index + 1]
        descr_vals = [self.__class__.__name__,
                      'index={0}'.format(self.index)]
        if table.masked:
            descr_vals.append('masked=True')

        return table._base_repr_(html, descr_vals, max_width=-1,
                                 tableid='table{0}'.format(id(self._table)))

    def _repr_html_(self):
        return self._base_repr_(html=True)

    def __repr__(self):
        return self._base_repr_(html=False)

    def __unicode__(self):
        index = self.index if (self.index >= 0) else self.index + len(self._table)
        return '\n'.join(self.table[index:index + 1].pformat(max_width=-1))
    if not six.PY2:
        __str__ = __unicode__

    def __bytes__(self):
        return six.text_type(self).encode('utf-8')
    if six.PY2:
        __str__ = __bytes__


collections.Sequence.register(Row)