Skip to content

Commit

Permalink
Added to_number function to misc_utils.
Browse files Browse the repository at this point in the history
  • Loading branch information
dmichaels-harvard committed Aug 7, 2024
1 parent b92adff commit f0aa788
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 13 deletions.
21 changes: 14 additions & 7 deletions dcicutils/misc_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1022,17 +1022,17 @@ def to_integer(value: str, fallback: Optional[Any] = None, strict: bool = False)
def to_number(value: str,
allow_commas: bool = False,
allow_multiplier_suffix: bool = False,
as_float: bool = False,
allow_float: bool = False,
fallback: Optional[Union[int, float]] = None) -> Optional[Union[int, float]]:

"""
Converts the give string value to an int, or float if as_float is True.
Converts the give string value to an int, or possibly float if allow_float is True.
If allow_commas is True (default: False) then allow commas (only) every three digits.
If allow_multiplier_suffix is True (default: False) allow any of K, Kb, KB; or M, Mb, MB;
or G, Gb, or GB; or T, Tb, TB, to mean multiply value by one thousand; one million;
one billion; or one trillion; respectively. If as_float is True (default: False)
one billion; or one trillion; respectively. If allow_float is True (default: False)
allow the value to be floating point (i.e. with a decimal point and a fractional part),
in which case the returned value will be of type float rather than int.
in which case the returned value will be of type float, if it needs to be, and not int.
If the string is not well formated then returns None.
"""
if not (isinstance(value, str) and (value := value.strip())):
Expand All @@ -1058,10 +1058,11 @@ def to_number(value: str,
return fallback
break

if as_float is True:
if allow_float is True:
if (dot_index := value.rfind(".")) >= 0:
if value_fraction := value[dot_index + 1:].strip():
try:
# value_fraction = float(f"0.{value_fraction}")
value_fraction = float(f"0.{value_fraction}")
except Exception:
return fallback
Expand All @@ -1075,15 +1076,21 @@ def to_number(value: str,
if not value.isdigit():
return fallback

result = int(value) * value_multiplier
result = int(value)

if value_fraction:
result += value_fraction

result *= value_multiplier

if value_negative:
result = -result

return float(result) if as_float is True else result
if allow_float is True:
if result == int(result):
result = int(result)

return result


def to_float(value: str, fallback: Optional[Any] = None) -> Optional[Any]:
Expand Down
4 changes: 2 additions & 2 deletions dcicutils/structured_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ def _map_function_integer(self, typeinfo: dict) -> Callable:
allow_multiplier_suffix = typeinfo.get("allow_multiplier_suffix") is True
def map_integer(value: str, src: Optional[str]) -> Any: # noqa
nonlocal allow_commas, allow_multiplier_suffix
return to_number(value, fallback=value, as_float=False,
return to_number(value, fallback=value, allow_float=False,
allow_commas=allow_commas,
allow_multiplier_suffix=allow_multiplier_suffix)
return map_integer
Expand All @@ -737,7 +737,7 @@ def _map_function_number(self, typeinfo: dict) -> Callable:
allow_multiplier_suffix = typeinfo.get("allow_multiplier_suffix") is True
def map_number(value: str, src: Optional[str]) -> Any: # noqa
nonlocal allow_commas, allow_multiplier_suffix
return to_number(value, fallback=value, as_float=True,
return to_number(value, fallback=value, allow_float=True,
allow_commas=allow_commas,
allow_multiplier_suffix=allow_multiplier_suffix)
return map_number
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "dcicutils"
version = "8.13.3.1b22" # TODO: To become 8.14.0
version = "8.13.3.1b23" # TODO: To become 8.14.0
description = "Utility package for interacting with the 4DN Data Portal and other 4DN resources"
authors = ["4DN-DCIC Team <[email protected]>"]
license = "MIT"
Expand Down
8 changes: 5 additions & 3 deletions test/test_misc_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3733,11 +3733,11 @@ def test_to_number():
assert to_number("1234") == 1234
assert to_number("1,234,567") is None
assert to_number("27500") == 27500
assert to_number("789", as_float=True) == 789.0
assert type(to_number("789", as_float=True)) == float
assert to_number("789", allow_float=True) == 789.0
# assert type(to_number("789", allow_float=True)) == float
assert to_number("27500", allow_commas=True) == 27500
assert to_number("1,234,567", allow_commas=True) == 1234567
assert to_number("1234.0567", as_float=True) == 1234.0567
assert to_number("1234.0567", allow_float=True) == 1234.0567
assert to_number("1K", allow_multiplier_suffix=True) == 1000
assert to_number("1Kb", allow_multiplier_suffix=True) == 1000
assert to_number("1KB", allow_multiplier_suffix=True) == 1000
Expand All @@ -3756,5 +3756,7 @@ def test_to_number():
assert to_number("-1,234,567K", allow_commas=True, allow_multiplier_suffix=True) == -1234567000
assert to_number(4321) == 4321
assert to_number(4321.1234) == 4321.1234
assert to_number("1.5K", allow_multiplier_suffix=True, allow_float=True) == 1500
assert type(to_number("1.5K", allow_multiplier_suffix=True, allow_float=True)) == int
# TODO: More ...
pass

0 comments on commit f0aa788

Please sign in to comment.