Skip to content

Commit

Permalink
feat/nice_bytes (MycroftAI#19)
Browse files Browse the repository at this point in the history
Co-authored-by: jarbasal <jarbasai@mailfence.com>
  • Loading branch information
JarbasAl and JarbasAl authored May 9, 2021
1 parent 92b0b34 commit 79fe4a5
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 2 deletions.
50 changes: 50 additions & 0 deletions lingua_nostra/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,3 +566,53 @@ def nice_response(text, lang=''):
assertEqual(nice_response_de("10 ^ 2"),
"10 hoch 2")
"""


@localized_function(run_own_code_on=[FunctionNotLocalizedError])
def nice_bytes(number, lang='', speech=True, binary=True, gnu=False):
"""
turns a number of bytes into a string using appropriate units
prefixes - https://en.wikipedia.org/wiki/Binary_prefix
spoken binary units - https://en.wikipedia.org/wiki/Kibibyte
implementation - http://stackoverflow.com/a/1094933/2444609
:param number: number of bytes (int)
:param lang: lang_code, ignored for now (str)
:param speech: spoken form (True) or short units (False)
:param binary: 1 kilobyte = 1024 bytes (True) or 1 kilobyte = 1000 bytes (False)
:param gnu: say only order of magnitude (bool) - 100 Kilo (True) or 100 Kilobytes (False)
:return: nice bytes (str)
"""
if speech and gnu:
default_units = ['Bytes', 'Kilo', 'Mega', 'Giga', 'Tera', 'Peta',
'Exa', 'Zetta', 'Yotta']
elif speech and binary:
default_units = ['Bytes', 'Kibibytes', 'Mebibytes', 'Gibibytes',
'Tebibytes', 'Pebibytes', 'Exbibytes', 'Zebibytes',
'Yobibytes']
elif speech:
default_units = ['Bytes', 'Kilobytes', 'Megabytes', 'Gigabytes',
'Terabytes', 'Petabytes', 'Exabytes', 'Zettabytes',
'Yottabytes']
elif gnu:
default_units = ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
elif binary:
default_units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB',
'YiB']
else:
default_units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']

units = default_units

if binary:
n = 1024
else:
n = 1000

for unit in units[:-1]:
if abs(number) < n:
if number == 1 and speech and not gnu:
# strip final "s"
unit = unit[:-1]
return "%3.1f %s" % (number, unit)
number /= n
return "%.1f %s" % (number, units[-1])
8 changes: 8 additions & 0 deletions lingua_nostra/internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,14 @@ def _call_localized_function(func, *args, **kwargs):
# If we didn't find a localized function to correspond with
# the wrapped function, we cached NotImplementedError in its
# place.

# first account for the function not being present in any
# module, meaning all modules are falling back to a catch all
# parser, this usually means the function will need localization
# only in future languages not currently supported
if func_name not in _localized_functions[_module_name][lang_code]:
raise FunctionNotLocalizedError(func_name, lang_code)

loc_signature = _localized_functions[_module_name][lang_code][func_name]
if isinstance(loc_signature, type(NotImplementedError())):
raise loc_signature
Expand Down
133 changes: 131 additions & 2 deletions test/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from lingua_nostra.format import pronounce_number
from lingua_nostra.format import date_time_format
from lingua_nostra.format import join_list
from lingua_nostra.format import nice_bytes


def setUpModule():
Expand Down Expand Up @@ -80,7 +81,6 @@ def tearDownModule():


class TestNiceNumberFormat(unittest.TestCase):

tmp_var = None

def set_tmp_var(self, val):
Expand Down Expand Up @@ -116,6 +116,7 @@ def test_unknown_language(self):
""" An unknown / unhandled language should return the string
representation of the input number.
"""

def bypass_warning():
self.assertEqual(
nice_number(5.5, lang='as-df'), '5.5',
Expand Down Expand Up @@ -384,6 +385,7 @@ def test_ordinals(self):
short_scale=False), "eighteen "
"trillionth")


# def nice_time(dt, lang="en-us", speech=True, use_24hour=False,
# use_ampm=False):

Expand Down Expand Up @@ -600,7 +602,7 @@ def test_nice_year(self):
self.assertTrue(len(nice_year(dt, lang=lang)) > 0)
# Looking through the date sequence can be helpful

# print(nice_year(dt, lang=lang))
# print(nice_year(dt, lang=lang))

def test_nice_duration(self):
self.assertEqual(nice_duration(1), "one second")
Expand Down Expand Up @@ -637,5 +639,132 @@ def test_join(self):
self.assertEqual(join_list([1, "b", 3, "d"], "or"), "1, b, 3 or d")


class TestNiceBytes(unittest.TestCase):

def test_nice_bytes_non_binary_speech(self):
self.assertEqual(nice_bytes(0, binary=False), "0.0 Bytes")
self.assertEqual(nice_bytes(1, binary=False), "1.0 Byte")
self.assertEqual(nice_bytes(1000, binary=False), "1.0 Kilobyte")
self.assertEqual(nice_bytes(2000000, binary=False), "2.0 Megabytes")
self.assertEqual(nice_bytes(2000000000, binary=False), "2.0 Gigabytes")
self.assertEqual(nice_bytes(2000000000000, binary=False),
"2.0 Terabytes")
self.assertEqual(nice_bytes(2000000000000000, binary=False),
"2.0 Petabytes")
self.assertEqual(nice_bytes(2000000000000000000, binary=False),
"2.0 Exabytes")
self.assertEqual(nice_bytes(2000000000000000000000, binary=False),
"2.0 Zettabytes")
self.assertEqual(nice_bytes(2000000000000000000000000, binary=False),
"2.0 Yottabytes")
# no more named prefixes after Y - https://en.wikipedia.org/wiki/Binary_prefix
self.assertEqual(
nice_bytes(2000000000000000000000000000, binary=False),
"2000.0 Yottabytes")

def test_nice_bytes_non_binary(self):
self.assertEqual(nice_bytes(0, speech=False, binary=False), "0.0 B")
self.assertEqual(nice_bytes(1000, speech=False, binary=False),
"1.0 KB")
self.assertEqual(nice_bytes(1024, speech=False, binary=False),
"1.0 KB")
self.assertEqual(nice_bytes(2000000, speech=False, binary=False),
"2.0 MB")
self.assertEqual(nice_bytes(2000000000, speech=False, binary=False),
"2.0 GB")
self.assertEqual(nice_bytes(2000000000000, speech=False, binary=False),
"2.0 TB")
self.assertEqual(
nice_bytes(2000000000000000, speech=False, binary=False), "2.0 PB")
self.assertEqual(
nice_bytes(2000000000000000000, speech=False, binary=False),
"2.0 EB")
self.assertEqual(
nice_bytes(2000000000000000000000, speech=False, binary=False),
"2.0 ZB")
self.assertEqual(
nice_bytes(2000000000000000000000000, speech=False, binary=False),
"2.0 YB")
# no more named prefixes after Y - https://en.wikipedia.org/wiki/Binary_prefix
self.assertEqual(nice_bytes(2000000000000000000000000000, speech=False,
binary=False), "2000.0 YB")

def test_nice_bytes_speech(self):
# https://en.wikipedia.org/wiki/Kibibyte
self.assertEqual(nice_bytes(0), "0.0 Bytes")
self.assertEqual(nice_bytes(1), "1.0 Byte")
self.assertEqual(nice_bytes(1000), "1000.0 Bytes")
self.assertEqual(nice_bytes(1024), "1.0 Kibibyte")
self.assertEqual(nice_bytes(2000000), "1.9 Mebibytes")
self.assertEqual(nice_bytes(2000000000), "1.9 Gibibytes")
self.assertEqual(nice_bytes(2000000000000), "1.8 Tebibytes")
self.assertEqual(nice_bytes(2000000000000000), "1.8 Pebibytes")
self.assertEqual(nice_bytes(2000000000000000000), "1.7 Exbibytes")
self.assertEqual(nice_bytes(2000000000000000000000), "1.7 Zebibytes")
self.assertEqual(nice_bytes(2000000000000000000000000),
"1.7 Yobibytes")
# no more named prefixes after Y - https://en.wikipedia.org/wiki/Binary_prefix
self.assertEqual(nice_bytes(2000000000000000000000000000),
"1654.4 Yobibytes")

def test_nice_bytes(self):
self.assertEqual(nice_bytes(0, speech=False), "0.0 B")
self.assertEqual(nice_bytes(1000, speech=False), "1000.0 B")
self.assertEqual(nice_bytes(1024, speech=False), "1.0 KiB")
self.assertEqual(nice_bytes(2000000, speech=False), "1.9 MiB")
self.assertEqual(nice_bytes(2000000000, speech=False), "1.9 GiB")
self.assertEqual(nice_bytes(2000000000000, speech=False), "1.8 TiB")
self.assertEqual(nice_bytes(2000000000000000, speech=False), "1.8 PiB")
self.assertEqual(nice_bytes(2000000000000000000, speech=False),
"1.7 EiB")
self.assertEqual(nice_bytes(2000000000000000000000, speech=False),
"1.7 ZiB")
self.assertEqual(nice_bytes(2000000000000000000000000, speech=False),
"1.7 YiB")
# no more named prefixes after Y - https://en.wikipedia.org/wiki/Binary_prefix
self.assertEqual(
nice_bytes(2000000000000000000000000000, speech=False),
"1654.4 YiB")

def test_nice_bytes_gnu(self):
self.assertEqual(nice_bytes(1024, gnu=True), "1.0 Kilo")
self.assertEqual(nice_bytes(2000000, gnu=True), "1.9 Mega")
self.assertEqual(nice_bytes(2000000000, gnu=True), "1.9 Giga")
self.assertEqual(nice_bytes(2000000000000, gnu=True), "1.8 Tera")

self.assertEqual(nice_bytes(0, speech=False, gnu=True), "0.0 B")
self.assertEqual(nice_bytes(1000, speech=False, gnu=True), "1000.0 B")
self.assertEqual(nice_bytes(1024, speech=False, gnu=True), "1.0 K")
self.assertEqual(nice_bytes(2000000, speech=False, gnu=True), "1.9 M")
self.assertEqual(nice_bytes(2000000000, speech=False, gnu=True),
"1.9 G")
self.assertEqual(nice_bytes(2000000000000, speech=False, gnu=True),
"1.8 T")
self.assertEqual(nice_bytes(2000000000000000, speech=False, gnu=True),
"1.8 P")
self.assertEqual(
nice_bytes(2000000000000000000, speech=False, gnu=True), "1.7 E")
self.assertEqual(
nice_bytes(2000000000000000000000, speech=False, gnu=True),
"1.7 Z")
self.assertEqual(
nice_bytes(2000000000000000000000000, speech=False, gnu=True),
"1.7 Y")
# no more named prefixes after Y - https://en.wikipedia.org/wiki/Binary_prefix
self.assertEqual(
nice_bytes(2000000000000000000000000000, speech=False, gnu=True),
"1654.4 Y")

self.assertEqual(nice_bytes(2000000, gnu=True, binary=False),
"2.0 Mega")
self.assertEqual(nice_bytes(2000000000, gnu=True, binary=False),
"2.0 Giga")
self.assertEqual(
nice_bytes(2000000, speech=False, gnu=True, binary=False), "2.0 M")
self.assertEqual(
nice_bytes(2000000000, speech=False, gnu=True, binary=False),
"2.0 G")


if __name__ == "__main__":
unittest.main()

0 comments on commit 79fe4a5

Please sign in to comment.