commit c90e87ca9a8b70319a58d2222ee7e328f8af00d3 Author: Damian Johnson atagar@torproject.org Date: Sat Oct 17 16:37:51 2020 -0700
Normalize label input arguments
Functions like size_label() and time_label() are documented as taking an int argument, but getting a float shouldn't make them choke. Especially in such an unhelpful way...
====================================================================== ERROR: test_time_label Checks the time_label() function. ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/atagar/Desktop/stem/test/unit/util/str_tools.py", line 99, in test_time_label self.assertEqual('0s', str_tools.time_label(0.1)) File "/home/atagar/Desktop/stem/stem/util/str_tools.py", line 366, in time_label return _get_label(TIME_UNITS, seconds, decimal, is_long) File "/home/atagar/Desktop/stem/stem/util/str_tools.py", line 595, in _get_label raise ValueError('BUG: %s should always be divisible by a unit (%s)' % (count, str(units))) ValueError: BUG: 0.1 should always be divisible by a unit (((86400.0, 'd', ' day'), (3600.0, 'h', ' hour'), (60.0, 'm', ' minute'), (1.0, 's', ' second'))) --- stem/util/str_tools.py | 35 ++++++++++++++++++++++++----------- test/unit/util/str_tools.py | 1 + 2 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/stem/util/str_tools.py b/stem/util/str_tools.py index 64bcfc46..9803d437 100644 --- a/stem/util/str_tools.py +++ b/stem/util/str_tools.py @@ -329,6 +329,9 @@ def size_label(byte_count: int, decimal: int = 0, is_long: bool = False, is_byte :returns: **str** with human readable representation of the size """
+ if isinstance(byte_count, float): + byte_count = int(byte_count) + if is_bytes: return _get_label(SIZE_UNITS_BYTES, byte_count, decimal, is_long, round) else: @@ -363,6 +366,9 @@ def time_label(seconds: int, decimal: int = 0, is_long: bool = False) -> str: :returns: **str** with human readable representation of the time """
+ if isinstance(seconds, float): + seconds = int(seconds) + return _get_label(TIME_UNITS, seconds, decimal, is_long)
@@ -386,6 +392,9 @@ def time_labels(seconds: int, is_long: bool = False) -> Sequence[str]: :returns: **list** of strings with human readable representations of the time """
+ if isinstance(seconds, float): + seconds = int(seconds) + time_labels = []
for count_per_unit, _, _ in TIME_UNITS: @@ -416,6 +425,9 @@ def short_time_label(seconds: int) -> str: :raises: **ValueError** if the input is negative """
+ if isinstance(seconds, float): + seconds = int(seconds) + if seconds < 0: raise ValueError("Input needs to be a non-negative integer, got '%i'" % seconds)
@@ -560,35 +572,36 @@ def _get_label(units: Sequence[Tuple[float, str, str]], count: int, decimal: int
# formatted string for the requested number of digits label_format = '%%.%if' % decimal + remainder = count
- if count < 0: + if remainder < 0: label_format = '-' + label_format - count = abs(count) - elif count == 0: + remainder = abs(remainder) + elif remainder == 0: units_label = units[-1][2] + 's' if is_long else units[-1][1] return '%s%s' % (label_format % count, units_label)
for count_per_unit, short_label, long_label in units: - if count >= count_per_unit: + if remainder >= count_per_unit: if not round: - # Rounding down with a '%f' is a little clunky. Reducing the count so - # it'll divide evenly as the rounded down value. + # Rounding down with a '%f' is a little clunky. Reducing the remainder + # so it'll divide evenly as the rounded down value.
- count -= count % (count_per_unit / (10 ** decimal)) + remainder -= remainder % (count_per_unit / (10 ** decimal))
- count_label = label_format % (count / count_per_unit) + count_label = label_format % (remainder / count_per_unit)
if is_long: # Pluralize if any of the visible units make it greater than one. For # instance 1.0003 is plural but 1.000 isn't.
if decimal > 0: - is_plural = count > count_per_unit + is_plural = remainder > count_per_unit else: - is_plural = count >= count_per_unit * 2 + is_plural = remainder >= count_per_unit * 2
return count_label + long_label + ('s' if is_plural else '') else: return count_label + short_label
- raise ValueError('BUG: value should always be divisible by a unit (%s)' % str(units)) + raise ValueError('BUG: %s should always be divisible by a unit (%s)' % (count, str(units))) diff --git a/test/unit/util/str_tools.py b/test/unit/util/str_tools.py index ee270717..8b0365f7 100644 --- a/test/unit/util/str_tools.py +++ b/test/unit/util/str_tools.py @@ -96,6 +96,7 @@ class TestStrTools(unittest.TestCase): self.assertEqual('1.01 minutes', str_tools.time_label(61, 2, True))
self.assertEqual('0s', str_tools.time_label(0)) + self.assertEqual('0s', str_tools.time_label(0.1)) self.assertEqual('0 seconds', str_tools.time_label(0, is_long = True)) self.assertEqual('0.00s', str_tools.time_label(0, 2)) self.assertEqual('-10s', str_tools.time_label(-10))