Files
computer-playbook/utils/sizes.py
T

58 lines
1.5 KiB
Python

"""Parse human-readable memory size strings to bytes.
SI/decimal units for the bare suffixes (k=10^3, m=10^6, g=10^9, ...) and IEC
binary for the explicit ``*ib`` suffixes (kib=1024, mib=1024^2, ...). Shared by
the ``node_max_old_space_size`` lookup and the peertube ``install_mem_limit``
filter.
"""
from __future__ import annotations
import re
from ansible.errors import AnsibleFilterError
_SIZE_RE = re.compile(r"^\s*(\d+(?:\.\d+)?)\s*([kmgtp]?i?b?)?\s*$", re.IGNORECASE)
_MULT = {
"": 1,
"b": 1,
"k": 10**3,
"kb": 10**3,
"m": 10**6,
"mb": 10**6,
"g": 10**9,
"gb": 10**9,
"t": 10**12,
"tb": 10**12,
"p": 10**15,
"pb": 10**15,
"kib": 1024,
"mib": 1024**2,
"gib": 1024**3,
"tib": 1024**4,
"pib": 1024**5,
}
def to_bytes(val):
"""Convert a numeric or string size (e.g. '512m', '2GiB', 1024) to bytes.
Returns None for None/empty input. Raises AnsibleFilterError on an unparseable value.
"""
if val is None or val == "":
return None
if isinstance(val, (int, float)):
return int(val)
if not isinstance(val, str):
raise AnsibleFilterError(
f"to_bytes: unsupported size type: {type(val).__name__}"
)
m = _SIZE_RE.match(val)
if not m:
raise AnsibleFilterError(f"to_bytes: unrecognized size string: {val!r}")
num = float(m.group(1))
unit = (m.group(2) or "").lower()
if unit not in _MULT:
raise AnsibleFilterError(f"to_bytes: unknown unit in size: {unit!r}")
return int(num * _MULT[unit])