Repository: jmoiron/humanize

Issue:
Negative Sizes Only Show In Bytes
When using `naturalsize` with negative values (I wish to display a change in file size), you only get bytes:

```python
>>> In[4] import humanize
>>> In[5] humanize.naturalsize(123456)
>>> Out[5]: '123.5 kB'
>>> In[6] humanize.naturalsize(-123456)
>>> Out[6]: '-123456 Bytes'
````

Is it possible to get these values shown in the same manner as positive values?

Discussion:

Patch:
diff --git a/src/humanize/filesize.py b/src/humanize/filesize.py
index 754a9f3..694e264 100644
--- a/src/humanize/filesize.py
+++ b/src/humanize/filesize.py
@@ -10,12 +10,20 @@ suffixes = {
 
 
 def naturalsize(value, binary=False, gnu=False, format="%.1f"):
-    """Format a number of byteslike a human readable filesize (eg. 10 kB).  By
-    default, decimal suffixes (kB, MB) are used.  Passing binary=true will use
-    binary suffixes (KiB, MiB) are used and the base will be 2**10 instead of
-    10**3.  If ``gnu`` is True, the binary argument is ignored and GNU-style
-    (ls -sh style) prefixes are used (K, M) with the 2**10 definition.
-    Non-gnu modes are compatible with jinja2's ``filesizeformat`` filter."""
+    """Format a number of bytes like a human readable filesize (eg. 10 kB).
+
+    By default, decimal suffixes (kB, MB) are used.
+
+    Non-gnu modes are compatible with jinja2's ``filesizeformat`` filter.
+
+    Args:
+        value (int, float, string): Integer to convert.
+        binary (Boolean): If `True`, uses binary suffixes (KiB, MiB) with base 2**10
+        instead of 10**3.
+        gnu (Boolean): If `True`, the binary argument is ignored and GNU-style
+        (`ls -sh` style) prefixes are used (K, M) with the 2**10 definition.
+        format (str): Custom formatter.
+    """
     if gnu:
         suffix = suffixes["gnu"]
     elif binary:
@@ -25,19 +33,20 @@ def naturalsize(value, binary=False, gnu=False, format="%.1f"):
 
     base = 1024 if (gnu or binary) else 1000
     bytes = float(value)
+    abs_bytes = abs(bytes)
 
-    if bytes == 1 and not gnu:
-        return "1 Byte"
-    elif bytes < base and not gnu:
+    if abs_bytes == 1 and not gnu:
+        return "%d Byte" % bytes
+    elif abs_bytes < base and not gnu:
         return "%d Bytes" % bytes
-    elif bytes < base and gnu:
+    elif abs_bytes < base and gnu:
         return "%dB" % bytes
 
     for i, s in enumerate(suffix):
         unit = base ** (i + 2)
-        if bytes < unit and not gnu:
+        if abs_bytes < unit and not gnu:
             return (format + " %s") % ((base * bytes / unit), s)
-        elif bytes < unit and gnu:
+        elif abs_bytes < unit and gnu:
             return (format + "%s") % ((base * bytes / unit), s)
     if gnu:
         return (format + "%s") % ((base * bytes / unit), s)


Test patch:
diff --git a/tests/test_filesize.py b/tests/test_filesize.py
index 959ce88..871c61a 100644
--- a/tests/test_filesize.py
+++ b/tests/test_filesize.py
@@ -31,5 +31,9 @@ import pytest
         ([10 ** 26 * 30, True, False, "%.3f"], "2481.542 YiB"),
     ],
 )
-def test_naturaltime_minimum_unit_default(test_args, expected):
+def test_naturalsize(test_args, expected):
     assert humanize.naturalsize(*test_args) == expected
+
+    args_with_negative = test_args
+    args_with_negative[0] *= -1
+    assert humanize.naturalsize(*args_with_negative) == "-" + expected