Skip to content
Snippets Groups Projects
Commit c90e87ca authored by Damian Johnson's avatar Damian Johnson
Browse files

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')))
parent 99396db3
No related branches found
No related tags found
No related merge requests found
......@@ -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)))
......@@ -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))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment