##// END OF EJS Templates
Remove dead code in utils.data
Thomas Kluyver -
Show More
@@ -1,96 +1,35 b''
1 1 # encoding: utf-8
2 2 """Utilities for working with data structures like lists, dicts and tuples.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (C) 2008-2011 The IPython Development Team
7 7 #
8 8 # Distributed under the terms of the BSD License. The full license is in
9 9 # the file COPYING, distributed as part of this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 import types
17
18 #-----------------------------------------------------------------------------
19 # Code
20 #-----------------------------------------------------------------------------
21
22 12 def uniq_stable(elems):
23 13 """uniq_stable(elems) -> list
24 14
25 15 Return from an iterable, a list of all the unique elements in the input,
26 16 but maintaining the order in which they first appear.
27 17
28 18 Note: All elements in the input must be hashable for this routine
29 19 to work, as it internally uses a set for efficiency reasons.
30 20 """
31 21 seen = set()
32 22 return [x for x in elems if x not in seen and not seen.add(x)]
33 23
34 24
35 def sort_compare(lst1, lst2, inplace=1):
36 """Sort and compare two lists.
37
38 By default it does it in place, thus modifying the lists. Use inplace = 0
39 to avoid that (at the cost of temporary copy creation)."""
40 if not inplace:
41 lst1 = lst1[:]
42 lst2 = lst2[:]
43 lst1.sort(); lst2.sort()
44 return lst1 == lst2
45
46
47 def list2dict(lst):
48 """Takes a list of (key,value) pairs and turns it into a dict."""
49
50 dic = {}
51 for k,v in lst: dic[k] = v
52 return dic
53
54
55 def list2dict2(lst, default=''):
56 """Takes a list and turns it into a dict.
57 Much slower than list2dict, but more versatile. This version can take
58 lists with sublists of arbitrary length (including sclars)."""
59
60 dic = {}
61 for elem in lst:
62 if type(elem) in (types.ListType,types.TupleType):
63 size = len(elem)
64 if size == 0:
65 pass
66 elif size == 1:
67 dic[elem] = default
68 else:
69 k,v = elem[0], elem[1:]
70 if len(v) == 1: v = v[0]
71 dic[k] = v
72 else:
73 dic[elem] = default
74 return dic
75
76
77 25 def flatten(seq):
78 26 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
79 27
80 28 return [x for subseq in seq for x in subseq]
81
82
83 def get_slice(seq, start=0, stop=None, step=1):
84 """Get a slice of a sequence with variable step. Specify start,stop,step."""
85 if stop == None:
86 stop = len(seq)
87 item = lambda i: seq[i]
88 return map(item,xrange(start,stop,step))
89
29
90 30
91 31 def chop(seq, size):
92 32 """Chop a sequence into chunks of the given size."""
93 chunk = lambda i: seq[i:i+size]
94 return map(chunk,xrange(0,len(seq),size))
33 return [seq[i:i+size] for i in xrange(0,len(seq),size)]
95 34
96 35
@@ -1,393 +1,391 b''
1 1 # encoding: utf-8
2 2 """A dict subclass that supports attribute style access.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez (original)
7 7 * Brian Granger (refactoring to a dict subclass)
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2008-2011 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 from IPython.utils.data import list2dict2
22
23 21 __all__ = ['Struct']
24 22
25 23 #-----------------------------------------------------------------------------
26 24 # Code
27 25 #-----------------------------------------------------------------------------
28 26
29 27
30 28 class Struct(dict):
31 29 """A dict subclass with attribute style access.
32 30
33 31 This dict subclass has a a few extra features:
34 32
35 33 * Attribute style access.
36 34 * Protection of class members (like keys, items) when using attribute
37 35 style access.
38 36 * The ability to restrict assignment to only existing keys.
39 37 * Intelligent merging.
40 38 * Overloaded operators.
41 39 """
42 40 _allownew = True
43 41 def __init__(self, *args, **kw):
44 42 """Initialize with a dictionary, another Struct, or data.
45 43
46 44 Parameters
47 45 ----------
48 46 args : dict, Struct
49 47 Initialize with one dict or Struct
50 48 kw : dict
51 49 Initialize with key, value pairs.
52 50
53 51 Examples
54 52 --------
55 53
56 54 >>> s = Struct(a=10,b=30)
57 55 >>> s.a
58 56 10
59 57 >>> s.b
60 58 30
61 59 >>> s2 = Struct(s,c=30)
62 60 >>> sorted(s2.keys())
63 61 ['a', 'b', 'c']
64 62 """
65 63 object.__setattr__(self, '_allownew', True)
66 64 dict.__init__(self, *args, **kw)
67 65
68 66 def __setitem__(self, key, value):
69 67 """Set an item with check for allownew.
70 68
71 69 Examples
72 70 --------
73 71
74 72 >>> s = Struct()
75 73 >>> s['a'] = 10
76 74 >>> s.allow_new_attr(False)
77 75 >>> s['a'] = 10
78 76 >>> s['a']
79 77 10
80 78 >>> try:
81 79 ... s['b'] = 20
82 80 ... except KeyError:
83 81 ... print 'this is not allowed'
84 82 ...
85 83 this is not allowed
86 84 """
87 85 if not self._allownew and key not in self:
88 86 raise KeyError(
89 87 "can't create new attribute %s when allow_new_attr(False)" % key)
90 88 dict.__setitem__(self, key, value)
91 89
92 90 def __setattr__(self, key, value):
93 91 """Set an attr with protection of class members.
94 92
95 93 This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
96 94 :exc:`AttributeError`.
97 95
98 96 Examples
99 97 --------
100 98
101 99 >>> s = Struct()
102 100 >>> s.a = 10
103 101 >>> s.a
104 102 10
105 103 >>> try:
106 104 ... s.get = 10
107 105 ... except AttributeError:
108 106 ... print "you can't set a class member"
109 107 ...
110 108 you can't set a class member
111 109 """
112 110 # If key is an str it might be a class member or instance var
113 111 if isinstance(key, str):
114 112 # I can't simply call hasattr here because it calls getattr, which
115 113 # calls self.__getattr__, which returns True for keys in
116 114 # self._data. But I only want keys in the class and in
117 115 # self.__dict__
118 116 if key in self.__dict__ or hasattr(Struct, key):
119 117 raise AttributeError(
120 118 'attr %s is a protected member of class Struct.' % key
121 119 )
122 120 try:
123 121 self.__setitem__(key, value)
124 122 except KeyError as e:
125 123 raise AttributeError(e)
126 124
127 125 def __getattr__(self, key):
128 126 """Get an attr by calling :meth:`dict.__getitem__`.
129 127
130 128 Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
131 129 :exc:`AttributeError`.
132 130
133 131 Examples
134 132 --------
135 133
136 134 >>> s = Struct(a=10)
137 135 >>> s.a
138 136 10
139 137 >>> type(s.get)
140 138 <... 'builtin_function_or_method'>
141 139 >>> try:
142 140 ... s.b
143 141 ... except AttributeError:
144 142 ... print "I don't have that key"
145 143 ...
146 144 I don't have that key
147 145 """
148 146 try:
149 147 result = self[key]
150 148 except KeyError:
151 149 raise AttributeError(key)
152 150 else:
153 151 return result
154 152
155 153 def __iadd__(self, other):
156 154 """s += s2 is a shorthand for s.merge(s2).
157 155
158 156 Examples
159 157 --------
160 158
161 159 >>> s = Struct(a=10,b=30)
162 160 >>> s2 = Struct(a=20,c=40)
163 161 >>> s += s2
164 162 >>> sorted(s.keys())
165 163 ['a', 'b', 'c']
166 164 """
167 165 self.merge(other)
168 166 return self
169 167
170 168 def __add__(self,other):
171 169 """s + s2 -> New Struct made from s.merge(s2).
172 170
173 171 Examples
174 172 --------
175 173
176 174 >>> s1 = Struct(a=10,b=30)
177 175 >>> s2 = Struct(a=20,c=40)
178 176 >>> s = s1 + s2
179 177 >>> sorted(s.keys())
180 178 ['a', 'b', 'c']
181 179 """
182 180 sout = self.copy()
183 181 sout.merge(other)
184 182 return sout
185 183
186 184 def __sub__(self,other):
187 185 """s1 - s2 -> remove keys in s2 from s1.
188 186
189 187 Examples
190 188 --------
191 189
192 190 >>> s1 = Struct(a=10,b=30)
193 191 >>> s2 = Struct(a=40)
194 192 >>> s = s1 - s2
195 193 >>> s
196 194 {'b': 30}
197 195 """
198 196 sout = self.copy()
199 197 sout -= other
200 198 return sout
201 199
202 200 def __isub__(self,other):
203 201 """Inplace remove keys from self that are in other.
204 202
205 203 Examples
206 204 --------
207 205
208 206 >>> s1 = Struct(a=10,b=30)
209 207 >>> s2 = Struct(a=40)
210 208 >>> s1 -= s2
211 209 >>> s1
212 210 {'b': 30}
213 211 """
214 212 for k in other.keys():
215 213 if k in self:
216 214 del self[k]
217 215 return self
218 216
219 217 def __dict_invert(self, data):
220 218 """Helper function for merge.
221 219
222 220 Takes a dictionary whose values are lists and returns a dict with
223 221 the elements of each list as keys and the original keys as values.
224 222 """
225 223 outdict = {}
226 224 for k,lst in data.items():
227 225 if isinstance(lst, str):
228 226 lst = lst.split()
229 227 for entry in lst:
230 228 outdict[entry] = k
231 229 return outdict
232 230
233 231 def dict(self):
234 232 return self
235 233
236 234 def copy(self):
237 235 """Return a copy as a Struct.
238 236
239 237 Examples
240 238 --------
241 239
242 240 >>> s = Struct(a=10,b=30)
243 241 >>> s2 = s.copy()
244 242 >>> type(s2) is Struct
245 243 True
246 244 """
247 245 return Struct(dict.copy(self))
248 246
249 247 def hasattr(self, key):
250 248 """hasattr function available as a method.
251 249
252 250 Implemented like has_key.
253 251
254 252 Examples
255 253 --------
256 254
257 255 >>> s = Struct(a=10)
258 256 >>> s.hasattr('a')
259 257 True
260 258 >>> s.hasattr('b')
261 259 False
262 260 >>> s.hasattr('get')
263 261 False
264 262 """
265 263 return key in self
266 264
267 265 def allow_new_attr(self, allow = True):
268 266 """Set whether new attributes can be created in this Struct.
269 267
270 268 This can be used to catch typos by verifying that the attribute user
271 269 tries to change already exists in this Struct.
272 270 """
273 271 object.__setattr__(self, '_allownew', allow)
274 272
275 273 def merge(self, __loc_data__=None, __conflict_solve=None, **kw):
276 274 """Merge two Structs with customizable conflict resolution.
277 275
278 276 This is similar to :meth:`update`, but much more flexible. First, a
279 277 dict is made from data+key=value pairs. When merging this dict with
280 278 the Struct S, the optional dictionary 'conflict' is used to decide
281 279 what to do.
282 280
283 281 If conflict is not given, the default behavior is to preserve any keys
284 282 with their current value (the opposite of the :meth:`update` method's
285 283 behavior).
286 284
287 285 Parameters
288 286 ----------
289 287 __loc_data : dict, Struct
290 288 The data to merge into self
291 289 __conflict_solve : dict
292 290 The conflict policy dict. The keys are binary functions used to
293 291 resolve the conflict and the values are lists of strings naming
294 292 the keys the conflict resolution function applies to. Instead of
295 293 a list of strings a space separated string can be used, like
296 294 'a b c'.
297 295 kw : dict
298 296 Additional key, value pairs to merge in
299 297
300 298 Notes
301 299 -----
302 300
303 301 The `__conflict_solve` dict is a dictionary of binary functions which will be used to
304 302 solve key conflicts. Here is an example::
305 303
306 304 __conflict_solve = dict(
307 305 func1=['a','b','c'],
308 306 func2=['d','e']
309 307 )
310 308
311 309 In this case, the function :func:`func1` will be used to resolve
312 310 keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
313 311 keys 'd' and 'e'. This could also be written as::
314 312
315 313 __conflict_solve = dict(func1='a b c',func2='d e')
316 314
317 315 These functions will be called for each key they apply to with the
318 316 form::
319 317
320 318 func1(self['a'], other['a'])
321 319
322 320 The return value is used as the final merged value.
323 321
324 322 As a convenience, merge() provides five (the most commonly needed)
325 323 pre-defined policies: preserve, update, add, add_flip and add_s. The
326 324 easiest explanation is their implementation::
327 325
328 326 preserve = lambda old,new: old
329 327 update = lambda old,new: new
330 328 add = lambda old,new: old + new
331 329 add_flip = lambda old,new: new + old # note change of order!
332 330 add_s = lambda old,new: old + ' ' + new # only for str!
333 331
334 332 You can use those four words (as strings) as keys instead
335 333 of defining them as functions, and the merge method will substitute
336 334 the appropriate functions for you.
337 335
338 336 For more complicated conflict resolution policies, you still need to
339 337 construct your own functions.
340 338
341 339 Examples
342 340 --------
343 341
344 342 This show the default policy:
345 343
346 344 >>> s = Struct(a=10,b=30)
347 345 >>> s2 = Struct(a=20,c=40)
348 346 >>> s.merge(s2)
349 347 >>> sorted(s.items())
350 348 [('a', 10), ('b', 30), ('c', 40)]
351 349
352 350 Now, show how to specify a conflict dict:
353 351
354 352 >>> s = Struct(a=10,b=30)
355 353 >>> s2 = Struct(a=20,b=40)
356 354 >>> conflict = {'update':'a','add':'b'}
357 355 >>> s.merge(s2,conflict)
358 356 >>> sorted(s.items())
359 357 [('a', 20), ('b', 70)]
360 358 """
361 359
362 360 data_dict = dict(__loc_data__,**kw)
363 361
364 362 # policies for conflict resolution: two argument functions which return
365 363 # the value that will go in the new struct
366 364 preserve = lambda old,new: old
367 365 update = lambda old,new: new
368 366 add = lambda old,new: old + new
369 367 add_flip = lambda old,new: new + old # note change of order!
370 368 add_s = lambda old,new: old + ' ' + new
371 369
372 370 # default policy is to keep current keys when there's a conflict
373 conflict_solve = list2dict2(self.keys(), default = preserve)
371 conflict_solve = dict.fromkeys(self, preserve)
374 372
375 373 # the conflict_solve dictionary is given by the user 'inverted': we
376 374 # need a name-function mapping, it comes as a function -> names
377 375 # dict. Make a local copy (b/c we'll make changes), replace user
378 376 # strings for the three builtin policies and invert it.
379 377 if __conflict_solve:
380 378 inv_conflict_solve_user = __conflict_solve.copy()
381 379 for name, func in [('preserve',preserve), ('update',update),
382 380 ('add',add), ('add_flip',add_flip),
383 381 ('add_s',add_s)]:
384 382 if name in inv_conflict_solve_user.keys():
385 383 inv_conflict_solve_user[func] = inv_conflict_solve_user[name]
386 384 del inv_conflict_solve_user[name]
387 385 conflict_solve.update(self.__dict_invert(inv_conflict_solve_user))
388 386 for key in data_dict:
389 387 if key not in self:
390 388 self[key] = data_dict[key]
391 389 else:
392 390 self[key] = conflict_solve[key](self[key],data_dict[key])
393 391
General Comments 0
You need to be logged in to leave comments. Login now