root / snfcommon / synnefo / util / units.py @ 3c98e3a5
History  View  Annotate  Download (4.2 kB)
1 
# Copyright 2013 GRNET S.A. All rights reserved.


2 
#

3 
# Redistribution and use in source and binary forms, with or

4 
# without modification, are permitted provided that the following

5 
# conditions are met:

6 
#

7 
# 1. Redistributions of source code must retain the above

8 
# copyright notice, this list of conditions and the following

9 
# disclaimer.

10 
#

11 
# 2. Redistributions in binary form must reproduce the above

12 
# copyright notice, this list of conditions and the following

13 
# disclaimer in the documentation and/or other materials

14 
# provided with the distribution.

15 
#

16 
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS

17 
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

18 
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR

19 
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR

20 
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

21 
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

22 
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF

23 
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED

24 
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

25 
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

26 
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

27 
# POSSIBILITY OF SUCH DAMAGE.

28 
#

29 
# The views and conclusions contained in the software and

30 
# documentation are those of the authors and should not be

31 
# interpreted as representing official policies, either expressed

32 
# or implied, of GRNET S.A.

33  
34 
from synnefo.lib.ordereddict import OrderedDict 
35 
import re 
36  
37 
PRACTICALLY_INFINITE = 2**63  1 
38 
DEFAULT_PARSE_BASE = 1024

39 
PARSE_EXPONENTS = { 
40 
'': 0, 
41 
'bytes': 0, 
42 
'K': 1, 
43 
'KB': 1, 
44 
'KIB': 1, 
45 
'M': 2, 
46 
'MB': 2, 
47 
'MIB': 2, 
48 
'G': 3, 
49 
'GB': 3, 
50 
'GIB': 3, 
51 
'T': 4, 
52 
'TB': 4, 
53 
'TIB': 4, 
54 
'P': 5, 
55 
'PB': 5, 
56 
'PIB': 5, 
57 
} 
58  
59 
_MATCHER = re.compile('^(\d+\.?\d*)(.*)$')

60  
61  
62 
class ParseError(Exception): 
63 
pass

64  
65  
66 
def _parse_number_with_unit(s): 
67 
match = _MATCHER.match(s) 
68 
if not match: 
69 
raise ParseError()

70 
number, unit = match.groups() 
71 
try:

72 
number = long(number)

73 
except ValueError: 
74 
number = float(number)

75  
76 
return number, unit.strip().upper()

77  
78  
79 
def parse_with_style(s): 
80 
if s in ['inf', 'infinite']: 
81 
return PRACTICALLY_INFINITE, 0 
82  
83 
n, unit = _parse_number_with_unit(s) 
84 
try:

85 
exponent = PARSE_EXPONENTS[unit] 
86 
except KeyError: 
87 
raise ParseError()

88 
multiplier = DEFAULT_PARSE_BASE ** exponent 
89 
return long(n * multiplier), exponent 
90  
91  
92 
def parse(s): 
93 
n, _ = parse_with_style(s) 
94 
return n

95  
96  
97 
UNITS = { 
98 
'bytes': {

99 
'DISPLAY': ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB'], 
100 
'BASE': 1024, 
101 
} 
102 
} 
103  
104 
STYLE_TO_EXP = OrderedDict( 
105 
[('b', 0), 
106 
('kb', 1), 
107 
('mb', 2), 
108 
('gb', 3), 
109 
('tb', 4), 
110 
('pb', 5), 
111 
] 
112 
) 
113  
114 
STYLES = STYLE_TO_EXP.keys() + ['auto', 'none'] 
115  
116  
117 
class StyleError(Exception): 
118 
pass

119  
120  
121 
def show_float(n): 
122 
if n < 1: 
123 
return "%.3f" % n 
124 
if n < 10: 
125 
return "%.2f" % n 
126 
return "%.1f" % n 
127  
128  
129 
def get_exponent(style): 
130 
if isinstance(style, (int, long)): 
131 
if style in STYLE_TO_EXP.values(): 
132 
return style

133 
else:

134 
raise StyleError()

135 
else:

136 
try:

137 
return STYLE_TO_EXP[style]

138 
except KeyError: 
139 
raise StyleError()

140  
141  
142 
def show(n, unit, style=None): 
143 
if style == 'none': 
144 
return str(n) 
145  
146 
if n == PRACTICALLY_INFINITE:

147 
return 'inf' 
148  
149 
try:

150 
unit_dict = UNITS[unit] 
151 
except KeyError: 
152 
return str(n) 
153  
154 
BASE = unit_dict['BASE']

155 
DISPLAY = unit_dict['DISPLAY']

156  
157 
if style is None or style == 'auto': 
158 
if n < BASE:

159 
return "%d %s" % (n, DISPLAY[0]) 
160 
n = float(n)

161 
for i in DISPLAY[1:]: 
162 
n = n / BASE 
163 
if n < BASE:

164 
break

165 
return "%s %s" % (show_float(n), i) 
166  
167 
exponent = get_exponent(style) 
168 
unit_display = DISPLAY[exponent] 
169 
if exponent == 0: 
170 
return "%d %s" % (n, unit_display) 
171  
172 
divisor = BASE ** exponent 
173 
n = float(n)

174 
n = n / divisor 
175 
return "%s %s" % (show_float(n), unit_display) 