Source code for rudiments.humanize

# -*- coding: utf-8 -*-
# pylint: disable=bad-continuation
""" I/O of common values in forms understood by humans.
"""
# Copyright ©  2015 - 2019 Jürgen Hermann <jh@web.de>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import, unicode_literals, print_function


IEC_UNITS = ('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')


[docs]def bytes2iec(size, compact=False): """ Convert a size value in bytes to its equivalent in IEC notation. See `<http://physics.nist.gov/cuu/Units/binary.html>`_. Parameters: size (int): Number of bytes. compact (bool): If ``True``, the result contains no spaces. Return: String representation of ``size``. Raises: ValueError: Negative or out of bounds value for ``size``. """ postfn = lambda text: text.replace(' ', '') if compact else text if size < 0: raise ValueError("Negative byte size value {}".format(size)) if size < 1024: return postfn('{:4d} bytes'.format(size)) scaled = size for iec_unit in IEC_UNITS[1:]: scaled /= 1024.0 if scaled < 1024: return postfn('{:6.1f} {}'.format(scaled, iec_unit)) raise ValueError("Byte size value {} out of bounds".format(size))
[docs]def iec2bytes(size_spec, only_positive=True): """ Convert a size specification, optionally containing a scaling unit in IEC notation, to a number of bytes. Parameters: size_spec (str): Number, optionally followed by a unit. only_positive (bool): Allow only positive values? Return: Numeric bytes size. Raises: ValueError: Unknown unit specifiers, or bad leading integer. """ scale = 1 try: size = int(0 + size_spec) # return numeric values as-is except (TypeError, ValueError): spec = size_spec.strip().lower() for exp, iec_unit in enumerate(IEC_UNITS[1:], 1): iec_unit = iec_unit.lower() if spec.endswith(iec_unit): spec = spec[:-len(iec_unit)] scale = 2 ** (10 * exp) break elif spec.endswith(iec_unit[0]): spec = spec[:-1] scale = 2 ** (10 * exp) break else: if spec.endswith('b'): spec = spec[:-1] try: if '.' in spec: size = float(spec.strip()) else: size = int(spec.strip(), base=0) except (TypeError, ValueError) as cause: raise ValueError('Invalid bytes size specification {!r}: {}'.format(size_spec, cause)) if only_positive and size < 0: raise ValueError('Invalid negative bytes size specification {!r}'.format(size_spec)) return int(size * scale)
[docs]def merge_adjacent(numbers, indicator='..', base=0): """ Merge adjacent numbers in an iterable of numbers. Parameters: numbers (list): List of integers or numeric strings. indicator (str): Delimiter to indicate generated ranges. base (int): Passed to the `int()` conversion when comparing numbers. Return: list of str: Condensed sequence with either ranges or isolated numbers. """ integers = list(sorted([(int("%s" % i, base), i) for i in numbers])) idx = 0 result = [] while idx < len(numbers): end = idx + 1 while end < len(numbers) and integers[end-1][0] == integers[end][0] - 1: end += 1 result.append("%s%s%s" % (integers[idx][1], indicator, integers[end-1][1]) if end > idx + 1 else "%s" % integers[idx][1]) idx = end return result