Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add small_formatting argument to file_size #692

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
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
20 changes: 14 additions & 6 deletions src/human_readable/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@


def file_size(
value: int, binary: bool = False, gnu: bool = False, formatting: str = ".1f"
value: int,
binary: bool = False,
gnu: bool = False,
formatting: str = ".1f",
small_formatting: str = "",
) -> str:
"""Return human-readable file size.

Expand All @@ -12,12 +16,16 @@ def file_size(
`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.
small_formatting is used instead of formatting when the number of bytes
is small enough that the applied suffix is B / Byte / Bytes, since files
cannot have a decimal number of bytes in a file size

Args:
value: size number.
binary: binary format. Defaults to False.
gnu: GNU format. Defaults to False.
formatting: format pattern. Defaults to ".1f".
formatting: format pattern (applied to a float). Defaults to ".1f".
small_formatting: format pattern for small values (applied to an int). Defaults to "".

Returns:
str: file size in natural language.
Expand All @@ -27,16 +35,16 @@ def file_size(
elif binary:
suffixes = (" KiB", " MiB", " GiB", " TiB", " PiB", " EiB", " ZiB", " YiB")
else:
suffixes = (" kB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB")
suffixes = (" KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB")

base = 1024 if (gnu or binary) else 1000

if value == 1 and not gnu:
return f"{1:{formatting}} Byte"
return f"{1:{small_formatting}} Byte"
if value < base and not gnu:
return f"{value:{formatting}} Bytes"
return f"{value:{small_formatting}} Bytes"
if value < base and gnu:
return f"{value:{formatting}}B"
return f"{value:{small_formatting}}B"

byte_size = float(value)
suffix = ""
Expand Down
25 changes: 15 additions & 10 deletions tests/unit/test_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

import pytest

import human_readable.files as files
from human_readable import files


@pytest.mark.parametrize(
"params, expected",
[
(1, "1.0 Byte"), # unit number
(300, "300.0 Bytes"), # hundreds number
(1, "1 Byte"), # unit number
(300, "300 Bytes"), # hundreds number
(2900000, "2.9 MB"), # millions number
(2000000000, "2.0 GB"), # billions number
(10**26 * 30, "3000.0 YB"), # giant number
Expand All @@ -24,8 +24,8 @@ def test_file_size(params: int, expected: str) -> None:
@pytest.mark.parametrize(
"params, expected",
[
((1, True), "1.0 Byte"), # unit number
((300, True), "300.0 Bytes"), # hundreds number
((1, True), "1 Byte"), # unit number
((300, True), "300 Bytes"), # hundreds number
((2900000, True), "2.8 MiB"), # millions number
((2000000000, True), "1.9 GiB"), # billions number
((10**26 * 30, True), "2481.5 YiB"), # giant number
Expand All @@ -39,8 +39,8 @@ def test_file_size_binary(params: tuple[int, bool], expected: str) -> None:
@pytest.mark.parametrize(
"params, expected",
[
((1, False, True), "1.0B"), # unit number
((300, False, True), "300.0B"), # hundreds number
((1, False, True), "1B"), # unit number
((300, False, True), "300B"), # hundreds number
((2900000, False, True), "2.8M"), # millions number
((2000000000, False, True), "1.9G"), # billions number
((10**26 * 30, False, True), "2481.5Y"), # giant number
Expand All @@ -54,9 +54,14 @@ def test_file_size_gnu(params: tuple[int, bool, bool], expected: str) -> None:
@pytest.mark.parametrize(
"params, expected",
[
((1, False, True, ".0f"), "1B"), # unit number
((300, True, False, ".2f"), "300.00 Bytes"), # hundreds number
((2900000, False, True, ".3f"), "2.766M"), # millions number
((1, False, True, ".3f", ".1f"), "1.0B"), # unit number (small formatting)
((999, False, False, ".3f", ".1f"), "999.0 Bytes"), # hundreds number (small formatting)
((1000, False, False, ".3f", ".1f"), "1.000 KB"), # hundreds number (small formatting boundary)
((1023, False, True, ".3f", ".1f"), "1023.0B"), # hundreds number (small formatting boundary)
((1024, False, True, ".3f", ".1f"), "1.000K"), # hundreds number (small formatting boundary)
((1023, True, False, ".3f", ".1f"), "1023.0 Bytes"), # hundreds number (small formatting boundary)
((1024, True, False, ".3f", ".1f"), "1.000 KiB"), # hundreds number (small formatting boundary)
((2900000, False, True, ".3f"), "2.766M"), # millions number (large formatting)
(
(2000000000, True, False, ".3f"),
"1.863 GiB",
Expand Down