From 96916d2abdd2a9246e51def8e8e6b5a0c175c2b5 Mon Sep 17 00:00:00 2001 From: stijndcl Date: Fri, 1 Jul 2022 12:43:41 +0200 Subject: [PATCH] Re-create & test number converter --- didier/utils/discord/converters/__init__.py | 0 didier/utils/discord/converters/numbers.py | 42 ++++++++++++++++ .../test_discord/test_converters/__init__.py | 0 .../test_converters/test_numbers.py | 50 +++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 didier/utils/discord/converters/__init__.py create mode 100644 didier/utils/discord/converters/numbers.py create mode 100644 tests/test_didier/test_utils/test_discord/test_converters/__init__.py create mode 100644 tests/test_didier/test_utils/test_discord/test_converters/test_numbers.py diff --git a/didier/utils/discord/converters/__init__.py b/didier/utils/discord/converters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/didier/utils/discord/converters/numbers.py b/didier/utils/discord/converters/numbers.py new file mode 100644 index 0000000..bd0f432 --- /dev/null +++ b/didier/utils/discord/converters/numbers.py @@ -0,0 +1,42 @@ +import math +from typing import Optional + + +def abbreviated_number(argument: str) -> int: + """Custom converter to allow numbers to be abbreviated + Examples: + 515k + 4m + """ + if not argument: + raise ValueError + + if argument.isdecimal(): + return int(argument) + + units = {"k": 3, "m": 6, "b": 9, "t": 12} + + # Get the unit if there is one, then chop it off + unit: Optional[str] = None + if not argument[-1].isdigit(): + if argument[-1].lower() not in units: + raise ValueError + + unit = argument[-1].lower() + argument = argument[:-1] + + # [int][unit] + if "." not in argument and unit is not None: + return int(argument) * (10 ** units.get(unit)) + + # [float][unit] + if "." in argument: + # Floats themselves are not supported + if unit is None: + raise ValueError + + as_float = float(argument) + return math.floor(as_float * (10 ** units.get(unit))) + + # Unparseable + raise ValueError diff --git a/tests/test_didier/test_utils/test_discord/test_converters/__init__.py b/tests/test_didier/test_utils/test_discord/test_converters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_didier/test_utils/test_discord/test_converters/test_numbers.py b/tests/test_didier/test_utils/test_discord/test_converters/test_numbers.py new file mode 100644 index 0000000..3efc9f4 --- /dev/null +++ b/tests/test_didier/test_utils/test_discord/test_converters/test_numbers.py @@ -0,0 +1,50 @@ +import pytest + +from didier.utils.discord.converters import numbers + + +def test_abbreviated_int(): + """Test abbreviated_number for a regular int""" + assert numbers.abbreviated_number("500") == 500 + + +def test_abbreviated_float_errors(): + """Test abbreviated_number for a float""" + with pytest.raises(ValueError): + numbers.abbreviated_number("5.4") + + +def test_abbreviated_int_unit(): + """Test abbreviated_number for an int combined with a unit""" + assert numbers.abbreviated_number("20k") == 20000 + + +def test_abbreviated_int_unknown_unit(): + """Test abbreviated_number for an int combined with an unknown unit""" + with pytest.raises(ValueError): + numbers.abbreviated_number("20p") + + +def test_abbreviated_float_unit(): + """Test abbreviated_number for a float combined with a unit""" + assert numbers.abbreviated_number("20.5k") == 20500 + + +def test_abbreviated_float_unknown_unit(): + """Test abbreviated_number for a float combined with an unknown unit""" + with pytest.raises(ValueError): + numbers.abbreviated_number("20.5p") + + +def test_abbreviated_no_number(): + """Test abbreviated_number for unparseable content""" + with pytest.raises(ValueError): + numbers.abbreviated_number("didier") + + +def test_abbreviated_float_floors(): + """Test abbreviated_number for a float that is longer than the unit + Example: + 5.3k is 5300, but 5.3001k is 5300.1 + """ + assert numbers.abbreviated_number("5.3001k") == 5300