View | Details | Raw Unified | Return to bug 45249
Collapse All | Expand All

(-)a/base/univention-lib/python/ordered_set.py (-1 / +330 lines)
Line 0    Link Here 
0
- 
1
#!/usr/bin/python2.7
2
# coding: utf-8
3
#
4
# Univention Common Python Library
5
#  OrderedSet
6
#
7
# Copyright 2017 Univention GmbH
8
#
9
# http://www.univention.de/
10
#
11
# All rights reserved.
12
#
13
# The source code of this program is made available
14
# under the terms of the GNU Affero General Public License version 3
15
# (GNU AGPL V3) as published by the Free Software Foundation.
16
#
17
# Binary versions of this program provided by Univention to you as
18
# well as other copyrighted, protected or trademarked materials like
19
# Logos, graphics, fonts, specific documentations and configurations,
20
# cryptographic keys etc. are subject to a license agreement between
21
# you and Univention and not subject to the GNU AGPL V3.
22
#
23
# In the case you use this program under the terms of the GNU AGPL V3,
24
# the program is provided in the hope that it will be useful,
25
# but WITHOUT ANY WARRANTY; without even the implied warranty of
26
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
# GNU Affero General Public License for more details.
28
#
29
# You should have received a copy of the GNU Affero General Public
30
# License with the Debian GNU/Linux or Univention distribution in file
31
# /usr/share/common-licenses/AGPL-3; if not, see
32
# <http://www.gnu.org/licenses/>.
33
34
import unittest
35
import collections
36
37
38
class OrderedSet(collections.MutableSet):
39
	"""
40
	A `set()` that remembers insertion order.
41
	"""
42
	def __init__(self, iterable=None):
43
		raw = ((k, None) for k in iterable) if iterable else ()
44
		self._data = collections.OrderedDict(raw)
45
46
	@property
47
	def _name(self):
48
		return self.__class__.__name__
49
50
	def __repr__(self):
51
		return "{}({!r})".format(self._name, [x for x in self])
52
53
	def __len__(self):
54
		return len(self._data)
55
56
	def __contains__(self, key):
57
		return key in self._data
58
59
	def __getitem__(self, index):
60
		try:
61
			return self._data.keys()[index]
62
		except IndexError:
63
			raise IndexError("{} index out of range".format(self._name))
64
65
	def add(self, key):
66
		self._data[key] = None
67
68
	def update(self, sequence):
69
		self._data.update((k, None) for k in sequence)
70
71
	def clear(self):
72
		self._data.clear()
73
74
	def pop(self):
75
		if not self:
76
			raise KeyError("{} is empty".format(self._name))
77
		first = next(iter(self))
78
		self.discard(first)
79
		return first
80
81
	def discard(self, key):
82
		del self._data[key]
83
84
	def __iter__(self):
85
		return iter(self._data)
86
87
	def __eq__(self, other):
88
		if isinstance(other, OrderedSet):
89
			return self._data == other._data
90
		if isinstance(other, collections.Set):
91
			return set(self) == other
92
		return False
93
94
	def __reversed__(self):
95
		return OrderedSet(reversed(self._data))
96
97
	def isdisjoint(self, other):
98
		return bool(self & other)
99
100
	def issubset(self, other):
101
		return self <= other
102
103
	def issuperset(self, other):
104
		return self >= other
105
106
	def difference(self, other):
107
		return self - other
108
109
	def intersection(self, other):
110
		return self & other
111
112
	def symmetric_difference(self, other):
113
		return self ^ other
114
115
	def union(self, other):
116
		return self | other
117
118
119
class OrderedSetTest(unittest.TestCase):
120
	def test_empty_init(self):
121
		os = OrderedSet()
122
		self.assertEqual(len(os), 0)
123
		os = OrderedSet([])
124
		self.assertEqual(len(os), 0)
125
126
	def test_simple_init(self):
127
		os = OrderedSet([1])
128
		self.assertEqual(len(os), 1)
129
130
	def test_large_init(self):
131
		os = OrderedSet([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])
132
		self.assertEqual(len(os), 4)
133
134
	def test_contains(self):
135
		os = OrderedSet([1, 2, 3])
136
		self.assertIn(1, os)
137
		self.assertNotIn(4, os)
138
139
	def test_getitem(self):
140
		os = OrderedSet([1, 2, 3])
141
		self.assertEqual(os[0], 1)
142
		self.assertEqual(os[1], 2)
143
		self.assertEqual(os[2], 3)
144
		with self.assertRaises(IndexError):
145
			os[42]
146
147
	def test_add(self):
148
		os = OrderedSet([1, 2, 3])
149
		self.assertEqual(len(os), 3)
150
		os.add(3)
151
		self.assertIn(3, os)
152
		self.assertEqual(len(os), 3)
153
		os.add(4)
154
		self.assertIn(4, os)
155
		self.assertEqual(len(os), 4)
156
157
	def test_update(self):
158
		os = OrderedSet([1, 2, 3])
159
		self.assertEqual(len(os), 3)
160
		os.update([3, 4, 5, 6])
161
		self.assertEqual(len(os), 6)
