Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 51 additions & 72 deletions src/humanize/filesize.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,96 +4,75 @@

from math import log

suffixes = {
from humanize.i18n import gettext as _
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from humanize.i18n import gettext as _
from humanize.i18n import _gettext as _


_SUFFIXES = {
"decimal": (
" kB",
" MB",
" GB",
" TB",
" PB",
" EB",
" ZB",
" YB",
" RB",
" QB",
_(" kB"),
_(" MB"),
_(" GB"),
_(" TB"),
_(" PB"),
_(" EB"),
_(" ZB"),
_(" YB"),
_(" RB"),
_(" QB"),
),
"binary": (
" KiB",
" MiB",
" GiB",
" TiB",
" PiB",
" EiB",
" ZiB",
" YiB",
" RiB",
" QiB",
_(" KiB"),
_(" MiB"),
_(" GiB"),
_(" TiB"),
_(" PiB"),
_(" EiB"),
_(" ZiB"),
_(" YiB"),
_(" RiB"),
_(" QiB"),
Comment on lines +11 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've included the space in the translated text here, but not in the .mo, so they won't match up.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These binary "KiB", "MiB", ... values are missing from the .mo.

),
"gnu": "KMGTPEZYRQ",
}


def naturalsize(
value: float | str,
binary: bool = False,
gnu: bool = False,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't remove this, it's a breaking API change.

format: str = "%.1f",
) -> str:
"""Format a number of bytes like a human-readable filesize (e.g. 10 kB).

By default, decimal suffixes (kB, MB) are used.

Non-GNU modes are compatible with jinja2's `filesizeformat` filter.
"""Format a number of bytes like a human-readable file size.

Examples:
```pycon
>>> naturalsize(3000000)
'3.0 MB'
>>> naturalsize(300, False, True)
'300B'
>>> naturalsize(3000, False, True)
'2.9K'
>>> naturalsize(3000, False, True, "%.3f")
'2.930K'
>>> naturalsize(3000, True)
'2.9 KiB'
>>> naturalsize(10**28)
'10.0 RB'
>>> naturalsize(10**34 * 3)
'30000.0 QB'
>>> naturalsize(-4096, True)
'-4.0 KiB'
>>> naturalsize(42)
'42 Bytes'
>>> naturalsize(42000)
'42.0 kB'
>>> naturalsize(42000000)
'42.0 MB'

```
When a locale is activated via ``humanize.i18n.activate()``,
the unit suffixes will be translated accordingly.

Args:
value (int, float, str): Integer to convert.
binary (bool): If `True`, uses binary suffixes (KiB, MiB) with base
2<sup>10</sup> instead of 10<sup>3</sup>.
gnu (bool): 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.

Returns:
str: Human readable representation of a filesize.
:param value: The number of bytes.
:param binary: Use binary (powers of 1024) units instead of decimal.
:param format: Numeric format string.
:return: Human-readable file size.
"""
if gnu:
suffix = suffixes["gnu"]
elif binary:
suffix = suffixes["binary"]
else:
suffix = suffixes["decimal"]
try:
bytes_value = float(value)
except (TypeError, ValueError):
return str(value)

if bytes_value == 1:
return _("1 Byte")
if bytes_value < 1024:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't hardcode 1024, use base

return _("%d Bytes") % bytes_value

base = 1024 if (gnu or binary) else 1000
bytes_ = float(value)
abs_bytes = abs(bytes_)
base = 1024 if binary else 1000
exp = int(log(bytes_value, base))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work for negative numbers:

>>> from math import log
>>> log(-1)
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    log(-1)
    ~~~^^^^
ValueError: expected a positive input

exp = min(exp, len(_SUFFIXES["binary"]) if binary else len(_SUFFIXES["decimal"]))

if abs_bytes == 1 and not gnu:
return f"{int(bytes_)} Byte"
value = bytes_value / base**exp

if abs_bytes < base:
return f"{int(bytes_)}B" if gnu else f"{int(bytes_)} Bytes"
suffix = _SUFFIXES["binary"][exp - 1] if binary else _SUFFIXES["decimal"][exp - 1]

exp = int(min(log(abs_bytes, base), len(suffix)))
ret: str = format % (bytes_ / (base**exp)) + suffix[exp - 1]
return ret
return (format % value) + suffix
31 changes: 31 additions & 0 deletions src/humanize/locale/fr_FR/LC_MESSAGES/humanize.po
Original file line number Diff line number Diff line change
Expand Up @@ -363,3 +363,34 @@ msgstr "hier"
#, python-format
msgid "%s and %s"
msgstr "%s et %s"

# --- filesize units (naturalsize) ---
msgid "Byte"
msgstr "octet"

msgid "Bytes"
msgstr "octets"

msgid "kB"
msgstr "Ko"

msgid "MB"
msgstr "Mo"

msgid "GB"
msgstr "Go"

msgid "TB"
msgstr "To"

msgid "PB"
msgstr "Po"

msgid "EB"
msgstr "Eo"

msgid "ZB"
msgstr "Zo"

msgid "YB"
msgstr "Yo"
Loading