changeset 3524:584379473925

tools (common/utils): new methods to parse and generate file size with symbols: - `parseSize` lets parse a size which can be either a int, or a string with a symbol like `Mio` - `getSizeMultiplier` returns a tuple of size with it's multiplier symbol - `getHumanSize` returns a string with size and adapted multiplier.
author Goffi <goffi@goffi.org>
date Wed, 05 May 2021 15:37:33 +0200
parents 30779935c0aa
children 7f5bf108961a
files sat/plugins/plugin_misc_file.py sat/tools/common/utils.py sat_frontends/jp/cmd_file.py
diffstat 3 files changed, 88 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/sat/plugins/plugin_misc_file.py	Wed May 05 15:37:21 2021 +0200
+++ b/sat/plugins/plugin_misc_file.py	Wed May 05 15:37:33 2021 +0200
@@ -29,6 +29,7 @@
 from sat.tools import xml_tools
 from sat.tools import stream
 from sat.tools import utils
+from sat.tools.common import utils as common_utils
 
 
 log = getLogger(__name__)
@@ -321,9 +322,7 @@
         assert filename and not "/" in filename
         assert PROGRESS_ID_KEY in file_data
         # human readable size
-        file_data["size_human"] = "{:.6n} Mio".format(
-            float(file_data["size"]) / (1024 ** 2)
-        )
+        file_data["size_human"] = common_utils.getHumanSize(file_data["size"])
         d = xml_tools.deferDialog(
             self.host,
             _(CONFIRM).format(peer=peer_jid.full(), **file_data),
--- a/sat/tools/common/utils.py	Wed May 05 15:37:21 2021 +0200
+++ b/sat/tools/common/utils.py	Wed May 05 15:37:33 2021 +0200
@@ -19,6 +19,42 @@
 """Misc utils for both backend and frontends"""
 
 import collections.abc
+size_units = {
+    "b": 1,
+    "kb": 1000,
+    "mb": 1000**2,
+    "gb": 1000**3,
+    "tb": 1000**4,
+    "pb": 1000**5,
+    "eb": 1000**6,
+    "zb": 1000**7,
+    "yb": 1000**8,
+    "o": 1,
+    "ko": 1000,
+    "mo": 1000**2,
+    "go": 1000**3,
+    "to": 1000**4,
+    "po": 1000**5,
+    "eo": 1000**6,
+    "zo": 1000**7,
+    "yo": 1000**8,
+    "kib": 1024,
+    "mib": 1024**2,
+    "gib": 1024**3,
+    "tib": 1024**4,
+    "pib": 1024**5,
+    "eib": 1024**6,
+    "zib": 1024**7,
+    "yib": 1024**8,
+    "kio": 1024,
+    "mio": 1024**2,
+    "gio": 1024**3,
+    "tio": 1024**4,
+    "pio": 1024**5,
+    "eio": 1024**6,
+    "zio": 1024**7,
+    "yio": 1024**8,
+}
 
 
 def per_luminance(red, green, blue):
@@ -73,3 +109,51 @@
 
     def update(self, items):
         self._dict.update({i: None for i in items})
+
+
+def parseSize(size):
+    """Parse a file size with optional multiple symbole"""
+    try:
+        return int(size)
+    except ValueError:
+        number = []
+        symbol = []
+        try:
+            for c in size:
+                if c == " ":
+                    continue
+                if c.isdigit():
+                    number.append(c)
+                elif c.isalpha():
+                    symbol.append(c)
+                else:
+                    raise ValueError("unexpected char in size: {c!r} (size: {size!r})")
+            number = int("".join(number))
+            symbol = "".join(symbol)
+            if symbol:
+                try:
+                    multiplier = size_units[symbol.lower()]
+                except KeyError:
+                    raise ValueError(
+                        "unknown size multiplier symbole: {symbol!r} (size: {size!r})")
+                else:
+                    return number * multiplier
+            return number
+        except Exception as e:
+            raise ValueError(f"invalid size: {e}")
+
+
+def getSizeMultiplier(size, suffix="o"):
+    """Get multiplier of a file size"""
+    size = int(size)
+    #  cf. https://stackoverflow.com/a/1094933 (thanks)
+    for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
+        if abs(size) < 1024.0:
+            return size, f"{unit}{suffix}"
+        size /= 1024.0
+    return size, f"Yi{suffix}"
+
+
+def getHumanSize(size, suffix="o", sep=" "):
+    size, symbol = getSizeMultiplier(size, suffix)
+    return f"{size:.2f}{sep}{symbol}"
--- a/sat_frontends/jp/cmd_file.py	Wed May 05 15:37:21 2021 +0200
+++ b/sat_frontends/jp/cmd_file.py	Wed May 05 15:37:33 2021 +0200
@@ -30,6 +30,7 @@
 from sat_frontends.jp import common
 from sat_frontends.tools import jid
 from sat.tools.common.ansi import ANSI as A
+from sat.tools.common import utils
 from urllib.parse import urlparse
 from pathlib import Path
 import tempfile
@@ -864,15 +865,7 @@
     def _size_filter(self, size, row):
         if not size:
             return ""
-        size = int(size)
-        #  cf. https://stackoverflow.com/a/1094933 (thanks)
-        suffix = "o"
-        for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
-            if abs(size) < 1024.0:
-                return A.color(A.BOLD, "{:.2f}".format(size), unit, suffix)
-            size /= 1024.0
-
-        return A.color(A.BOLD, "{:.2f}".format(size), "Yi", suffix)
+        return A.color(A.BOLD, utils.getHumanSize(size))
 
     def default_output(self, files_data):
         """display files a way similar to ls"""