1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Various classes and functions to provide some backwards-compatibility with
17 previous versions of Python from 2.6 onward.
18 """
19
20 import errno
21 import math
22 import os
23 import time
24
25 from trac.util.text import cleandoc
26
27
28 try:
29 from crypt import crypt
30 except ImportError:
31 try:
32 from passlib.hash import des_crypt
33 except ImportError:
34 crypt = None
35 else:
37
38 if hasattr(des_crypt, 'hash'):
39 return des_crypt.using(salt=salt).hash(secret)
40 else:
41 return des_crypt.encrypt(secret, salt=salt)
42
43
44
45 all = all
46 any = any
47 frozenset = frozenset
48 reversed = reversed
49 set = set
50 sorted = sorted
51 from functools import partial
52 from hashlib import md5, sha1
53 from itertools import groupby, tee
57 """Use in templates as an alternative to `itertools.groupby`,
58 which leaks memory for Python < 2.5.3.
59
60 This class will be removed in Trac 1.3.1.
61 """
63 if key is None:
64 key = lambda x: x
65 self.keyfunc = key
66 self.it = iter(iterable)
67 self.tgtkey = self.currkey = self.currvalue = xrange(0)
71 while self.currkey == self.tgtkey:
72 self.currvalue = self.it.next()
73 self.currkey = self.keyfunc(self.currvalue)
74 self.tgtkey = self.currkey
75 return self.currkey, self._grouper(self.tgtkey)
77 while self.currkey == tgtkey:
78 yield self.currvalue
79 self.currvalue = self.it.next()
80 self.currkey = self.keyfunc(self.currvalue)
81
84
85
86
87 close_fds = os.name != 'nt'
91 """This function is typically called before a file save operation,
92 waiting if necessary for the file modification time to change. The
93 purpose is to avoid successive file updates going undetected by the
94 caching mechanism that depends on a change in the file modification
95 time to know when the file should be reparsed."""
96
97 from trac.util import touch_file
98 try:
99 mtime = os.stat(filename).st_mtime
100 touch_file(filename)
101 while mtime == os.stat(filename).st_mtime:
102 time.sleep(1e-3)
103 touch_file(filename)
104 except OSError as e:
105 if e.errno == errno.ENOENT:
106 pass
107 else:
108 raise
109
110
111 try:
112 from collections import OrderedDict
113 except ImportError:
114
115 try:
116 from thread import get_ident as _get_ident
117 except ImportError:
118 from dummy_thread import get_ident as _get_ident
121 'Dictionary that remembers insertion order'
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
139 """Initialize an ordered dictionary. Signature is the same
140 as for regular dictionaries, but keyword arguments are not
141 recommended because their insertion order is arbitrary.
142 """
143 if len(args) > 1:
144 raise TypeError('expected at most 1 arguments, got %d'
145 % len(args))
146 try:
147 self.__root
148 except AttributeError:
149 self.__root = root = []
150 root[:] = [root, root, None]
151 self.__map = {}
152 self.__update(*args, **kwds)
153
155 'od.__setitem__(i, y) <==> od[i]=y'
156
157
158
159
160 if key not in self:
161 root = self.__root
162 last = root[0]
163 last[1] = root[0] = self.__map[key] = [last, root, key]
164 dict_setitem(self, key, value)
165
166 - def __delitem__(self, key, dict_delitem=dict.__delitem__):
167 """od.__delitem__(y) <==> del od[y]"""
168
169
170
171 dict_delitem(self, key)
172 link_prev, link_next, key = self.__map.pop(key)
173 link_prev[1] = link_next
174 link_next[0] = link_prev
175
177 """od.__iter__() <==> iter(od)"""
178 root = self.__root
179 curr = root[1]
180 while curr is not root:
181 yield curr[2]
182 curr = curr[1]
183
185 """od.__reversed__() <==> reversed(od)"""
186 root = self.__root
187 curr = root[0]
188 while curr is not root:
189 yield curr[2]
190 curr = curr[0]
191
193 """od.clear() -> None. Remove all items from od."""
194 try:
195 for node in self.__map.itervalues():
196 del node[:]
197 root = self.__root
198 root[:] = [root, root, None]
199 self.__map.clear()
200 except AttributeError:
201 pass
202 dict.clear(self)
203
205 """od.popitem() -> (k, v), return and remove a (key, value)
206 pair. Pairs are returned in LIFO order if last is true or
207 FIFO order if false.
208 """
209 if not self:
210 raise KeyError('dictionary is empty')
211 root = self.__root
212 if last:
213 link = root[0]
214 link_prev = link[0]
215 link_prev[1] = root
216 root[0] = link_prev
217 else:
218 link = root[1]
219 link_next = link[1]
220 root[1] = link_next
221 link_next[0] = root
222 key = link[2]
223 del self.__map[key]
224 value = dict.pop(self, key)
225 return key, value
226
227
228
230 """od.keys() -> list of keys in od"""
231 return list(self)
232
234 """od.values() -> list of values in od"""
235 return [self[key] for key in self]
236
238 """od.items() -> list of (key, value) pairs in od"""
239 return [(key, self[key]) for key in self]
240
242 """od.iterkeys() -> an iterator over the keys in od"""
243 return iter(self)
244
246 """od.itervalues -> an iterator over the values in od"""
247 for k in self:
248 yield self[k]
249
251 """od.iteritems -> an iterator over the (key, value) items
252 in od
253 """
254 for k in self:
255 yield (k, self[k])
256
258 """od.update(E, **F) -> None. Update od from dict/iterable
259 E and F.
260
261 If E is a dict instance, does:
262 for k in E: od[k] = E[k]
263 If E has a .keys() method, does:
264 for k in E.keys(): od[k] = E[k]
265 Or if E is an iterable of items, does:
266 for k, v in E: od[k] = v
267 In either case, this is followed by:
268 for k, v in F.items(): od[k] = v
269 """
270 if len(args) > 2:
271 raise TypeError('update() takes at most 2 positional '
272 'arguments (%d given)' % (len(args),))
273 elif not args:
274 raise TypeError('update() takes at least 1 argument (0 given)')
275 self = args[0]
276
277 other = ()
278 if len(args) == 2:
279 other = args[1]
280 if isinstance(other, dict):
281 for key in other:
282 self[key] = other[key]
283 elif hasattr(other, 'keys'):
284 for key in other.keys():
285 self[key] = other[key]
286 else:
287 for key, value in other:
288 self[key] = value
289 for key, value in kwds.items():
290 self[key] = value
291
292
293 __update = update
294
295 __marker = object()
296
297 - def pop(self, key, default=__marker):
298 """od.pop(k[,d]) -> v, remove specified key and return the
299 corresponding value. If key is not found, d is returned if
300 given, otherwise KeyError is raised.
301 """
302 if key in self:
303 result = self[key]
304 del self[key]
305 return result
306 if default is self.__marker:
307 raise KeyError(key)
308 return default
309
311 """od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if
312 k not in od
313 """
314 if key in self:
315 return self[key]
316 self[key] = default
317 return default
318
320 """od.__repr__() <==> repr(od)"""
321 call_key = id(self), _get_ident()
322 if call_key in _repr_running:
323 return '...'
324 _repr_running[call_key] = 1
325 try:
326 if not self:
327 return '%s()' % (self.__class__.__name__,)
328 return '%s(%r)' % (self.__class__.__name__, self.items())
329 finally:
330 del _repr_running[call_key]
331
333 """Return state information for pickling"""
334 items = [[k, self[k]] for k in self]
335 inst_dict = vars(self).copy()
336 for k in vars(OrderedDict()):
337 inst_dict.pop(k, None)
338 if inst_dict:
339 return (self.__class__, (items,), inst_dict)
340 return self.__class__, (items,)
341
343 """od.copy() -> a shallow copy of od"""
344 return self.__class__(self)
345
346 @classmethod
347 - def fromkeys(cls, iterable, value=None):
348 """OD.fromkeys(S[, v]) -> New ordered dictionary with keys
349 from S and values equal to v (which defaults to None).
350 """
351 d = cls()
352 for key in iterable:
353 d[key] = value
354 return d
355
357 """od.__eq__(y) <==> od==y. Comparison to another OD is
358 order-sensitive while comparison to a regular mapping is
359 order-insensitive.
360 """
361 if isinstance(other, OrderedDict):
362 return len(self)==len(other) and self.items() == other.items()
363 return dict.__eq__(self, other)
364
366 return not self == other
367