codekingpro/portable-devtools
115k
1import datetime2import functools3import ipaddress4import time5 6SIZE_UNITS = {7 "b": 1024**0,8 "k": 1024**1,9 "m": 1024**2,10 "g": 1024**3,11 "t": 1024**4,12}13 14 15def pretty_size(size: int) -> str:16 """Convert a number of bytes into a human-readable string.17 18 len(return value) <= 5 always holds true.19 """20 s: float = size # type cast for mypy21 if s < 1024:22 return f"{s}b"23 for suffix in ["k", "m", "g", "t"]:24 s /= 102425 if s < 99.95:26 return f"{s:.1f}{suffix}"27 if s < 1024 or suffix == "t":28 return f"{s:.0f}{suffix}"29 raise AssertionError30 31 32@functools.lru_cache33def parse_size(s: str | None) -> int | None:34 """35 Parse a size with an optional k/m/... suffix.36 Invalid values raise a ValueError. For added convenience, passing `None` returns `None`.37 """38 if s is None:39 return None40 try:41 return int(s)42 except ValueError:43 pass44 for i in SIZE_UNITS.keys():45 if s.endswith(i):46 try:47 return int(s[:-1]) * SIZE_UNITS[i]48 except ValueError:49 break50 raise ValueError("Invalid size specification.")51 52 53def pretty_duration(secs: float | None) -> str:54 formatters = [55 (100, "{:.0f}s"),56 (10, "{:2.1f}s"),57 (1, "{:1.2f}s"),58 ]59 if secs is None:60 return ""61 62 for limit, formatter in formatters:63 if secs >= limit:64 return formatter.format(secs)65 # less than 1 sec66 return f"{secs * 1000:.0f}ms"67 68 69def format_timestamp(s):70 s = time.localtime(s)71 d = datetime.datetime.fromtimestamp(time.mktime(s))72 return d.strftime("%Y-%m-%d %H:%M:%S")73 74 75def format_timestamp_with_milli(s):76 d = datetime.datetime.fromtimestamp(s)77 return d.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]78 79 80@functools.lru_cache81def format_address(address: tuple | None) -> str:82 """83 This function accepts IPv4/IPv6 tuples and84 returns the formatted address string with port number85 """86 if address is None:87 return "<no address>"88 try:89 host = ipaddress.ip_address(address[0])90 if host.is_unspecified:91 return f"*:{address[1]}"92 if isinstance(host, ipaddress.IPv4Address):93 return f"{host}:{address[1]}"94 # If IPv6 is mapped to IPv495 elif host.ipv4_mapped:96 return f"{host.ipv4_mapped}:{address[1]}"97 return f"[{host}]:{address[1]}"98 except ValueError:99 return f"{address[0]}:{address[1]}"100 