1313"""
1414
1515__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
16- __version__ = '2025042001 '
16+ __version__ = '2025121201 '
1717
1818import math
1919
20+ # Pre-computed thresholds for bits2human (descending order)
21+ _BITS_THRESHOLDS = (
22+ ('YiB' , 9671406556917033397649408 ),
23+ ('ZiB' , 9444732965739290427392 ),
24+ ('EiB' , 9223372036854775808 ),
25+ ('PiB' , 9007199254740992 ),
26+ ('TiB' , 8796093022208 ),
27+ ('GiB' , 8589934592 ),
28+ ('MiB' , 8388608 ),
29+ ('KiB' , 8192 ),
30+ ('B' , 8 ),
31+ )
32+
33+ # Pre-computed thresholds for bps2human (descending order)
34+ _BPS_THRESHOLDS = (
35+ ('Ybps' , 1000000000000000000000000 ),
36+ ('Zbps' , 1000000000000000000000 ),
37+ ('Ebps' , 1000000000000000000 ),
38+ ('Pbps' , 1000000000000000 ),
39+ ('Tbps' , 1000000000000 ),
40+ ('Gbps' , 1000000000 ),
41+ ('Mbps' , 1000000 ),
42+ ('Kbps' , 1000 ),
43+ ('bps' , 1 ),
44+ )
45+
46+ # Pre-computed thresholds for bytes2human (descending order)
47+ _BYTES_THRESHOLDS = (
48+ ('YiB' , 1208925819614629174706176 ),
49+ ('ZiB' , 1180591620717411303424 ),
50+ ('EiB' , 1152921504606846976 ),
51+ ('PiB' , 1125899906842624 ),
52+ ('TiB' , 1099511627776 ),
53+ ('GiB' , 1073741824 ),
54+ ('MiB' , 1048576 ),
55+ ('KiB' , 1024 ),
56+ ('B' , 1 ),
57+ )
58+
59+ # Pre-computed multipliers for human2bytes (binary units always 1024-based)
60+ _BINARY_MULTIPLIERS = (
61+ ('yib' , 1208925819614629174706176 ),
62+ ('zib' , 1180591620717411303424 ),
63+ ('eib' , 1152921504606846976 ),
64+ ('pib' , 1125899906842624 ),
65+ ('tib' , 1099511627776 ),
66+ ('gib' , 1073741824 ),
67+ ('mib' , 1048576 ),
68+ ('kib' , 1024 ),
69+ )
70+
71+ # Pre-computed multipliers for human2bytes (decimal, base 1024)
72+ _DECIMAL_1024_MULTIPLIERS = (
73+ ('yb' , 1208925819614629174706176 ),
74+ ('y' , 1208925819614629174706176 ),
75+ ('zb' , 1180591620717411303424 ),
76+ ('z' , 1180591620717411303424 ),
77+ ('eb' , 1152921504606846976 ),
78+ ('e' , 1152921504606846976 ),
79+ ('pb' , 1125899906842624 ),
80+ ('p' , 1125899906842624 ),
81+ ('tb' , 1099511627776 ),
82+ ('t' , 1099511627776 ),
83+ ('gb' , 1073741824 ),
84+ ('g' , 1073741824 ),
85+ ('mb' , 1048576 ),
86+ ('m' , 1048576 ),
87+ ('kb' , 1024 ),
88+ ('k' , 1024 ),
89+ )
90+
91+ # Pre-computed multipliers for human2bytes (decimal, base 1000)
92+ _DECIMAL_1000_MULTIPLIERS = (
93+ ('yb' , 1000000000000000000000000 ),
94+ ('y' , 1000000000000000000000000 ),
95+ ('zb' , 1000000000000000000000 ),
96+ ('z' , 1000000000000000000000 ),
97+ ('eb' , 1000000000000000000 ),
98+ ('e' , 1000000000000000000 ),
99+ ('pb' , 1000000000000000 ),
100+ ('p' , 1000000000000000 ),
101+ ('tb' , 1000000000000 ),
102+ ('t' , 1000000000000 ),
103+ ('gb' , 1000000000 ),
104+ ('g' , 1000000000 ),
105+ ('mb' , 1000000 ),
106+ ('m' , 1000000 ),
107+ ('kb' , 1000 ),
108+ ('k' , 1000 ),
109+ )
110+
111+ # Pre-computed unit to seconds mapping for human2seconds
112+ _UNIT_TO_SECONDS = {
113+ 's' : 1 ,
114+ 'm' : 60 ,
115+ 'h' : 3600 ,
116+ 'D' : 86400 ,
117+ 'W' : 604800 ,
118+ 'M' : 2592000 ,
119+ 'Y' : 31536000 ,
120+ }
121+
122+ # Pre-computed SI prefixes for number2human
123+ _SI_PREFIXES = ('' , 'K' , 'M' , 'G' , 'T' , 'P' , 'E' , 'Z' , 'Y' )
124+ _SI_PREFIXES_MAX_IDX = 8 # len(_SI_PREFIXES) - 1
125+
126+ # Pre-computed time units for seconds2human (full names)
127+ _TIME_UNITS_FULL = (
128+ ('years' , 31536000 ),
129+ ('months' , 2592000 ),
130+ ('weeks' , 604800 ),
131+ ('days' , 86400 ),
132+ ('hours' , 3600 ),
133+ ('minutes' , 60 ),
134+ ('seconds' , 1 ),
135+ ('millisecs' , 1e-3 ),
136+ ('microsecs' , 1e-6 ),
137+ ('nanosecs' , 1e-9 ),
138+ ('picosecs' , 1e-12 ),
139+ )
140+
141+ # Pre-computed time units for seconds2human (short names)
142+ _TIME_UNITS_SHORT = (
143+ ('Y' , 31536000 ),
144+ ('M' , 2592000 ),
145+ ('W' , 604800 ),
146+ ('D' , 86400 ),
147+ ('h' , 3600 ),
148+ ('m' , 60 ),
149+ ('s' , 1 ),
150+ ('ms' , 1e-3 ),
151+ ('us' , 1e-6 ),
152+ ('ns' , 1e-9 ),
153+ ('ps' , 1e-12 ),
154+ )
155+
20156
21157def bits2human (n , decimals = 1 , space = False ):
22158 """
@@ -44,19 +180,14 @@ def bits2human(n, decimals=1, space=False):
44180 >>> bits2human(8192, decimals=3, space=True)
45181 '1.000 KiB'
46182 """
47- symbols = ('B' , 'KiB' , 'MiB' , 'GiB' , 'TiB' , 'PiB' , 'EiB' , 'ZiB' , 'YiB' )
48- prefix = {'B' : 8 }
49- for i , symbol in enumerate (symbols [1 :], 1 ):
50- prefix [symbol ] = 1024 ** i * 8
51-
52- for symbol in reversed (symbols ):
53- if n >= prefix [symbol ]:
54- value = float (n ) / prefix [symbol ]
55- sep = ' ' if space else ''
183+ sep = ' ' if space else ''
184+
185+ for symbol , threshold in _BITS_THRESHOLDS :
186+ if n >= threshold :
187+ value = float (n ) / threshold
56188 return f'{ value :.{decimals }f} { sep } { symbol } '
57189
58- sep = ' ' if space else ''
59- return f'{ n :.{decimals }f} { sep } { symbols [0 ]} '
190+ return f'{ n :.{decimals }f} { sep } B'
60191
61192
62193def bps2human (n , decimals = 1 , space = False ):
@@ -87,17 +218,14 @@ def bps2human(n, decimals=1, space=False):
87218 >>> bps2human(72000000, decimals=2, space=True)
88219 '72.00 Mbps'
89220 """
90- symbols = ('bps' , 'Kbps' , 'Mbps' , 'Gbps' , 'Tbps' , 'Pbps' , 'Ebps' , 'Zbps' , 'Ybps' )
91- prefix = {symbol : 1000 ** i for i , symbol in enumerate (symbols )}
221+ sep = ' ' if space else ''
92222
93- for symbol in reversed (symbols [1 :]):
94- if n >= prefix [symbol ]:
95- value = float (n ) / prefix [symbol ]
96- sep = ' ' if space else ''
223+ for symbol , threshold in _BPS_THRESHOLDS :
224+ if n >= threshold :
225+ value = float (n ) / threshold
97226 return f'{ value :.{decimals }f} { sep } { symbol } '
98227
99- sep = ' ' if space else ''
100- return f'{ n :.{decimals }f} { sep } { symbols [0 ]} '
228+ return f'{ n :.{decimals }f} { sep } bps'
101229
102230
103231def bytes2human (n , decimals = 1 , space = False ):
@@ -131,17 +259,14 @@ def bytes2human(n, decimals=1, space=False):
131259 >>> bytes2human(1048576, decimals=1, space=True)
132260 '1.0 MiB'
133261 """
134- symbols = ('B' , 'KiB' , 'MiB' , 'GiB' , 'TiB' , 'PiB' , 'EiB' , 'ZiB' , 'YiB' )
135- prefix = {symbol : 1 << (i + 1 ) * 10 for i , symbol in enumerate (symbols [1 :])}
262+ sep = ' ' if space else ''
136263
137- for symbol in reversed (symbols [1 :]):
138- if n >= prefix [symbol ]:
139- value = float (n ) / prefix [symbol ]
140- sep = ' ' if space else ''
264+ for symbol , threshold in _BYTES_THRESHOLDS :
265+ if n >= threshold :
266+ value = float (n ) / threshold
141267 return f'{ value :.{decimals }f} { sep } { symbol } '
142268
143- sep = ' ' if space else ''
144- return f'{ n :.{decimals }f} { sep } { symbols [0 ]} '
269+ return f'{ n :.{decimals }f} { sep } B'
145270
146271
147272def extract_hrnumbers (s , boundaries = None ):
@@ -191,7 +316,7 @@ def human2bytes(string, binary=True):
191316 """
192317 Converts a human-readable string to the equivalent number of bytes.
193318
194- This function converts a string representation of a file size, such as '3.072GiB' or '3.072GB',
319+ This function converts a string representation of a file size, such as '3.072GiB' or '3.072GB',
195320 into the corresponding number of bytes. It supports both binary (base 1024) and decimal
196321 (base 1000) units.
197322
@@ -212,43 +337,23 @@ def human2bytes(string, binary=True):
212337 3072000000
213338 """
214339 try :
215- string = string .lower ()
216- if 'kib' in string :
217- return int (float (string .replace ('kib' , '' ).strip ()) * 1024 )
218- if 'mib' in string :
219- return int (float (string .replace ('mib' , '' ).strip ()) * 1024 ** 2 )
220- if 'gib' in string :
221- return int (float (string .replace ('gib' , '' ).strip ()) * 1024 ** 3 )
222- if 'tib' in string :
223- return int (float (string .replace ('tib' , '' ).strip ()) * 1024 ** 4 )
224- if 'pib' in string :
225- return int (float (string .replace ('pib' , '' ).strip ()) * 1024 ** 5 )
226- if 'eib' in string :
227- return int (float (string .replace ('eib' , '' ).strip ()) * 1024 ** 6 )
228- if 'zib' in string :
229- return int (float (string .replace ('zib' , '' ).strip ()) * 1024 ** 7 )
230- if 'yib' in string :
231- return int (float (string .replace ('yib' , '' ).strip ()) * 1024 ** 8 )
232-
233- base = 1024 if binary else 1000
234- if 'k' in string : # matches "kb" or "k"
235- return int (float (string .replace ('kb' , '' ).replace ('k' , '' ).strip ()) * base )
236- if 'm' in string :
237- return int (float (string .replace ('mb' , '' ).replace ('m' , '' ).strip ()) * base ** 2 )
238- if 'g' in string :
239- return int (float (string .replace ('gb' , '' ).replace ('g' , '' ).strip ()) * base ** 3 )
240- if 't' in string :
241- return int (float (string .replace ('tb' , '' ).replace ('t' , '' ).strip ()) * base ** 4 )
242- if 'p' in string :
243- return int (float (string .replace ('pb' , '' ).replace ('p' , '' ).strip ()) * base ** 5 )
244- if 'e' in string :
245- return int (float (string .replace ('eb' , '' ).replace ('e' , '' ).strip ()) * base ** 6 )
246- if 'z' in string :
247- return int (float (string .replace ('zb' , '' ).replace ('z' , '' ).strip ()) * base ** 7 )
248- if 'y' in string :
249- return int (float (string .replace ('yb' , '' ).replace ('y' , '' ).strip ()) * base ** 8 )
250- if 'b' in string :
251- return int (float (string .replace ('b' , '' ).strip ()))
340+ string_lower = string .lower ()
341+
342+ # Check binary units first (always 1024-based)
343+ for unit , multiplier in _BINARY_MULTIPLIERS :
344+ if unit in string_lower :
345+ return int (float (string_lower .replace (unit , '' ).strip ()) * multiplier )
346+
347+ # Check decimal units (base depends on binary parameter)
348+ multipliers = _DECIMAL_1024_MULTIPLIERS if binary else _DECIMAL_1000_MULTIPLIERS
349+ for unit , multiplier in multipliers :
350+ if unit in string_lower :
351+ return int (float (string_lower .replace (unit , '' ).strip ()) * multiplier )
352+
353+ # Check for plain 'b' (bytes)
354+ if 'b' in string_lower :
355+ return int (float (string_lower .replace ('b' , '' ).strip ()))
356+
252357 return 0
253358 except Exception :
254359 return 0
@@ -307,32 +412,22 @@ def human2seconds(string):
307412 >>> human2seconds('invalid')
308413 0
309414 """
310- unit_to_seconds = {
311- 's' : 1 ,
312- 'm' : 60 ,
313- 'h' : 3600 ,
314- 'D' : 86400 ,
315- 'W' : 604800 ,
316- 'M' : 2592000 ,
317- 'Y' : 31536000 ,
318- }
319-
320415 string = string .strip ()
321416 if not string or len (string ) < 2 :
322417 return 0
323418
324419 unit = string [- 1 ]
325420 value_str = string [:- 1 ]
326421
327- if unit not in unit_to_seconds :
422+ if unit not in _UNIT_TO_SECONDS :
328423 return 0
329424
330425 try :
331426 value = float (value_str )
332427 except (ValueError , TypeError ):
333428 return 0
334429
335- return int (value * unit_to_seconds [unit ])
430+ return int (value * _UNIT_TO_SECONDS [unit ])
336431
337432
338433def humanduration2seconds (text ):
@@ -457,7 +552,6 @@ def number2human(number):
457552 >>> number2human(9223372036854775808)
458553 '9.2E'
459554 """
460- millnames = ['' , 'K' , 'M' , 'G' , 'T' , 'P' , 'E' , 'Z' , 'Y' ]
461555 try :
462556 number = float (number )
463557 except Exception :
@@ -468,9 +562,9 @@ def number2human(number):
468562 else :
469563 millidx = int (math .floor (math .log10 (abs (number )) / 3 ))
470564
471- millidx = max (0 , min (len ( millnames ) - 1 , millidx ))
565+ millidx = max (0 , min (_SI_PREFIXES_MAX_IDX , millidx ))
472566 scaled = number / 10 ** (3 * millidx )
473- return f'{ scaled :.1f} { millnames [millidx ]} '
567+ return f'{ scaled :.1f} { _SI_PREFIXES [millidx ]} '
474568
475569
476570def seconds2human (seconds , keep_short = True , full_name = False ):
@@ -521,31 +615,7 @@ def seconds2human(seconds, keep_short=True, full_name=False):
521615 """
522616 seconds = float (seconds )
523617
524- units = (
525- ('years' , 60 * 60 * 24 * 365 ),
526- ('months' , 60 * 60 * 24 * 30 ),
527- ('weeks' , 60 * 60 * 24 * 7 ),
528- ('days' , 60 * 60 * 24 ),
529- ('hours' , 60 * 60 ),
530- ('minutes' , 60 ),
531- ('seconds' , 1 ),
532- ('millisecs' , 1e-3 ),
533- ('microsecs' , 1e-6 ),
534- ('nanosecs' , 1e-9 ),
535- ('picosecs' , 1e-12 ),
536- ) if full_name else (
537- ('Y' , 60 * 60 * 24 * 365 ),
538- ('M' , 60 * 60 * 24 * 30 ),
539- ('W' , 60 * 60 * 24 * 7 ),
540- ('D' , 60 * 60 * 24 ),
541- ('h' , 60 * 60 ),
542- ('m' , 60 ),
543- ('s' , 1 ),
544- ('ms' , 1e-3 ),
545- ('us' , 1e-6 ),
546- ('ns' , 1e-9 ),
547- ('ps' , 1e-12 ),
548- )
618+ units = _TIME_UNITS_FULL if full_name else _TIME_UNITS_SHORT
549619
550620 result = []
551621 for name , count in units :
0 commit comments