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

1from __future__ import (absolute_import, division, print_function, 

2 unicode_literals) 

3 

4import re 

5import six 

6import math 

7 

8 

9def to_int(input_, default=0, exception=(ValueError, TypeError), regexp=None): 

10 r''' 

11 Convert the given input to an integer or return default 

12 

13 When trying to convert the exceptions given in the exception parameter 

14 are automatically catched and the default will be returned. 

15 

16 The regexp parameter allows for a regular expression to find the digits 

17 in a string. 

18 When True it will automatically match any digit in the string. 

19 When a (regexp) object (has a search method) is given, that will be used. 

20 WHen a string is given, re.compile will be run over it first 

21 

22 The last group of the regexp will be used as value 

23 

24 >>> to_int('abc') 

25 0 

26 >>> to_int('1') 

27 1 

28 >>> to_int('abc123') 

29 0 

30 >>> to_int('123abc') 

31 0 

32 >>> to_int('abc123', regexp=True) 

33 123 

34 >>> to_int('123abc', regexp=True) 

35 123 

36 >>> to_int('abc123abc', regexp=True) 

37 123 

38 >>> to_int('abc123abc456', regexp=True) 

39 123 

40 >>> to_int('abc123', regexp=re.compile(r'(\d+)')) 

41 123 

42 >>> to_int('123abc', regexp=re.compile(r'(\d+)')) 

43 123 

44 >>> to_int('abc123abc', regexp=re.compile(r'(\d+)')) 

45 123 

46 >>> to_int('abc123abc456', regexp=re.compile(r'(\d+)')) 

47 123 

48 >>> to_int('abc123', regexp=r'(\d+)') 

49 123 

50 >>> to_int('123abc', regexp=r'(\d+)') 

51 123 

52 >>> to_int('abc', regexp=r'(\d+)') 

53 0 

54 >>> to_int('abc123abc', regexp=r'(\d+)') 

55 123 

56 >>> to_int('abc123abc456', regexp=r'(\d+)') 

57 123 

58 >>> to_int('1234', default=1) 

59 1234 

60 >>> to_int('abc', default=1) 

61 1 

62 >>> to_int('abc', regexp=123) 

63 Traceback (most recent call last): 

64 ... 

65 TypeError: unknown argument for regexp parameter: 123 

66 ''' 

67 

68 if regexp is True: 

69 regexp = re.compile(r'(\d+)') 

70 elif isinstance(regexp, six.string_types): 

71 regexp = re.compile(regexp) 

72 elif hasattr(regexp, 'search'): 

73 pass 

74 elif regexp is not None: 

75 raise TypeError('unknown argument for regexp parameter: %r' % regexp) 

76 

77 try: 

78 if regexp: 

79 match = regexp.search(input_) 

80 if match: 

81 input_ = match.groups()[-1] 

82 return int(input_) 

83 except exception: 

84 return default 

85 

86 

87def to_float(input_, default=0, exception=(ValueError, TypeError), 

88 regexp=None): 

89 r''' 

90 Convert the given `input_` to an integer or return default 

91 

92 When trying to convert the exceptions given in the exception parameter 

93 are automatically catched and the default will be returned. 

94 

95 The regexp parameter allows for a regular expression to find the digits 

96 in a string. 

97 When True it will automatically match any digit in the string. 

98 When a (regexp) object (has a search method) is given, that will be used. 

99 WHen a string is given, re.compile will be run over it first 

100 

101 The last group of the regexp will be used as value 

102 

103 >>> '%.2f' % to_float('abc') 

104 '0.00' 

105 >>> '%.2f' % to_float('1') 

106 '1.00' 

107 >>> '%.2f' % to_float('abc123.456', regexp=True) 

108 '123.46' 

109 >>> '%.2f' % to_float('abc123', regexp=True) 

110 '123.00' 

111 >>> '%.2f' % to_float('abc0.456', regexp=True) 

112 '0.46' 

113 >>> '%.2f' % to_float('abc123.456', regexp=re.compile(r'(\d+\.\d+)')) 

114 '123.46' 

115 >>> '%.2f' % to_float('123.456abc', regexp=re.compile(r'(\d+\.\d+)')) 

116 '123.46' 

117 >>> '%.2f' % to_float('abc123.46abc', regexp=re.compile(r'(\d+\.\d+)')) 

118 '123.46' 

119 >>> '%.2f' % to_float('abc123abc456', regexp=re.compile(r'(\d+(\.\d+|))')) 

120 '123.00' 

121 >>> '%.2f' % to_float('abc', regexp=r'(\d+)') 

122 '0.00' 

123 >>> '%.2f' % to_float('abc123', regexp=r'(\d+)') 

124 '123.00' 

125 >>> '%.2f' % to_float('123abc', regexp=r'(\d+)') 

126 '123.00' 

127 >>> '%.2f' % to_float('abc123abc', regexp=r'(\d+)') 

128 '123.00' 

129 >>> '%.2f' % to_float('abc123abc456', regexp=r'(\d+)') 

130 '123.00' 

131 >>> '%.2f' % to_float('1234', default=1) 

132 '1234.00' 

133 >>> '%.2f' % to_float('abc', default=1) 

134 '1.00' 

135 >>> '%.2f' % to_float('abc', regexp=123) 

136 Traceback (most recent call last): 

137 ... 

138 TypeError: unknown argument for regexp parameter 

139 ''' 

