1import abc
2import weakref
3
4
5class BTBaseList(object, metaclass=abc.ABCMeta):
6    def __init__(self, table, value):
7        self._table = table
8        self._value = self._validate(list(value))
9
10    @property
11    def _table(self):
12        return self._table_ref()
13
14    @_table.setter
15    def _table(self, value):
16        self._table_ref = weakref.ref(value)
17
18    @property
19    def value(self):
20        return self._value
21
22    def __len__(self):
23        return len(self._value)
24
25    def __iter__(self):
26        return iter(self._value)
27
28    def __next__(self):
29        return next(self._value)
30
31    def __repr__(self):
32        class_ = type(self).__name__
33        data = ", ".join(repr(v) for v in self._value)
34        return "{}<{}>".format(class_, data)
35
36    def __eq__(self, other):
37        if len(self) != len(other):
38            return False
39        for i, j in zip(self, other):
40            if i != j:
41                return False
42        return True
43
44    def __contains__(self, item):
45        """Returns whether `item` is present"""
46        return item in self._value
47
48    def _append(self, item):
49        self._value.append(item)
50
51    def _insert(self, i, item):
52        self._value.insert(i, item)
53
54    def _pop(self, i=-1):
55        return self._value.pop(self._get_canonical_key(i))
56
57    def _remove(self, item):
58        self._value.remove(item)
59
60    def _reverse(self):
61        self._value.reverse()
62
63    def _sort(self, key, reverse=False):
64        self._value.sort(key=key, reverse=reverse)
65
66    def _clear(self):
67        self._value.clear()
68
69    def count(self, item):
70        return self._value.count(item)
71
72    def index(self, item, *args):
73        """Returns the index of `item`"""
74        try:
75            return self._value.index(item, *args)
76        except ValueError:
77            raise KeyError("Key {} is not available".format(item))
78
79    def __getitem__(self, key):
80        """Returns item at index or header `key`"""
81        return self._value[self._get_canonical_key(key)]
82
83    def __setitem__(self, key, value):
84        """Updates item at index or header `key`"""
85        self._value[self._get_canonical_key(key)] = value
86
87    def __delitem__(self, key):
88        del self._value[self._get_canonical_key(key)]
89
90    def _validate(self, value):
91        if len(value) != self._get_ideal_length():
92            raise ValueError(
93                ("'Expected iterable of length {}, " "got {}").format(
94                    self._get_ideal_length(), len(value)
95                )
96            )
97        return value
98
99    @abc.abstractmethod
100    def _get_canonical_key(self, key):
101        pass
102
103    @abc.abstractmethod
104    def _get_ideal_length(self):
105        pass
106
107
108class BTBaseRow(BTBaseList):
109    def _get_canonical_key(self, key):
110        return self._table.columns._canonical_key(key)
111
112    def _get_ideal_length(self):
113        return self._table._ncol
114
115    def _validate(self, value):
116        if self._get_ideal_length() == 0 and len(value) > 0:
117            self._table.columns._reset_state(len(value))
118        return super(BTBaseRow, self)._validate(value)
119
120
121class BTBaseColumn(BTBaseList):
122    def _get_canonical_key(self, key):
123        return self._table.rows._canonical_key(key)
124
125    def _get_ideal_length(self):
126        return len(self._table._data)
127
128    def _validate(self, value):
129        if self._get_ideal_length() == 0 and len(value) > 0:
130            self._table.rows._reset_state(len(value))
131        return super(BTBaseColumn, self)._validate(value)
132