def _is_int(value: object) -> bool: return isinstance(value, int) and not isinstance(value, bool) def meter_advance(opening_read: int, closing_read: int, digits: int) -> int: """Units a meter advanced between two reads. A closing read lower than the opening read means the register rolled over past all nines, once. """ if not _is_int(digits) or digits < 1 or digits > 15: raise ValueError("digits must be a whole number from 1 to 15, received %s" % (digits,)) span = 10**digits for read in (opening_read, closing_read): if not _is_int(read) or read < 0 or read >= span: raise ValueError( "reads must be whole numbers from 0 to %d for a %d-digit meter, received %s" % (span - 1, digits, read) ) if closing_read >= opening_read: return closing_read - opening_read return closing_read + span - opening_read