162
		for x in (1, 2, 3, 4, 5, 6):
163
			self.assertIn(x, os)
164
165
	def test_clear(self):
166
		os = OrderedSet([1, 2, 3])
167
		os.clear()
168
		self.assertEqual(len(os), 0)
169
		for x in (1, 2, 3):
170
			self.assertNotIn(x, os)
171
172
	def test_pop(self):
173
		os = OrderedSet([1, 2, 3])
174
		self.assertEqual(os.pop(), 1)
175
		self.assertNotIn(1, os)
176
		self.assertEqual(len(os), 2)
177
		self.assertEqual(os.pop(), 2)
178
		self.assertNotIn(2, os)
179
		self.assertEqual(len(os), 1)
180
		self.assertEqual(os.pop(), 3)
181
		self.assertNotIn(3, os)
182
		self.assertEqual(len(os), 0)
183
		with self.assertRaises(KeyError):
184
			os.pop()
185
186
	def test_discard(self):
187
		os = OrderedSet([1, 2, 3])
188
		os.discard(2)
189
		self.assertNotIn(2, os)
190
		self.assertEqual(len(os), 2)
191
		for x in (1, 3):
192
			self.assertIn(x, os)
193
194
	def test_iter(self):
195
		os = OrderedSet([])
196
		collected = [x for x in os]
197
		self.assertEqual(collected, [])
198
		os = OrderedSet([1, 2, 3])
199
		collected = [x for x in os]
200
		self.assertEqual(collected, [1, 2, 3])
201
		os = OrderedSet([3, 2, 1])
202
		collected = [x for x in os]
203
		self.assertEqual(collected, [3, 2, 1])
204
205
	def test_eq_empty(self):
206
		os_emtpy_a = OrderedSet()
207
		os_emtpy_b = OrderedSet([])
208
		self.assertEqual(os_emtpy_a, os_emtpy_b)
209
		self.assertEqual(os_emtpy_a, set())
210
		self.assertNotEqual(os_emtpy_a, [])
211
		self.assertNotEqual(os_emtpy_a, ())
212
213
	def test_eq_single(self):
214
		os_one_a = OrderedSet([1])
215
		os_one_b = OrderedSet([1])
216
		os_one_c = OrderedSet([2])
217
		self.assertEqual(os_one_a, os_one_b)
218
		self.assertNotEqual(os_one_a, os_one_c)
219
		self.assertEqual(os_one_a, set([1]))
220
		self.assertNotEqual(os_one_a, [1])
221
		self.assertNotEqual(os_one_a, (1,))
222
223
	def test_eq_multiple(self):
224
		os_one = OrderedSet([1])
225
		os_multiple_a = OrderedSet([1, 2, 3])
226
		os_multiple_b = OrderedSet([1, 2, 3, 3])
227
		os_multiple_c = OrderedSet([3, 2, 1])
228
		os_multiple_d = OrderedSet([4, 5, 6])
229
230
		self.assertNotEqual(os_one, os_multiple_a)
231
		self.assertEqual(os_multiple_a, os_multiple_b)
232
		self.assertNotEqual(os_multiple_a, os_multiple_c)
233
		self.assertNotEqual(os_multiple_a, os_multiple_d)
234
235
	def test_reversed(self):
236
		self.assertEqual(reversed(OrderedSet([])), OrderedSet([]))
237
		self.assertEqual(reversed(OrderedSet([1])), OrderedSet([1]))
238
		self.assertEqual(reversed(OrderedSet([1, 2])), OrderedSet([2, 1]))
239
		self.assertEqual(reversed(OrderedSet([1, 2, 3])), OrderedSet([3, 2, 1]))
240
		self.assertEqual(reversed(OrderedSet([1, 2, 2, 3])), OrderedSet([3, 3, 2, 1]))
241
242
	# With the methods as tested above, several are available through
243
	# `collections.MutableSet`. The typical `set` operations are available
244
	# through `collections.Set`.
245
246
	def test_remove(self):
247
		os = OrderedSet([1, 2, 3])
248
		os.remove(2)
249
		self.assertNotIn(2, os)
250
		self.assertEqual(len(os), 2)
251
		with self.assertRaises(KeyError):
252
			os.remove(2)
253
254
	def test_is_subset(self):
255
		os_a = OrderedSet([1, 2, 3])
256
		os_b = OrderedSet([1, 2, 3, 3, 4, 5])
257
		self.assertTrue(os_a <= os_b)
258
		self.assertFalse(os_b <= os_a)
259
		self.assertTrue(os_a.issubset(os_b))
260
		self.assertFalse(os_b.issubset(os_a))
261
		self.assertTrue(set([1]) <= OrderedSet([1, 2]))
262
		self.assertTrue(OrderedSet([1]) <= set([1, 2]))
263
264
	def test_is_superset(self):
265
		os_a = OrderedSet([1, 2, 3])
266
		os_b = OrderedSet([1, 2, 3, 3, 4, 5])
267
		self.assertTrue(os_b >= os_a)
268
		self.assertFalse(os_a >= os_b)
269
		self.assertTrue(os_b.issuperset(os_a))
270
		self.assertFalse(os_a.issuperset(os_b))