140 

141 if regexp is True: 

142 regexp = re.compile(r'(\d+(\.\d+|))') 

143 elif isinstance(regexp, six.string_types): 

144 regexp = re.compile(regexp) 

145 elif hasattr(regexp, 'search'): 

146 pass 

147 elif regexp is not None: 

148 raise TypeError('unknown argument for regexp parameter') 

149 

150 try: 

151 if regexp: 

152 match = regexp.search(input_) 

153 if match: 

154 input_ = match.group(1) 

155 return float(input_) 

156 except exception: 

157 return default 

158 

159 

160def to_unicode(input_, encoding='utf-8', errors='replace'): 

161 '''Convert objects to unicode, if needed decodes string with the given 

162 encoding and errors settings. 

163 

164 :rtype: unicode 

165 

166 >>> to_unicode(b'a') 

167 'a' 

168 >>> to_unicode('a') 

169 'a' 

170 >>> to_unicode(u'a') 

171 'a' 

172 >>> class Foo(object): __str__ = lambda s: u'a' 

173 >>> to_unicode(Foo()) 

174 'a' 

175 >>> to_unicode(Foo) 

176 "<class 'python_utils.converters.Foo'>" 

177 ''' 

178 if isinstance(input_, six.binary_type): 

179 input_ = input_.decode(encoding, errors) 

180 else: 

181 input_ = six.text_type(input_) 

182 return input_ 

183 

184 

185def to_str(input_, encoding='utf-8', errors='replace'): 

186 '''Convert objects to string, encodes to the given encoding 

187 

188 :rtype: str 

189 

190 >>> to_str('a') 

191 b'a' 

192 >>> to_str(u'a') 

193 b'a' 

194 >>> to_str(b'a') 

195 b'a' 

196 >>> class Foo(object): __str__ = lambda s: u'a' 

197 >>> to_str(Foo()) 

198 'a' 

199 >>> to_str(Foo) 

200 "<class 'python_utils.converters.Foo'>" 

201 ''' 

202 if isinstance(input_, six.binary_type): 

203 pass 

204 else: 

205 if not hasattr(input_, 'encode'): 

206 input_ = six.text_type(input_) 

207 

208 input_ = input_.encode(encoding, errors) 

209 return input_ 

210 

211 

212def scale_1024(x, n_prefixes): 

213 '''Scale a number down to a suitable size, based on powers of 1024. 

214 

215 Returns the scaled number and the power of 1024 used. 

216 

217 Use to format numbers of bytes to KiB, MiB, etc. 

218 

219 >>> scale_1024(310, 3) 

220 (310.0, 0) 

221 >>> scale_1024(2048, 3) 

222 (2.0, 1) 

223 >>> scale_1024(0, 2) 

224 (0.0, 0) 

225 >>> scale_1024(0.5, 2) 

226 (0.5, 0) 

227 >>> scale_1024(1, 2) 

228 (1.0, 0) 

229 ''' 

230 if x <= 0: 

231 power = 0 

232 else: 

233 power = min(int(math.log(x, 2) / 10), n_prefixes - 1) 

234 scaled = float(x) / (2 ** (10 * power)) 

235 return scaled, power 

236 

237 

238def remap(value, old_min, old_max, new_min, new_max): 

239 """ 

240 remap a value from one range into another. 

241 

242 >>> remap(500, 0, 1000, 0, 100) 

243 50 

244 >>> remap(250.0, 0.0, 1000.0, 0.0, 100.0) 

245 25.0 

246 >>> remap(-75, -100, 0, -1000, 0) 

247 -750 

248 >>> remap(33, 0, 100, -500, 500) 

249 -170 

250 

251 This is a great use case example. Take an AVR that has dB values the 

252 minimum being -80dB and the maximum being 10dB and you want to convert 

253 volume percent to the equilivint in that dB range 

254 

255 >>> remap(46.0, 0.0, 100.0, -80.0, 10.0) 

256 -38.6 

257 

258 Some edge cases to test 

259 >>> remap(0, 0, 0, 0, 0) 

260 0 

261 >>> remap(0, 0, 0, 1, 0) 

262 1 

263 

264 :param value: value to be converted 

265 :type value: int, float 

266 

267 :param old_min: minimum of the range for the value that has been passed 

268 :type old_min: int, float 

269 

270 :param old_max: maximum of the range for the value that has been passed 

271 :type old_max: int, float 

272 

273 :param new_min: the minimum of the new range 

274 :type new_min: int, float 

275 

276 :param new_max: the maximum of the new range 

277 :type new_max: int, float 

278 

279 :return: value that has been re ranged, if the value is an int floor 

280 division is used so the returned value will always be rounded down 

281 to the closest whole number. 

282 :rtype: int, float 

283 """ 

284 old_range = old_max - old_min 

285 new_range = new_max - new_min 

286 if new_range == 0: 

287 return 0 

288 

289 if old_range == 0: 

290 new_value = new_min 

291 else: 

292 new_value = (value - old_min) * new_range 

293 if isinstance(value, int): 

294 new_value = new_value // old_range 

295 else: 

296 new_value = new_value / old_range 

297 

298 new_value += new_min 

299 

300 return new_value