Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" Utility functions, used internally. """ 

2 

3import copy 

4import re 

5import functools 

6import six.moves 

7 

8try: 

9 # py2 

10 import thread 

11except ImportError: 

12 # py3 

13 import _thread as thread 

14 

15import webob 

16 

17_thread_local = {} 

18 

19 

20def thread_local(): 

21 threadid = thread.get_ident() 

22 try: 

23 return _thread_local[threadid] 

24 except KeyError: 

25 rl_data = {} 

26 _thread_local[threadid] = rl_data 

27 return rl_data 

28 

29 

30class class_or_instance(object): 

31 def __init__(self, fn): 

32 self._function = fn 

33 self._wrapper = functools.wraps(fn) 

34 

35 def __get__(self, ins, cls): 

36 return self._wrapper(functools.partial(self._function, ins, cls)) 

37 

38 

39def name2label(name): 

40 """ 

41 Convert a column name to a Human Readable name. 

42 1) Strip _id from the end 

43 2) Convert _ to spaces 

44 3) Convert CamelCase to Camel Case 

45 4) Upcase first character of Each Word 

46 """ 

47 if name.endswith('_id'): 

48 name = name[:-3] 

49 return ' '.join([s.capitalize() for s in 

50 re.findall(r'([A-Z][a-z0-9]+|[a-z0-9]+|[A-Z0-9]+)', name)]) 

51 

52 

53class MultipleReplacer(object): 

54 """Performs several regexp substitutions on a string with a single pass. 

55 

56 ``dct`` is a dictionary keyed by a regular expression string and with a 

57 callable as value that will get called to produce a substituted value. 

58 

59 The callable takes the matched text as first argument and may take any 

60 number of positional and keyword arguments. These arguments are any extra 

61 args passed when calling the instance. 

62 

63 For performance, a single regular expression is built. 

64 

65 Example:: 

66 

67 >>> string = "aaaabbbcc" 

68 >>> replacer = MultipleReplacer({ 

69 ... 'a+':lambda g, context: g + context['after_a'], 

70 ... 'b+':lambda g, context: g + context['after_b'], 

71 ... 'c+':lambda g, context: context['before_c'] + g, 

72 ... }) 

73 >>> replacer("aaaabbbcc", dict( 

74 ... after_a = "1", 

75 ... after_b = "2", 

76 ... before_c = "3" 

77 ... )) 

78 'aaaa1bbb23cc' 

79 """ 

80 def __init__(self, dct, options=0): 

81 self._raw_regexp = r"|".join("(%s)" % k for k in dct.keys()) 

82 self._substitutors = dct.values() 

83 self._regexp = re.compile(self._raw_regexp, options) 

84 

85 def __repr__(self): 

86 return "<%s at %d (%r)>" % (self.__class__.__name__, id(self), 

87 self._raw_regexp) 

88 

89 def _substitutor(self, *args, **kw): 

90 def substitutor(match): 

91 tuples = six.moves.zip(self._substitutors, match.groups()) 

92 for substitutor, group in tuples: 

93 if group is not None: 

94 return substitutor(group, *args, **kw) 

95 return substitutor 

96 

97 def __call__(self, string, *args, **kw): 

98 return self._regexp.sub(self._substitutor(*args, **kw), string) 

99 

100 

101def abort(req, status): 

102 return webob.Response(request=req, status=status, content_type="text/html") 

103 

104 

105_memoization_flush_callbacks = [] 

106 

107 

108class memoize(object): 

109 def __init__(self, f): 

110 global _memoization_flush_callbacks 

111 self.f = f 

112 self.mem = {} 

113 _memoization_flush_callbacks.append(self._flush) 

114 

115 def _flush(self): 

116 self.mem = {} 

117 

118 def __call__(self, *args, **kwargs): 

119 if (args, str(kwargs)) in self.mem: 

120 return self.mem[args, str(kwargs)] 

121 else: 

122 tmp = self.f(*args, **kwargs) 

123 self.mem[args, str(kwargs)] = tmp 

124 return tmp 

125 

126 

127def flush_memoization(): 

128 for cb in _memoization_flush_callbacks: 

129 cb() 

130 

131 

132def clone_object(obj, **values): 

133 if obj is None: 

134 obj = type('_TemporaryObject', (object,), {})() 

135 else: 

136 obj = copy.copy(obj) 

137 

138 for k,v in values.items(): 

139 setattr(obj, k, v) 

140 

141 return obj 

142 

143 

144# relpath support for python-2.5 

145# Taken from https://github.com/nipy/nipype/issues/62 

146# Related to https://github.com/toscawidgets/tw2.core/issues/30 

147try: 

148 from os.path import relpath 

149except ImportError: 

150 import os 

151 import os.path as op 

152 

153 def relpath(path, start=None): 

154 """Return a relative version of a path""" 

155 if start is None: 

156 start = os.curdir 

157 if not path: 

158 raise ValueError("no path specified") 

159 start_list = op.abspath(start).split(op.sep) 

160 path_list = op.abspath(path).split(op.sep) 

161 

162 if start_list[0].lower() != path_list[0].lower(): 

163 unc_path, rest = op.splitunc(path) 

164 unc_start, rest = op.splitunc(start) 

165 if bool(unc_path) ^ bool(unc_start): 

166 raise ValueError( 

167 "Cannot mix UNC and non-UNC paths (%s and%s)" % 

168 (path, start)) 

169 else: 

170 raise ValueError( 

171 "path is on drive %s, start on drive %s" 

172 % (path_list[0], start_list[0])) 

173 

174 # Work out how much of the filepath is shared by start and path. 

175 for i in range(min(len(start_list), len(path_list))): 

176 if start_list[i].lower() != path_list[i].lower(): 

177 break 

178 else: 

179 i += 1 

180 

181 rel_list = [op.pardir] * (len(start_list) - i) + path_list[i:] 

182 if not rel_list: 

183 return os.curdir 

184 return op.join(*rel_list)