forked from robotframework/robotframework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathitemlist.py
More file actions
184 lines (146 loc) · 5.74 KB
/
itemlist.py
File metadata and controls
184 lines (146 loc) · 5.74 KB
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
# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from functools import total_ordering
from robot.utils import py2to3, unicode
# TODO: When Python 2 support is dropped, we could extend MutableSequence.
# In Python 2 it doesn't have slots: https://bugs.python.org/issue11333
@total_ordering
@py2to3
class ItemList(object):
__slots__ = ['_item_class', '_common_attrs', '_items']
def __init__(self, item_class, common_attrs=None, items=None):
self._item_class = item_class
self._common_attrs = common_attrs
self._items = ()
if items:
self.extend(items)
def create(self, *args, **kwargs):
return self.append(self._item_class(*args, **kwargs))
def append(self, item):
self._check_type_and_set_attrs(item)
self._items += (item,)
return item
def _check_type_and_set_attrs(self, *items):
common_attrs = self._common_attrs or {}
for item in items:
if not isinstance(item, self._item_class):
raise TypeError("Only %s objects accepted, got %s."
% (self._item_class.__name__,
item.__class__.__name__))
for attr in common_attrs:
setattr(item, attr, common_attrs[attr])
return items
def extend(self, items):
self._items += self._check_type_and_set_attrs(*items)
def insert(self, index, item):
self._check_type_and_set_attrs(item)
items = list(self._items)
items.insert(index, item)
self._items = tuple(items)
def pop(self, *index):
items = list(self._items)
result = items.pop(*index)
self._items = tuple(items)
return result
def remove(self, item):
items = list(self._items)
items.remove(item)
self._items = tuple(items)
def index(self, item, *start_and_end):
return self._items.index(item, *start_and_end)
def clear(self):
self._items = ()
def visit(self, visitor):
for item in self:
item.visit(visitor)
def __iter__(self):
index = 0
while index < len(self._items):
yield self._items[index]
index += 1
def __getitem__(self, index):
if not isinstance(index, slice):
return self._items[index]
return self._create_new_from(self._items[index])
def _create_new_from(self, items):
# Cannot pass common_attrs directly to new object because all
# subclasses don't have compatible __init__.
new = type(self)(self._item_class)
new._common_attrs = self._common_attrs
new.extend(items)
return new
def __setitem__(self, index, item):
if isinstance(index, slice):
self._check_type_and_set_attrs(*item)
else:
self._check_type_and_set_attrs(item)
items = list(self._items)
items[index] = item
self._items = tuple(items)
def __delitem__(self, index):
items = list(self._items)
del items[index]
self._items = tuple(items)
def __contains__(self, item):
return item in self._items
def __len__(self):
return len(self._items)
def __unicode__(self):
return u'[%s]' % ', '.join(unicode(item) for item in self)
def count(self, item):
return self._items.count(item)
def sort(self):
self._items = tuple(sorted(self._items))
def reverse(self):
self._items = tuple(reversed(self._items))
def __reversed__(self):
index = 0
while index < len(self._items):
yield self._items[len(self._items) - index - 1]
index += 1
def __eq__(self, other):
return (isinstance(other, ItemList)
and self._is_compatible(other)
and self._items == other._items)
def _is_compatible(self, other):
return (self._item_class is other._item_class
and self._common_attrs == other._common_attrs)
def __ne__(self, other):
# @total_ordering doesn't add __ne__ in Python < 2.7.15
return not self == other
def __lt__(self, other):
if not isinstance(other, ItemList):
raise TypeError('Cannot order ItemList and %s' % type(other).__name__)
if not self._is_compatible(other):
raise TypeError('Cannot order incompatible ItemLists')
return self._items < other._items
def __add__(self, other):
if not isinstance(other, ItemList):
raise TypeError('Cannot add ItemList and %s' % type(other).__name__)
if not self._is_compatible(other):
raise TypeError('Cannot add incompatible ItemLists')
return self._create_new_from(self._items + other._items)
def __iadd__(self, other):
if isinstance(other, ItemList) and not self._is_compatible(other):
raise TypeError('Cannot add incompatible ItemLists')
self.extend(other)
return self
def __mul__(self, other):
return self._create_new_from(self._items * other)
def __imul__(self, other):
self._items *= other
return self
def __rmul__(self, other):
return self * other