Repository: jameslamb/pydistcheck (language: python)

Issue:
[feature request] accept sizes in Mi, Gi
### What change would you like to see?

Any configuration accepting MB and GB should accept Mi and Gi too.

### How would implementing this improve `pydistcheck`?

PyPI expresses file limits in these terms. Accepting them in `pydistcheck` would make it a bit easier to use this tool as a way to prevent going over those limits.

### Notes

See the k8s docs for some guidance on spelling these units.


Discussion / hints:

Fix patch:
diff --git a/src/pydistcheck/cli.py b/src/pydistcheck/cli.py
index 263c6a8..0c33e10 100644
--- a/src/pydistcheck/cli.py
+++ b/src/pydistcheck/cli.py
@@ -126,12 +126,15 @@ class ExitCodes:
     show_default=True,
     type=str,
     help=(
-        "maximum allowed compressed size, a string like '1.5M' indicating"
+        "maximum allowed compressed size, a string like '1.5MB' indicating"
         " '1.5 megabytes'. Supported units:\n"
         "  - B = bytes\n"
-        "  - K = kilobytes\n"
-        "  - M = megabytes\n"
-        "  - G = gigabytes"
+        "  - KB = kilobytes\n"
+        "  - K, Ki = kibibytes\n"
+        "  - MB = megabytes\n"
+        "  - M, Mi = mebibytes\n"
+        "  - GB = gigabytes\n"
+        "  - G, Gi = gibibytes"
     ),
 )
 @click.option(
@@ -140,12 +143,15 @@ class ExitCodes:
     show_default=True,
     type=str,
     help=(
-        "maximum allowed uncompressed size, a string like '1.5M' indicating"
+        "maximum allowed uncompressed size, a string like '1.5MB' indicating"
         " '1.5 megabytes'. Supported units:\n"
         "  - B = bytes\n"
-        "  - K = kilobytes\n"
-        "  - M = megabytes\n"
-        "  - G = gigabytes"
+        "  - KB = kilobytes\n"
+        "  - K, Ki = kibibytes\n"
+        "  - MB = megabytes\n"
+        "  - M, Mi = mebibytes\n"
+        "  - GB = gigabytes\n"
+        "  - G, Gi = gibibytes"
     ),
 )
 @click.option(
diff --git a/src/pydistcheck/utils.py b/src/pydistcheck/utils.py
index f630859..b04843c 100644
--- a/src/pydistcheck/utils.py
+++ b/src/pydistcheck/utils.py
@@ -5,7 +5,23 @@
 
 from typing import Tuple
 
-_UNIT_TO_NUM_BYTES = {"B": 1, "K": 1024, "M": 1024**2, "G": 1024**3}
+# references:
+#
+#   * https://physics.nist.gov/cuu/Units/binary.html
+#   * https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-memory
+#
+_UNIT_TO_NUM_BYTES = {
+    "b": 1,
+    "k": 1024,
+    "kb": 1000,
+    "ki": 1024,
+    "m": 1024**2,
+    "mb": 1000000,
+    "mi": 1024**2,
+    "g": 1024**3,
+    "gb": 1000000000,
+    "gi": 1024**3,
+}
 
 
 def _recommend_size_str(num_bytes: int) -> Tuple[float, str]:
@@ -35,7 +51,7 @@ def from_string(cls, size_str: str) -> "_FileSize":
 
     @property
     def total_size_bytes(self) -> int:
-        return int(self._num * _UNIT_TO_NUM_BYTES[self._unit_str])
+        return int(self._num * _UNIT_TO_NUM_BYTES[self._unit_str.lower()])
 
     def __eq__(self, other: object) -> bool:
         return (


Test patch:
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 1bf2e86..174ea94 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -3,9 +3,33 @@
 from pydistcheck.utils import _FileSize
 
 
-def test_file_size_minimally_works():
-    fs = _FileSize(num=1.0, unit_str="G")
-    assert fs.total_size_bytes == int(1024**3)
+@pytest.mark.parametrize(
+    ("unit_str", "expected_total_bytes"),
+    [
+        ("B", 3),
+        ("K", 3 * 1024),
+        ("KB", 3e3),
+        ("kB", 3e3),
+        ("kb", 3e3),
+        ("Ki", 3 * 1024),
+        ("ki", 3 * 1024),
+        ("M", 3 * (1024**2)),
+        ("MB", 3e6),
+        ("mB", 3e6),
+        ("mb", 3e6),
+        ("Mi", 3 * (1024**2)),
+        ("mi", 3 * (1024**2)),
+        ("G", 3 * (1024**3)),
+        ("GB", 3e9),
+        ("gB", 3e9),
+        ("gb", 3e9),
+        ("Gi", 3 * (1024**3)),
+        ("gi", 3 * (1024**3)),
+    ],
+)
+def test_file_size_minimally_works(expected_total_bytes, unit_str):
+    fs = _FileSize(num=3.0, unit_str=unit_str)
+    assert fs.total_size_bytes == int(expected_total_bytes)
 
 
 def test_file_size_comparisons_work():