271
		self.assertTrue(set([1, 2]) >= OrderedSet([1]))
272
		self.assertTrue(OrderedSet([1, 2]) >= set([1]))
273
274
	def test_union(self):
275
		self.assertEqual(OrderedSet() | OrderedSet(), OrderedSet())
276
		self.assertEqual(OrderedSet([1]) | OrderedSet([1]), OrderedSet([1]))
277
		self.assertEqual(OrderedSet([1]) | OrderedSet([2]), OrderedSet([1, 2]))
278
		self.assertEqual(OrderedSet([1, 2]) | OrderedSet([2, 3]), OrderedSet([1, 2, 3]))
279
		self.assertEqual(OrderedSet([1, 2]).union(OrderedSet([2, 3])), OrderedSet([1, 2, 3]))
280
281
	def test_union_set(self):
282
		self.assertEqual(set([1]) | OrderedSet([2]), set([1, 2]))
283
		self.assertEqual(OrderedSet([1]) | set([2]), OrderedSet([1, 2]))
284
		self.assertEqual(set([1]).union(OrderedSet([2])), set([1, 2]))
285
		self.assertEqual(OrderedSet([1]).union(set([2])), OrderedSet([1, 2]))
286
287
	def test_intersection(self):
288
		self.assertEqual(OrderedSet() & OrderedSet(), OrderedSet())
289
		self.assertEqual(OrderedSet([1]) & OrderedSet([1]), OrderedSet([1]))
290
		self.assertEqual(OrderedSet([1]) & OrderedSet([2]), OrderedSet([]))
291
		self.assertEqual(OrderedSet([1, 2]) & OrderedSet([2, 3]), OrderedSet([2]))
292
		self.assertEqual(OrderedSet([1, 2]).intersection(OrderedSet([2, 3])), OrderedSet([2]))
293
294
	def test_intersection_set(self):
295
		self.assertEqual(set([1, 2, 3]) & OrderedSet([2, 3, 4]), set([2, 3]))
296
		self.assertEqual(OrderedSet([1, 2, 3]) & set([2, 3, 4]), OrderedSet([2, 3]))
297
		self.assertEqual(set([1, 2, 3]).intersection(OrderedSet([2, 3, 4])), set([2, 3]))
298
		self.assertEqual(OrderedSet([1, 2, 3]).intersection(set([2, 3, 4])), OrderedSet([2, 3]))
299
300
	def test_difference(self):
301
		self.assertEqual(OrderedSet() - OrderedSet(), OrderedSet())
302
		self.assertEqual(OrderedSet([1]) - OrderedSet([1]), OrderedSet([]))
303
		self.assertEqual(OrderedSet([1]) - OrderedSet([2]), OrderedSet([1]))
304
		self.assertEqual(OrderedSet([1, 2]) - OrderedSet([2, 3]), OrderedSet([1]))
305
		self.assertEqual(OrderedSet([1, 2, 3]) - OrderedSet([4, 5]), OrderedSet([1, 2, 3]))
306
		self.assertEqual(OrderedSet([1, 2, 3]).difference(OrderedSet([4, 5])), OrderedSet([1, 2, 3]))
307
308
	def test_difference_set(self):
309
		self.assertEqual(set([1, 2, 3]) - OrderedSet([3, 4]), set([1, 2]))
310
		self.assertEqual(OrderedSet([1, 2, 3]) - set([3, 4]), OrderedSet([1, 2]))
311
		self.assertEqual(set([1, 2, 3]).difference(OrderedSet([3, 4])), set([1, 2]))
312
		self.assertEqual(OrderedSet([1, 2, 3]).difference(set([3, 4])), OrderedSet([1, 2]))
313
314
	def test_symmetric_difference(self):
315
		self.assertEqual(OrderedSet() ^ OrderedSet(), OrderedSet())
316
		self.assertEqual(OrderedSet([1]) ^ OrderedSet([1]), OrderedSet([]))
317
		self.assertEqual(OrderedSet([1]) ^ OrderedSet([2]), OrderedSet([1, 2]))
318
		self.assertEqual(OrderedSet([1, 2]) ^ OrderedSet([2, 3]), OrderedSet([1, 3]))
319
		self.assertEqual(OrderedSet([1, 4, 3]) ^ OrderedSet([4, 5]), OrderedSet([1, 3, 5]))
320
		self.assertEqual(OrderedSet([1, 4, 3]).symmetric_difference(OrderedSet([4, 5])), OrderedSet([1, 3, 5]))
321
322
	def test_symmetric_difference_set(self):
323
		self.assertEqual(set([1, 2]) ^ OrderedSet([2, 3]), set([1, 3]))
324
		self.assertEqual(OrderedSet([1, 2]) ^ set([2, 3]), OrderedSet([1, 3]))
325
		self.assertEqual(set([1, 2]).symmetric_difference(OrderedSet([2, 3])), set([1, 3]))
326
		self.assertEqual(OrderedSet([1, 2]).symmetric_difference(set([2, 3])), OrderedSet([1, 3]))
327
328
329
if __name__ == '__main__':
330
	unittest.main()

Return to bug 45249