1 """\
2 Indexed set module. Contains the indexed set class, a set that is indexed like
3 a dict.
4
5 @author: Aaron Mavrinac
6 @organization: University of Windsor
7 @contact: mavrin1@uwindsor.ca
8 @license: LGPL-3
9 """
10
11 from copy import copy
15 """\
16 Indexed member class. This is a special type of object which has mutable
17 properties but a special immutable property (called the index) which is
18 used for hashing and equality, allowing it to be stored in a set or to be
19 used as a dict key.
20 """
22 """\
23 Constructor.
24
25 @param index: The index object (immutable).
26 @type index: C{object}
27 """
28 if not hasattr(type(index), '__hash__') \
29 or not hasattr(type(index), '__eq__'):
30 raise TypeError('index object must be immutable')
31 self._index = index
32
33 @property
35 """\
36 Return the index object.
37
38 @rtype: C{object}
39 """
40 return self._index
41
43 """\
44 Return the canonical string representation of the index.
45
46 @return: Canonical string representation.
47 @rtype: C{str}
48 """
49 return repr(self.index)
50
52 """\
53 Return the string representation of the index.
54
55 @return: String representation.
56 @rtype: C{str}
57 """
58 return str(self.index)
59
61 """\
62 Return a hash of the index object.
63
64 @return: The index hash.
65 @rtype: C{int}
66 """
67 return hash(self.index)
68
70 """\
71 Return whether the index objects match.
72
73 @return: True if equal, false otherwise.
74 @rtype: C{bool}
75 """
76 return self.index == other.index if isinstance(other, IndexedMember) \
77 else self.index == other
78
80 """\
81 Return whether the index objects do not match.
82
83 @return: True if not equal, false otherwise.
84 @rtype: C{bool}
85 """
86 return not self == other
87
90 """\
91 Indexed set class. This is a special type of set whose members are mutable
92 objects with an immutable attribute. These overall-mutable members can then
93 be accessed in dict style, using the index as key.
94 """
95 _itemcls = IndexedMember
96
98 """\
99 Constructor.
100
101 @param iterable: The iterable to intialize the set with.
102 @type iterable: C{iterable}
103 """
104 super(IndexedSet, self).__init__()
105 for item in iterable:
106 self.add(item)
107
109 """\
110 Return a set item indexed by key.
111
112 @param key: The index of the item to get.
113 @type key: C{object}
114 @return: The matching item.
115 @rtype: C{object}
116 """
117 for item in self:
118 if item.index == key:
119 return item
120 raise KeyError(key)
121
123 """\
124 Assign an item by key. Normally, new items are added via add() and
125 existing items modified via object reference; this is included for
126 completeness.
127
128 @param key: The index of the item to assign.
129 @type key: C{object}
130 @param item: The item to assign.
131 @type item: C{object}
132 """
133 if not item.index == key:
134 raise ValueError('key does not match item index attribute')
135 if key in self:
136 self.remove(key)
137 set.add(self, item)
138
139 - def add(self, item, *args, **kwargs):
140 """\
141 Add an item to the set. Uses a copy since IndexedMembers have mutable
142 properties.
143
144 @param item: The item to add.
145 @type item: L{IndexedMember}
146 """
147 if not isinstance(item, self._itemcls):
148 item = self._itemcls(item, *args, **kwargs)
149 set.add(self, copy(item))
150
152 """\
153 Update the set with the union of itself and other iterables.
154 """
155 for arg in args:
156 for item in arg:
157 self.add(item)
158
160 """\
161 Update the set with the intersection of itself and other iterables.
162 """
163 common = set()
164 common.update(args)
165 for item in self.keys():
166 if item not in common:
167 self.remove(item)
168
170 """\
171 Return the difference of the set with other iterables.
172 """
173 result = self.copy()
174 result.difference_update(*args)
175 return result
176
178 """\
179 Update the set with the difference of itself and other iterables.
180 """
181 common = set()
182 common.update(args)
183 for item in common:
184 self.discard(item)
185
187 """\
188 Return the symmetric difference of the set with other iterables.
189 """
190 result = self.copy()
191 result.symmetric_difference_update(*args)
192 return result
193
195 """\
196 Update the set with the symmetric difference of itself and other
197 iterables.
198 """
199 common = set()
200 common.update(args)
201 for item in common:
202 try:
203 self.remove(item)
204 except KeyError:
205 self.add(item)
206
208 """\
209 Return a copy of the set with shallow copies of all members.
210 """
211 return self.__class__(self)
212
214 """\
215 Return a list of keys in the set.
216
217 @return: List of keys in the set.
218 @rtype: C{list}
219 """
220 return [item.index for item in self]
221
223 """\
224 Return whether this set contains an item with a given index.
225
226 @param key: The index to test for.
227 @type key: C{object}
228 @return: True if a matching key exists, false otherwise.
229 @rtype: C{bool}
230 """
231 return key in self.keys()
232