Coverage for /Volumes/workspace/python-utils/.tox/py38/lib/python3.8/site-packages/python_utils/converters.py : 0%

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)
4import re
5import six
6import math
9def to_int(input_, default=0, exception=(ValueError, TypeError), regexp=None):
10 r'''
11 Convert the given input to an integer or return default
13 When trying to convert the exceptions given in the exception parameter
14 are automatically catched and the default will be returned.
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
22 The last group of the regexp will be used as value
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 '''
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)
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
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
92 When trying to convert the exceptions given in the exception parameter
93 are automatically catched and the default will be returned.
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
101 The last group of the regexp will be used as value
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 '''
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')
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
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.
164 :rtype: unicode
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_
185def to_str(input_, encoding='utf-8', errors='replace'):
186 '''Convert objects to string, encodes to the given encoding
188 :rtype: str
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_)
208 input_ = input_.encode(encoding, errors)
209 return input_
212def scale_1024(x, n_prefixes):
213 '''Scale a number down to a suitable size, based on powers of 1024.
215 Returns the scaled number and the power of 1024 used.
217 Use to format numbers of bytes to KiB, MiB, etc.
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
238def remap(value, old_min, old_max, new_min, new_max):
239 """
240 remap a value from one range into another.
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
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
255 >>> remap(46.0, 0.0, 100.0, -80.0, 10.0)
256 -38.6
258 Some edge cases to test
259 >>> remap(0, 0, 0, 0, 0)
260 0
261 >>> remap(0, 0, 0, 1, 0)
262 1
264 :param value: value to be converted
265 :type value: int, float
267 :param old_min: minimum of the range for the value that has been passed
268 :type old_min: int, float
270 :param old_max: maximum of the range for the value that has been passed
271 :type old_max: int, float
273 :param new_min: the minimum of the new range
274 :type new_min: int, float
276 :param new_max: the maximum of the new range
277 :type new_max: int, float
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
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
298 new_value += new_min
300 return new_value