##// END OF EJS Templates
Use unittest2 for testing
marcink -
r3872:2b9da874 beta
parent child Browse files
Show More
@@ -1,550 +1,554 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.compat
3 rhodecode.lib.compat
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 Python backward compatibility functions and common libs
6 Python backward compatibility functions and common libs
7
7
8
8
9 :created_on: Oct 7, 2011
9 :created_on: Oct 7, 2011
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2010 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2010 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26
26
27 import os
27 import os
28 from rhodecode import __py_version__, is_windows
28 from rhodecode import __py_version__, is_windows
29
29
30 #==============================================================================
30 #==============================================================================
31 # json
31 # json
32 #==============================================================================
32 #==============================================================================
33 from rhodecode.lib.ext_json import json
33 from rhodecode.lib.ext_json import json
34
34
35 if __py_version__ >= (2, 7):
36 import unittest
37 else:
38 import unittest2 as unittest
35
39
36 #==============================================================================
40 #==============================================================================
37 # izip_longest
41 # izip_longest
38 #==============================================================================
42 #==============================================================================
39 try:
43 try:
40 from itertools import izip_longest
44 from itertools import izip_longest
41 except ImportError:
45 except ImportError:
42 import itertools
46 import itertools
43
47
44 def izip_longest(*args, **kwds):
48 def izip_longest(*args, **kwds):
45 fillvalue = kwds.get("fillvalue")
49 fillvalue = kwds.get("fillvalue")
46
50
47 def sentinel(counter=([fillvalue] * (len(args) - 1)).pop):
51 def sentinel(counter=([fillvalue] * (len(args) - 1)).pop):
48 yield counter() # yields the fillvalue, or raises IndexError
52 yield counter() # yields the fillvalue, or raises IndexError
49
53
50 fillers = itertools.repeat(fillvalue)
54 fillers = itertools.repeat(fillvalue)
51 iters = [itertools.chain(it, sentinel(), fillers)
55 iters = [itertools.chain(it, sentinel(), fillers)
52 for it in args]
56 for it in args]
53 try:
57 try:
54 for tup in itertools.izip(*iters):
58 for tup in itertools.izip(*iters):
55 yield tup
59 yield tup
56 except IndexError:
60 except IndexError:
57 pass
61 pass
58
62
59
63
60 #==============================================================================
64 #==============================================================================
61 # OrderedDict
65 # OrderedDict
62 #==============================================================================
66 #==============================================================================
63
67
64 # Python Software Foundation License
68 # Python Software Foundation License
65
69
66 # XXX: it feels like using the class with "is" and "is not" instead of "==" and
70 # XXX: it feels like using the class with "is" and "is not" instead of "==" and
67 # "!=" should be faster.
71 # "!=" should be faster.
68 class _Nil(object):
72 class _Nil(object):
69
73
70 def __repr__(self):
74 def __repr__(self):
71 return "nil"
75 return "nil"
72
76
73 def __eq__(self, other):
77 def __eq__(self, other):
74 if (isinstance(other, _Nil)):
78 if (isinstance(other, _Nil)):
75 return True
79 return True
76 else:
80 else:
77 return NotImplemented
81 return NotImplemented
78
82
79 def __ne__(self, other):
83 def __ne__(self, other):
80 if (isinstance(other, _Nil)):
84 if (isinstance(other, _Nil)):
81 return False
85 return False
82 else:
86 else:
83 return NotImplemented
87 return NotImplemented
84
88
85 _nil = _Nil()
89 _nil = _Nil()
86
90
87
91
88 class _odict(object):
92 class _odict(object):
89 """Ordered dict data structure, with O(1) complexity for dict operations
93 """Ordered dict data structure, with O(1) complexity for dict operations
90 that modify one element.
94 that modify one element.
91
95
92 Overwriting values doesn't change their original sequential order.
96 Overwriting values doesn't change their original sequential order.
93 """
97 """
94
98
95 def _dict_impl(self):
99 def _dict_impl(self):
96 return None
100 return None
97
101
98 def __init__(self, data=(), **kwds):
102 def __init__(self, data=(), **kwds):
99 """This doesn't accept keyword initialization as normal dicts to avoid
103 """This doesn't accept keyword initialization as normal dicts to avoid
100 a trap - inside a function or method the keyword args are accessible
104 a trap - inside a function or method the keyword args are accessible
101 only as a dict, without a defined order, so their original order is
105 only as a dict, without a defined order, so their original order is
102 lost.
106 lost.
103 """
107 """
104 if kwds:
108 if kwds:
105 raise TypeError("__init__() of ordered dict takes no keyword "
109 raise TypeError("__init__() of ordered dict takes no keyword "
106 "arguments to avoid an ordering trap.")
110 "arguments to avoid an ordering trap.")
107 self._dict_impl().__init__(self)
111 self._dict_impl().__init__(self)
108 # If you give a normal dict, then the order of elements is undefined
112 # If you give a normal dict, then the order of elements is undefined
109 if hasattr(data, "iteritems"):
113 if hasattr(data, "iteritems"):
110 for key, val in data.iteritems():
114 for key, val in data.iteritems():
111 self[key] = val
115 self[key] = val
112 else:
116 else:
113 for key, val in data:
117 for key, val in data:
114 self[key] = val
118 self[key] = val
115
119
116 # Double-linked list header
120 # Double-linked list header
117 def _get_lh(self):
121 def _get_lh(self):
118 dict_impl = self._dict_impl()
122 dict_impl = self._dict_impl()
119 if not hasattr(self, '_lh'):
123 if not hasattr(self, '_lh'):
120 dict_impl.__setattr__(self, '_lh', _nil)
124 dict_impl.__setattr__(self, '_lh', _nil)
121 return dict_impl.__getattribute__(self, '_lh')
125 return dict_impl.__getattribute__(self, '_lh')
122
126
123 def _set_lh(self, val):
127 def _set_lh(self, val):
124 self._dict_impl().__setattr__(self, '_lh', val)
128 self._dict_impl().__setattr__(self, '_lh', val)
125
129
126 lh = property(_get_lh, _set_lh)
130 lh = property(_get_lh, _set_lh)
127
131
128 # Double-linked list tail
132 # Double-linked list tail
129 def _get_lt(self):
133 def _get_lt(self):
130 dict_impl = self._dict_impl()
134 dict_impl = self._dict_impl()
131 if not hasattr(self, '_lt'):
135 if not hasattr(self, '_lt'):
132 dict_impl.__setattr__(self, '_lt', _nil)
136 dict_impl.__setattr__(self, '_lt', _nil)
133 return dict_impl.__getattribute__(self, '_lt')
137 return dict_impl.__getattribute__(self, '_lt')
134
138
135 def _set_lt(self, val):
139 def _set_lt(self, val):
136 self._dict_impl().__setattr__(self, '_lt', val)
140 self._dict_impl().__setattr__(self, '_lt', val)
137
141
138 lt = property(_get_lt, _set_lt)
142 lt = property(_get_lt, _set_lt)
139
143
140 def __getitem__(self, key):
144 def __getitem__(self, key):
141 return self._dict_impl().__getitem__(self, key)[1]
145 return self._dict_impl().__getitem__(self, key)[1]
142
146
143 def __setitem__(self, key, val):
147 def __setitem__(self, key, val):
144 dict_impl = self._dict_impl()
148 dict_impl = self._dict_impl()
145 try:
149 try:
146 dict_impl.__getitem__(self, key)[1] = val
150 dict_impl.__getitem__(self, key)[1] = val
147 except KeyError:
151 except KeyError:
148 new = [dict_impl.__getattribute__(self, 'lt'), val, _nil]
152 new = [dict_impl.__getattribute__(self, 'lt'), val, _nil]
149 dict_impl.__setitem__(self, key, new)
153 dict_impl.__setitem__(self, key, new)
150 if dict_impl.__getattribute__(self, 'lt') == _nil:
154 if dict_impl.__getattribute__(self, 'lt') == _nil:
151 dict_impl.__setattr__(self, 'lh', key)
155 dict_impl.__setattr__(self, 'lh', key)
152 else:
156 else:
153 dict_impl.__getitem__(
157 dict_impl.__getitem__(
154 self, dict_impl.__getattribute__(self, 'lt'))[2] = key
158 self, dict_impl.__getattribute__(self, 'lt'))[2] = key
155 dict_impl.__setattr__(self, 'lt', key)
159 dict_impl.__setattr__(self, 'lt', key)
156
160
157 def __delitem__(self, key):
161 def __delitem__(self, key):
158 dict_impl = self._dict_impl()
162 dict_impl = self._dict_impl()
159 pred, _, succ = self._dict_impl().__getitem__(self, key)
163 pred, _, succ = self._dict_impl().__getitem__(self, key)
160 if pred == _nil:
164 if pred == _nil:
161 dict_impl.__setattr__(self, 'lh', succ)
165 dict_impl.__setattr__(self, 'lh', succ)
162 else:
166 else:
163 dict_impl.__getitem__(self, pred)[2] = succ
167 dict_impl.__getitem__(self, pred)[2] = succ
164 if succ == _nil:
168 if succ == _nil:
165 dict_impl.__setattr__(self, 'lt', pred)
169 dict_impl.__setattr__(self, 'lt', pred)
166 else:
170 else:
167 dict_impl.__getitem__(self, succ)[0] = pred
171 dict_impl.__getitem__(self, succ)[0] = pred
168 dict_impl.__delitem__(self, key)
172 dict_impl.__delitem__(self, key)
169
173
170 def __contains__(self, key):
174 def __contains__(self, key):
171 return key in self.keys()
175 return key in self.keys()
172
176
173 def __len__(self):
177 def __len__(self):
174 return len(self.keys())
178 return len(self.keys())
175
179
176 def __str__(self):
180 def __str__(self):
177 pairs = ("%r: %r" % (k, v) for k, v in self.iteritems())
181 pairs = ("%r: %r" % (k, v) for k, v in self.iteritems())
178 return "{%s}" % ", ".join(pairs)
182 return "{%s}" % ", ".join(pairs)
179
183
180 def __repr__(self):
184 def __repr__(self):
181 if self:
185 if self:
182 pairs = ("(%r, %r)" % (k, v) for k, v in self.iteritems())
186 pairs = ("(%r, %r)" % (k, v) for k, v in self.iteritems())
183 return "odict([%s])" % ", ".join(pairs)
187 return "odict([%s])" % ", ".join(pairs)
184 else:
188 else:
185 return "odict()"
189 return "odict()"
186
190
187 def get(self, k, x=None):
191 def get(self, k, x=None):
188 if k in self:
192 if k in self:
189 return self._dict_impl().__getitem__(self, k)[1]
193 return self._dict_impl().__getitem__(self, k)[1]
190 else:
194 else:
191 return x
195 return x
192
196
193 def __iter__(self):
197 def __iter__(self):
194 dict_impl = self._dict_impl()
198 dict_impl = self._dict_impl()
195 curr_key = dict_impl.__getattribute__(self, 'lh')
199 curr_key = dict_impl.__getattribute__(self, 'lh')
196 while curr_key != _nil:
200 while curr_key != _nil:
197 yield curr_key
201 yield curr_key
198 curr_key = dict_impl.__getitem__(self, curr_key)[2]
202 curr_key = dict_impl.__getitem__(self, curr_key)[2]
199
203
200 iterkeys = __iter__
204 iterkeys = __iter__
201
205
202 def keys(self):
206 def keys(self):
203 return list(self.iterkeys())
207 return list(self.iterkeys())
204
208
205 def itervalues(self):
209 def itervalues(self):
206 dict_impl = self._dict_impl()
210 dict_impl = self._dict_impl()
207 curr_key = dict_impl.__getattribute__(self, 'lh')
211 curr_key = dict_impl.__getattribute__(self, 'lh')
208 while curr_key != _nil:
212 while curr_key != _nil:
209 _, val, curr_key = dict_impl.__getitem__(self, curr_key)
213 _, val, curr_key = dict_impl.__getitem__(self, curr_key)
210 yield val
214 yield val
211
215
212 def values(self):
216 def values(self):
213 return list(self.itervalues())
217 return list(self.itervalues())
214
218
215 def iteritems(self):
219 def iteritems(self):
216 dict_impl = self._dict_impl()
220 dict_impl = self._dict_impl()
217 curr_key = dict_impl.__getattribute__(self, 'lh')
221 curr_key = dict_impl.__getattribute__(self, 'lh')
218 while curr_key != _nil:
222 while curr_key != _nil:
219 _, val, next_key = dict_impl.__getitem__(self, curr_key)
223 _, val, next_key = dict_impl.__getitem__(self, curr_key)
220 yield curr_key, val
224 yield curr_key, val
221 curr_key = next_key
225 curr_key = next_key
222
226
223 def items(self):
227 def items(self):
224 return list(self.iteritems())
228 return list(self.iteritems())
225
229
226 def sort(self, cmp=None, key=None, reverse=False):
230 def sort(self, cmp=None, key=None, reverse=False):
227 items = [(k, v) for k, v in self.items()]
231 items = [(k, v) for k, v in self.items()]
228 if cmp is not None:
232 if cmp is not None:
229 items = sorted(items, cmp=cmp)
233 items = sorted(items, cmp=cmp)
230 elif key is not None:
234 elif key is not None:
231 items = sorted(items, key=key)
235 items = sorted(items, key=key)
232 else:
236 else:
233 items = sorted(items, key=lambda x: x[1])
237 items = sorted(items, key=lambda x: x[1])
234 if reverse:
238 if reverse:
235 items.reverse()
239 items.reverse()
236 self.clear()
240 self.clear()
237 self.__init__(items)
241 self.__init__(items)
238
242
239 def clear(self):
243 def clear(self):
240 dict_impl = self._dict_impl()
244 dict_impl = self._dict_impl()
241 dict_impl.clear(self)
245 dict_impl.clear(self)
242 dict_impl.__setattr__(self, 'lh', _nil)
246 dict_impl.__setattr__(self, 'lh', _nil)
243 dict_impl.__setattr__(self, 'lt', _nil)
247 dict_impl.__setattr__(self, 'lt', _nil)
244
248
245 def copy(self):
249 def copy(self):
246 return self.__class__(self)
250 return self.__class__(self)
247
251
248 def update(self, data=(), **kwds):
252 def update(self, data=(), **kwds):
249 if kwds:
253 if kwds:
250 raise TypeError("update() of ordered dict takes no keyword "
254 raise TypeError("update() of ordered dict takes no keyword "
251 "arguments to avoid an ordering trap.")
255 "arguments to avoid an ordering trap.")
252 if hasattr(data, "iteritems"):
256 if hasattr(data, "iteritems"):
253 data = data.iteritems()
257 data = data.iteritems()
254 for key, val in data:
258 for key, val in data:
255 self[key] = val
259 self[key] = val
256
260
257 def setdefault(self, k, x=None):
261 def setdefault(self, k, x=None):
258 try:
262 try:
259 return self[k]
263 return self[k]
260 except KeyError:
264 except KeyError:
261 self[k] = x
265 self[k] = x
262 return x
266 return x
263
267
264 def pop(self, k, x=_nil):
268 def pop(self, k, x=_nil):
265 try:
269 try:
266 val = self[k]
270 val = self[k]
267 del self[k]
271 del self[k]
268 return val
272 return val
269 except KeyError:
273 except KeyError:
270 if x == _nil:
274 if x == _nil:
271 raise
275 raise
272 return x
276 return x
273
277
274 def popitem(self):
278 def popitem(self):
275 try:
279 try:
276 dict_impl = self._dict_impl()
280 dict_impl = self._dict_impl()
277 key = dict_impl.__getattribute__(self, 'lt')
281 key = dict_impl.__getattribute__(self, 'lt')
278 return key, self.pop(key)
282 return key, self.pop(key)
279 except KeyError:
283 except KeyError:
280 raise KeyError("'popitem(): ordered dictionary is empty'")
284 raise KeyError("'popitem(): ordered dictionary is empty'")
281
285
282 def riterkeys(self):
286 def riterkeys(self):
283 """To iterate on keys in reversed order.
287 """To iterate on keys in reversed order.
284 """
288 """
285 dict_impl = self._dict_impl()
289 dict_impl = self._dict_impl()
286 curr_key = dict_impl.__getattribute__(self, 'lt')
290 curr_key = dict_impl.__getattribute__(self, 'lt')
287 while curr_key != _nil:
291 while curr_key != _nil:
288 yield curr_key
292 yield curr_key
289 curr_key = dict_impl.__getitem__(self, curr_key)[0]
293 curr_key = dict_impl.__getitem__(self, curr_key)[0]
290
294
291 __reversed__ = riterkeys
295 __reversed__ = riterkeys
292
296
293 def rkeys(self):
297 def rkeys(self):
294 """List of the keys in reversed order.
298 """List of the keys in reversed order.
295 """
299 """
296 return list(self.riterkeys())
300 return list(self.riterkeys())
297
301
298 def ritervalues(self):
302 def ritervalues(self):
299 """To iterate on values in reversed order.
303 """To iterate on values in reversed order.
300 """
304 """
301 dict_impl = self._dict_impl()
305 dict_impl = self._dict_impl()
302 curr_key = dict_impl.__getattribute__(self, 'lt')
306 curr_key = dict_impl.__getattribute__(self, 'lt')
303 while curr_key != _nil:
307 while curr_key != _nil:
304 curr_key, val, _ = dict_impl.__getitem__(self, curr_key)
308 curr_key, val, _ = dict_impl.__getitem__(self, curr_key)
305 yield val
309 yield val
306
310
307 def rvalues(self):
311 def rvalues(self):
308 """List of the values in reversed order.
312 """List of the values in reversed order.
309 """
313 """
310 return list(self.ritervalues())
314 return list(self.ritervalues())
311
315
312 def riteritems(self):
316 def riteritems(self):
313 """To iterate on (key, value) in reversed order.
317 """To iterate on (key, value) in reversed order.
314 """
318 """
315 dict_impl = self._dict_impl()
319 dict_impl = self._dict_impl()
316 curr_key = dict_impl.__getattribute__(self, 'lt')
320 curr_key = dict_impl.__getattribute__(self, 'lt')
317 while curr_key != _nil:
321 while curr_key != _nil:
318 pred_key, val, _ = dict_impl.__getitem__(self, curr_key)
322 pred_key, val, _ = dict_impl.__getitem__(self, curr_key)
319 yield curr_key, val
323 yield curr_key, val
320 curr_key = pred_key
324 curr_key = pred_key
321
325
322 def ritems(self):
326 def ritems(self):
323 """List of the (key, value) in reversed order.
327 """List of the (key, value) in reversed order.
324 """
328 """
325 return list(self.riteritems())
329 return list(self.riteritems())
326
330
327 def firstkey(self):
331 def firstkey(self):
328 if self:
332 if self:
329 return self._dict_impl().__getattribute__(self, 'lh')
333 return self._dict_impl().__getattribute__(self, 'lh')
330 else:
334 else:
331 raise KeyError("'firstkey(): ordered dictionary is empty'")
335 raise KeyError("'firstkey(): ordered dictionary is empty'")
332
336
333 def lastkey(self):
337 def lastkey(self):
334 if self:
338 if self:
335 return self._dict_impl().__getattribute__(self, 'lt')
339 return self._dict_impl().__getattribute__(self, 'lt')
336 else:
340 else:
337 raise KeyError("'lastkey(): ordered dictionary is empty'")
341 raise KeyError("'lastkey(): ordered dictionary is empty'")
338
342
339 def as_dict(self):
343 def as_dict(self):
340 return self._dict_impl()(self.items())
344 return self._dict_impl()(self.items())
341
345
342 def _repr(self):
346 def _repr(self):
343 """_repr(): low level repr of the whole data contained in the odict.
347 """_repr(): low level repr of the whole data contained in the odict.
344 Useful for debugging.
348 Useful for debugging.
345 """
349 """
346 dict_impl = self._dict_impl()
350 dict_impl = self._dict_impl()
347 form = "odict low level repr lh,lt,data: %r, %r, %s"
351 form = "odict low level repr lh,lt,data: %r, %r, %s"
348 return form % (dict_impl.__getattribute__(self, 'lh'),
352 return form % (dict_impl.__getattribute__(self, 'lh'),
349 dict_impl.__getattribute__(self, 'lt'),
353 dict_impl.__getattribute__(self, 'lt'),
350 dict_impl.__repr__(self))
354 dict_impl.__repr__(self))
351
355
352
356
353 class OrderedDict(_odict, dict):
357 class OrderedDict(_odict, dict):
354
358
355 def _dict_impl(self):
359 def _dict_impl(self):
356 return dict
360 return dict
357
361
358
362
359 #==============================================================================
363 #==============================================================================
360 # OrderedSet
364 # OrderedSet
361 #==============================================================================
365 #==============================================================================
362 from sqlalchemy.util import OrderedSet
366 from sqlalchemy.util import OrderedSet
363
367
364
368
365 #==============================================================================
369 #==============================================================================
366 # kill FUNCTIONS
370 # kill FUNCTIONS
367 #==============================================================================
371 #==============================================================================
368 if is_windows:
372 if is_windows:
369 import ctypes
373 import ctypes
370
374
371 def kill(pid, sig):
375 def kill(pid, sig):
372 """kill function for Win32"""
376 """kill function for Win32"""
373 kernel32 = ctypes.windll.kernel32
377 kernel32 = ctypes.windll.kernel32
374 handle = kernel32.OpenProcess(1, 0, pid)
378 handle = kernel32.OpenProcess(1, 0, pid)
375 return (0 != kernel32.TerminateProcess(handle, 0))
379 return (0 != kernel32.TerminateProcess(handle, 0))
376
380
377 else:
381 else:
378 kill = os.kill
382 kill = os.kill
379
383
380
384
381 #==============================================================================
385 #==============================================================================
382 # itertools.product
386 # itertools.product
383 #==============================================================================
387 #==============================================================================
384
388
385 try:
389 try:
386 from itertools import product
390 from itertools import product
387 except ImportError:
391 except ImportError:
388 def product(*args, **kwds):
392 def product(*args, **kwds):
389 # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
393 # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
390 # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
394 # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
391 pools = map(tuple, args) * kwds.get('repeat', 1)
395 pools = map(tuple, args) * kwds.get('repeat', 1)
392 result = [[]]
396 result = [[]]
393 for pool in pools:
397 for pool in pools:
394 result = [x + [y] for x in result for y in pool]
398 result = [x + [y] for x in result for y in pool]
395 for prod in result:
399 for prod in result:
396 yield tuple(prod)
400 yield tuple(prod)
397
401
398
402
399 #==============================================================================
403 #==============================================================================
400 # BytesIO
404 # BytesIO
401 #==============================================================================
405 #==============================================================================
402
406
403 try:
407 try:
404 from io import BytesIO
408 from io import BytesIO
405 except ImportError:
409 except ImportError:
406 from cStringIO import StringIO as BytesIO
410 from cStringIO import StringIO as BytesIO
407
411
408
412
409 #==============================================================================
413 #==============================================================================
410 # bytes
414 # bytes
411 #==============================================================================
415 #==============================================================================
412 if __py_version__ >= (2, 6):
416 if __py_version__ >= (2, 6):
413 _bytes = bytes
417 _bytes = bytes
414 else:
418 else:
415 # in py2.6 bytes is a synonim for str
419 # in py2.6 bytes is a synonim for str
416 _bytes = str
420 _bytes = str
417
421
418 if __py_version__ >= (2, 6):
422 if __py_version__ >= (2, 6):
419 _bytearray = bytearray
423 _bytearray = bytearray
420 else:
424 else:
421 import array
425 import array
422 # no idea if this is correct but all integration tests are passing
426 # no idea if this is correct but all integration tests are passing
423 # i think we never use bytearray anyway
427 # i think we never use bytearray anyway
424 _bytearray = array
428 _bytearray = array
425
429
426
430
427 #==============================================================================
431 #==============================================================================
428 # deque
432 # deque
429 #==============================================================================
433 #==============================================================================
430
434
431 if __py_version__ >= (2, 6):
435 if __py_version__ >= (2, 6):
432 from collections import deque
436 from collections import deque
433 else:
437 else:
434 #need to implement our own deque with maxlen
438 #need to implement our own deque with maxlen
435 class deque(object):
439 class deque(object):
436
440
437 def __init__(self, iterable=(), maxlen= -1):
441 def __init__(self, iterable=(), maxlen= -1):
438 if not hasattr(self, 'data'):
442 if not hasattr(self, 'data'):
439 self.left = self.right = 0
443 self.left = self.right = 0
440 self.data = {}
444 self.data = {}
441 self.maxlen = maxlen or -1
445 self.maxlen = maxlen or -1
442 self.extend(iterable)
446 self.extend(iterable)
443
447
444 def append(self, x):
448 def append(self, x):
445 self.data[self.right] = x
449 self.data[self.right] = x
446 self.right += 1
450 self.right += 1
447 if self.maxlen != -1 and len(self) > self.maxlen:
451 if self.maxlen != -1 and len(self) > self.maxlen:
448 self.popleft()
452 self.popleft()
449
453
450 def appendleft(self, x):
454 def appendleft(self, x):
451 self.left -= 1
455 self.left -= 1
452 self.data[self.left] = x
456 self.data[self.left] = x
453 if self.maxlen != -1 and len(self) > self.maxlen:
457 if self.maxlen != -1 and len(self) > self.maxlen:
454 self.pop()
458 self.pop()
455
459
456 def pop(self):
460 def pop(self):
457 if self.left == self.right:
461 if self.left == self.right:
458 raise IndexError('cannot pop from empty deque')
462 raise IndexError('cannot pop from empty deque')
459 self.right -= 1
463 self.right -= 1
460 elem = self.data[self.right]
464 elem = self.data[self.right]
461 del self.data[self.right]
465 del self.data[self.right]
462 return elem
466 return elem
463
467
464 def popleft(self):
468 def popleft(self):
465 if self.left == self.right:
469 if self.left == self.right:
466 raise IndexError('cannot pop from empty deque')
470 raise IndexError('cannot pop from empty deque')
467 elem = self.data[self.left]
471 elem = self.data[self.left]
468 del self.data[self.left]
472 del self.data[self.left]
469 self.left += 1
473 self.left += 1
470 return elem
474 return elem
471
475
472 def clear(self):
476 def clear(self):
473 self.data.clear()
477 self.data.clear()
474 self.left = self.right = 0
478 self.left = self.right = 0
475
479
476 def extend(self, iterable):
480 def extend(self, iterable):
477 for elem in iterable:
481 for elem in iterable:
478 self.append(elem)
482 self.append(elem)
479
483
480 def extendleft(self, iterable):
484 def extendleft(self, iterable):
481 for elem in iterable:
485 for elem in iterable:
482 self.appendleft(elem)
486 self.appendleft(elem)
483
487
484 def rotate(self, n=1):
488 def rotate(self, n=1):
485 if self:
489 if self:
486 n %= len(self)
490 n %= len(self)
487 for i in xrange(n):
491 for i in xrange(n):
488 self.appendleft(self.pop())
492 self.appendleft(self.pop())
489
493
490 def __getitem__(self, i):
494 def __getitem__(self, i):
491 if i < 0:
495 if i < 0:
492 i += len(self)
496 i += len(self)
493 try:
497 try:
494 return self.data[i + self.left]
498 return self.data[i + self.left]
495 except KeyError:
499 except KeyError:
496 raise IndexError
500 raise IndexError
497
501
498 def __setitem__(self, i, value):
502 def __setitem__(self, i, value):
499 if i < 0:
503 if i < 0:
500 i += len(self)
504 i += len(self)
501 try:
505 try:
502 self.data[i + self.left] = value
506 self.data[i + self.left] = value
503 except KeyError:
507 except KeyError:
504 raise IndexError
508 raise IndexError
505
509
506 def __delitem__(self, i):
510 def __delitem__(self, i):
507 size = len(self)
511 size = len(self)
508 if not (-size <= i < size):
512 if not (-size <= i < size):
509 raise IndexError
513 raise IndexError
510 data = self.data
514 data = self.data
511 if i < 0:
515 if i < 0:
512 i += size
516 i += size
513 for j in xrange(self.left + i, self.right - 1):
517 for j in xrange(self.left + i, self.right - 1):
514 data[j] = data[j + 1]
518 data[j] = data[j + 1]
515 self.pop()
519 self.pop()
516
520
517 def __len__(self):
521 def __len__(self):
518 return self.right - self.left
522 return self.right - self.left
519
523
520 def __cmp__(self, other):
524 def __cmp__(self, other):
521 if type(self) != type(other):
525 if type(self) != type(other):
522 return cmp(type(self), type(other))
526 return cmp(type(self), type(other))
523 return cmp(list(self), list(other))
527 return cmp(list(self), list(other))
524
528
525 def __repr__(self, _track=[]):
529 def __repr__(self, _track=[]):
526 if id(self) in _track:
530 if id(self) in _track:
527 return '...'
531 return '...'
528 _track.append(id(self))
532 _track.append(id(self))
529 r = 'deque(%r, maxlen=%s)' % (list(self), self.maxlen)
533 r = 'deque(%r, maxlen=%s)' % (list(self), self.maxlen)
530 _track.remove(id(self))
534 _track.remove(id(self))
531 return r
535 return r
532
536
533 def __getstate__(self):
537 def __getstate__(self):
534 return (tuple(self),)
538 return (tuple(self),)
535
539
536 def __setstate__(self, s):
540 def __setstate__(self, s):
537 self.__init__(s[0])
541 self.__init__(s[0])
538
542
539 def __hash__(self):
543 def __hash__(self):
540 raise TypeError
544 raise TypeError
541
545
542 def __copy__(self):
546 def __copy__(self):
543 return self.__class__(self)
547 return self.__class__(self)
544
548
545 def __deepcopy__(self, memo={}):
549 def __deepcopy__(self, memo={}):
546 from copy import deepcopy
550 from copy import deepcopy
547 result = self.__class__()
551 result = self.__class__()
548 memo[id(self)] = result
552 memo[id(self)] = result
549 result.__init__(deepcopy(tuple(self), memo))
553 result.__init__(deepcopy(tuple(self), memo))
550 return result
554 return result
@@ -1,202 +1,202 b''
1 """Pylons application test package
1 """Pylons application test package
2
2
3 This package assumes the Pylons environment is already loaded, such as
3 This package assumes the Pylons environment is already loaded, such as
4 when this script is imported from the `nosetests --with-pylons=test.ini`
4 when this script is imported from the `nosetests --with-pylons=test.ini`
5 command.
5 command.
6
6
7 This module initializes the application via ``websetup`` (`paster
7 This module initializes the application via ``websetup`` (`paster
8 setup-app`) and provides the base testing objects.
8 setup-app`) and provides the base testing objects.
9
9
10 nosetests -x - fail on first error
10 nosetests -x - fail on first error
11 nosetests rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
11 nosetests rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
12 nosetests --pdb --pdb-failures
12 nosetests --pdb --pdb-failures
13 nosetests --with-coverage --cover-package=rhodecode.model.validators rhodecode.tests.test_validators
13 nosetests --with-coverage --cover-package=rhodecode.model.validators rhodecode.tests.test_validators
14
14
15 optional FLAGS:
15 optional FLAGS:
16 RC_WHOOSH_TEST_DISABLE=1 - skip whoosh index building and tests
16 RC_WHOOSH_TEST_DISABLE=1 - skip whoosh index building and tests
17 RC_NO_TMP_PATH=1 - disable new temp path for tests, used mostly for test_vcs_operations
17 RC_NO_TMP_PATH=1 - disable new temp path for tests, used mostly for test_vcs_operations
18
18
19 """
19 """
20 import os
20 import os
21 import time
21 import time
22 import logging
22 import logging
23 import datetime
23 import datetime
24 import hashlib
24 import hashlib
25 import tempfile
25 import tempfile
26 from os.path import join as jn
26 from os.path import join as jn
27
27
28 from unittest import TestCase
29 from tempfile import _RandomNameSequence
28 from tempfile import _RandomNameSequence
30
29
31 from paste.deploy import loadapp
30 from paste.deploy import loadapp
32 from paste.script.appinstall import SetupCommand
31 from paste.script.appinstall import SetupCommand
33
32
34 import pylons
33 import pylons
35 import pylons.test
34 import pylons.test
36 from pylons import config, url
35 from pylons import config, url
37 from pylons.i18n.translation import _get_translator
36 from pylons.i18n.translation import _get_translator
38 from pylons.util import ContextObj
37 from pylons.util import ContextObj
39
38
40 from routes.util import URLGenerator
39 from routes.util import URLGenerator
41 from webtest import TestApp
40 from webtest import TestApp
42 from nose.plugins.skip import SkipTest
41 from nose.plugins.skip import SkipTest
43
42
43 from rhodecode.lib.compat import unittest
44 from rhodecode import is_windows
44 from rhodecode import is_windows
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.db import User
46 from rhodecode.model.db import User
47 from rhodecode.tests.nose_parametrized import parameterized
47 from rhodecode.tests.nose_parametrized import parameterized
48 from rhodecode.lib.utils2 import safe_unicode, safe_str
48 from rhodecode.lib.utils2 import safe_unicode, safe_str
49
49
50
50
51 os.environ['TZ'] = 'UTC'
51 os.environ['TZ'] = 'UTC'
52 if not is_windows:
52 if not is_windows:
53 time.tzset()
53 time.tzset()
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57 __all__ = [
57 __all__ = [
58 'parameterized', 'environ', 'url', 'get_new_dir', 'TestController',
58 'parameterized', 'environ', 'url', 'get_new_dir', 'TestController',
59 'SkipTest', 'ldap_lib_installed', 'BaseTestCase', 'init_stack',
59 'SkipTest', 'ldap_lib_installed', 'BaseTestCase', 'init_stack',
60 'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO',
60 'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO',
61 'HG_FORK', 'GIT_FORK', 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS',
61 'HG_FORK', 'GIT_FORK', 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS',
62 'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS',
62 'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS',
63 'TEST_USER_REGULAR_EMAIL', 'TEST_USER_REGULAR2_LOGIN',
63 'TEST_USER_REGULAR_EMAIL', 'TEST_USER_REGULAR2_LOGIN',
64 'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO',
64 'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO',
65 'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO',
65 'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO',
66 'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'HG_REMOTE_REPO',
66 'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'HG_REMOTE_REPO',
67 'GIT_REMOTE_REPO', 'SCM_TESTS',
67 'GIT_REMOTE_REPO', 'SCM_TESTS',
68 ]
68 ]
69
69
70 # Invoke websetup with the current config file
70 # Invoke websetup with the current config file
71 # SetupCommand('setup-app').run([config_file])
71 # SetupCommand('setup-app').run([config_file])
72
72
73 environ = {}
73 environ = {}
74
74
75 #SOME GLOBALS FOR TESTS
75 #SOME GLOBALS FOR TESTS
76
76
77 TESTS_TMP_PATH = jn('/', 'tmp', 'rc_test_%s' % _RandomNameSequence().next())
77 TESTS_TMP_PATH = jn('/', 'tmp', 'rc_test_%s' % _RandomNameSequence().next())
78 TEST_USER_ADMIN_LOGIN = 'test_admin'
78 TEST_USER_ADMIN_LOGIN = 'test_admin'
79 TEST_USER_ADMIN_PASS = 'test12'
79 TEST_USER_ADMIN_PASS = 'test12'
80 TEST_USER_ADMIN_EMAIL = 'test_admin@mail.com'
80 TEST_USER_ADMIN_EMAIL = 'test_admin@mail.com'
81
81
82 TEST_USER_REGULAR_LOGIN = 'test_regular'
82 TEST_USER_REGULAR_LOGIN = 'test_regular'
83 TEST_USER_REGULAR_PASS = 'test12'
83 TEST_USER_REGULAR_PASS = 'test12'
84 TEST_USER_REGULAR_EMAIL = 'test_regular@mail.com'
84 TEST_USER_REGULAR_EMAIL = 'test_regular@mail.com'
85
85
86 TEST_USER_REGULAR2_LOGIN = 'test_regular2'
86 TEST_USER_REGULAR2_LOGIN = 'test_regular2'
87 TEST_USER_REGULAR2_PASS = 'test12'
87 TEST_USER_REGULAR2_PASS = 'test12'
88 TEST_USER_REGULAR2_EMAIL = 'test_regular2@mail.com'
88 TEST_USER_REGULAR2_EMAIL = 'test_regular2@mail.com'
89
89
90 HG_REPO = 'vcs_test_hg'
90 HG_REPO = 'vcs_test_hg'
91 GIT_REPO = 'vcs_test_git'
91 GIT_REPO = 'vcs_test_git'
92
92
93 NEW_HG_REPO = 'vcs_test_hg_new'
93 NEW_HG_REPO = 'vcs_test_hg_new'
94 NEW_GIT_REPO = 'vcs_test_git_new'
94 NEW_GIT_REPO = 'vcs_test_git_new'
95
95
96 HG_FORK = 'vcs_test_hg_fork'
96 HG_FORK = 'vcs_test_hg_fork'
97 GIT_FORK = 'vcs_test_git_fork'
97 GIT_FORK = 'vcs_test_git_fork'
98
98
99 ## VCS
99 ## VCS
100 SCM_TESTS = ['hg', 'git']
100 SCM_TESTS = ['hg', 'git']
101 uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
101 uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
102
102
103 GIT_REMOTE_REPO = 'git://github.com/codeinn/vcs.git'
103 GIT_REMOTE_REPO = 'git://github.com/codeinn/vcs.git'
104
104
105 TEST_GIT_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
105 TEST_GIT_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
106 TEST_GIT_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcsgitclone%s' % uniq_suffix)
106 TEST_GIT_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcsgitclone%s' % uniq_suffix)
107 TEST_GIT_REPO_PULL = jn(TESTS_TMP_PATH, 'vcsgitpull%s' % uniq_suffix)
107 TEST_GIT_REPO_PULL = jn(TESTS_TMP_PATH, 'vcsgitpull%s' % uniq_suffix)
108
108
109
109
110 HG_REMOTE_REPO = 'http://bitbucket.org/marcinkuzminski/vcs'
110 HG_REMOTE_REPO = 'http://bitbucket.org/marcinkuzminski/vcs'
111
111
112 TEST_HG_REPO = jn(TESTS_TMP_PATH, HG_REPO)
112 TEST_HG_REPO = jn(TESTS_TMP_PATH, HG_REPO)
113 TEST_HG_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcshgclone%s' % uniq_suffix)
113 TEST_HG_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcshgclone%s' % uniq_suffix)
114 TEST_HG_REPO_PULL = jn(TESTS_TMP_PATH, 'vcshgpull%s' % uniq_suffix)
114 TEST_HG_REPO_PULL = jn(TESTS_TMP_PATH, 'vcshgpull%s' % uniq_suffix)
115
115
116 TEST_DIR = tempfile.gettempdir()
116 TEST_DIR = tempfile.gettempdir()
117 TEST_REPO_PREFIX = 'vcs-test'
117 TEST_REPO_PREFIX = 'vcs-test'
118
118
119 # cached repos if any !
119 # cached repos if any !
120 # comment out to get some other repos from bb or github
120 # comment out to get some other repos from bb or github
121 GIT_REMOTE_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
121 GIT_REMOTE_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
122 HG_REMOTE_REPO = jn(TESTS_TMP_PATH, HG_REPO)
122 HG_REMOTE_REPO = jn(TESTS_TMP_PATH, HG_REPO)
123
123
124 #skip ldap tests if LDAP lib is not installed
124 #skip ldap tests if LDAP lib is not installed
125 ldap_lib_installed = False
125 ldap_lib_installed = False
126 try:
126 try:
127 import ldap
127 import ldap
128 ldap_lib_installed = True
128 ldap_lib_installed = True
129 except ImportError:
129 except ImportError:
130 # means that python-ldap is not installed
130 # means that python-ldap is not installed
131 pass
131 pass
132
132
133
133
134 def get_new_dir(title):
134 def get_new_dir(title):
135 """
135 """
136 Returns always new directory path.
136 Returns always new directory path.
137 """
137 """
138 from rhodecode.tests.vcs.utils import get_normalized_path
138 from rhodecode.tests.vcs.utils import get_normalized_path
139 name = TEST_REPO_PREFIX
139 name = TEST_REPO_PREFIX
140 if title:
140 if title:
141 name = '-'.join((name, title))
141 name = '-'.join((name, title))
142 hex = hashlib.sha1(str(time.time())).hexdigest()
142 hex = hashlib.sha1(str(time.time())).hexdigest()
143 name = '-'.join((name, hex))
143 name = '-'.join((name, hex))
144 path = os.path.join(TEST_DIR, name)
144 path = os.path.join(TEST_DIR, name)
145 return get_normalized_path(path)
145 return get_normalized_path(path)
146
146
147
147
148 def init_stack(config=None):
148 def init_stack(config=None):
149 if not config:
149 if not config:
150 config = pylons.test.pylonsapp.config
150 config = pylons.test.pylonsapp.config
151 url._push_object(URLGenerator(config['routes.map'], environ))
151 url._push_object(URLGenerator(config['routes.map'], environ))
152 pylons.app_globals._push_object(config['pylons.app_globals'])
152 pylons.app_globals._push_object(config['pylons.app_globals'])
153 pylons.config._push_object(config)
153 pylons.config._push_object(config)
154 pylons.tmpl_context._push_object(ContextObj())
154 pylons.tmpl_context._push_object(ContextObj())
155 # Initialize a translator for tests that utilize i18n
155 # Initialize a translator for tests that utilize i18n
156 translator = _get_translator(pylons.config.get('lang'))
156 translator = _get_translator(pylons.config.get('lang'))
157 pylons.translator._push_object(translator)
157 pylons.translator._push_object(translator)
158
158
159
159
160 class BaseTestCase(TestCase):
160 class BaseTestCase(unittest.TestCase):
161 def __init__(self, *args, **kwargs):
161 def __init__(self, *args, **kwargs):
162 self.wsgiapp = pylons.test.pylonsapp
162 self.wsgiapp = pylons.test.pylonsapp
163 init_stack(self.wsgiapp.config)
163 init_stack(self.wsgiapp.config)
164 TestCase.__init__(self, *args, **kwargs)
164 unittest.TestCase.__init__(self, *args, **kwargs)
165
165
166
166
167 class TestController(BaseTestCase):
167 class TestController(BaseTestCase):
168
168
169 def __init__(self, *args, **kwargs):
169 def __init__(self, *args, **kwargs):
170 BaseTestCase.__init__(self, *args, **kwargs)
170 BaseTestCase.__init__(self, *args, **kwargs)
171 self.app = TestApp(self.wsgiapp)
171 self.app = TestApp(self.wsgiapp)
172 self.index_location = config['app_conf']['index_dir']
172 self.index_location = config['app_conf']['index_dir']
173
173
174 def log_user(self, username=TEST_USER_ADMIN_LOGIN,
174 def log_user(self, username=TEST_USER_ADMIN_LOGIN,
175 password=TEST_USER_ADMIN_PASS):
175 password=TEST_USER_ADMIN_PASS):
176 self._logged_username = username
176 self._logged_username = username
177 response = self.app.post(url(controller='login', action='index'),
177 response = self.app.post(url(controller='login', action='index'),
178 {'username': username,
178 {'username': username,
179 'password': password})
179 'password': password})
180
180
181 if 'invalid user name' in response.body:
181 if 'invalid user name' in response.body:
182 self.fail('could not login using %s %s' % (username, password))
182 self.fail('could not login using %s %s' % (username, password))
183
183
184 self.assertEqual(response.status, '302 Found')
184 self.assertEqual(response.status, '302 Found')
185 ses = response.session['rhodecode_user']
185 ses = response.session['rhodecode_user']
186 self.assertEqual(ses.get('username'), username)
186 self.assertEqual(ses.get('username'), username)
187 response = response.follow()
187 response = response.follow()
188 self.assertEqual(ses.get('is_authenticated'), True)
188 self.assertEqual(ses.get('is_authenticated'), True)
189
189
190 return response.session['rhodecode_user']
190 return response.session['rhodecode_user']
191
191
192 def _get_logged_user(self):
192 def _get_logged_user(self):
193 return User.get_by_username(self._logged_username)
193 return User.get_by_username(self._logged_username)
194
194
195 def checkSessionFlash(self, response, msg):
195 def checkSessionFlash(self, response, msg):
196 self.assertTrue('flash' in response.session,
196 self.assertTrue('flash' in response.session,
197 msg='Response session:%r have no flash'
197 msg='Response session:%r have no flash'
198 % response.session)
198 % response.session)
199 if not msg in response.session['flash'][0][1]:
199 if not msg in response.session['flash'][0][1]:
200 msg = u'msg `%s` not found in session flash: got `%s` instead' % (
200 msg = u'msg `%s` not found in session flash: got `%s` instead' % (
201 msg, response.session['flash'][0][1])
201 msg, response.session['flash'][0][1])
202 self.fail(safe_str(msg))
202 self.fail(safe_str(msg))
General Comments 0
You need to be logged in to leave comments. Login now