houtianze/bypy

View on GitHub
bypy/printer_util.py

Summary

Maintainability
A
3 hrs
Test Coverage
#!/usr/bin/env python
# encoding: utf-8
# PYTHON_ARGCOMPLETE_OK

# this file exists to avoid circular dependencies
# from __future__ imports must occur at the beginning of the file
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division

import os
import math
import re

from . import const

def iswindows():
    return os.name == 'nt'

def human_time(seconds):
    ''' DocTests:
    >>> human_time(0) == ''
    True
    >>> human_time(122.1) == '2m2s'
    True
    >>> human_time(133) == '2m13s'
    True
    >>> human_time(12345678) == '20W2D21h21m18s'
    True
    '''
    isec = int(seconds)
    s = isec % 60
    m = isec // 60 % 60
    h = isec // 60 // 60 % 24
    d = isec // 60 // 60 // 24 % 7
    w = isec // 60 // 60 // 24 // 7

    result = ''
    for t in [ ('W', w), ('D', d), ('h', h), ('m', m), ('s', s) ]:
        if t[1]:
            result += str(t[1]) + t[0]

    return result

def limit_unit(timestr, num = 2):
    ''' DocTests:
    >>> limit_unit('1m2s', 1) == '1m'
    True
    >>> limit_unit('1m2s') == '1m2s'
    True
    >>> limit_unit('1m2s', 4) == '1m2s'
    True
    >>> limit_unit('1d2h3m2s') == '1d2h'
    True
    >>> limit_unit('1d2h3m2s', 1) == '1d'
    True
    '''
    l = len(timestr)
    i = 0
    p = 0
    while i < num and p <= l:
        at = 0
        while p < l:
            c = timestr[p]
            if at == 0:
                if c.isdigit():
                    p += 1
                else:
                    at += 1
            elif at == 1:
                if not c.isdigit():
                    p += 1
                else:
                    at += 1
            else:
                break

        i += 1

    return timestr[:p]

def human_time_short(seconds):
    return limit_unit(human_time(seconds))

def interpret_size(si):
    '''
    >>> interpret_size(10)
    10
    >>> interpret_size('10')
    10
    >>> interpret_size('10b')
    10
    >>> interpret_size('10k')
    10240
    >>> interpret_size('10K')
    10240
    >>> interpret_size('10kb')
    10240
    >>> interpret_size('10kB')
    10240
    >>> interpret_size('a10')
    Traceback (most recent call last):
    ValueError
    >>> interpret_size('10a')
    Traceback (most recent call last):
    KeyError: 'A'
    '''
    m = re.match(r"\s*(\d+)\s*([ac-z]?)(b?)\s*$", str(si), re.I)
    if m:
        if not m.group(2) and m.group(3):
            times = 1
        else:
            times = const.SIPrefixTimes[m.group(2).upper()] if m.group(2) else 1
        return int(m.group(1)) * times
    else:
        raise ValueError

def human_num(num, precision = 0, filler = ''):
    # https://stackoverflow.com/questions/15263597/python-convert-floating-point-number-to-certain-precision-then-copy-to-string/15263885#15263885
    numfmt = '{{:.{}f}}'.format(precision)
    exp = math.log(num, const.OneK) if num > 0 else 0
    expint = int(math.floor(exp))
    maxsize = len(const.SIPrefixNames) - 1
    if expint > maxsize:
        print("Ridiculously large number '{}' passed to 'human_num()'".format(num))
        expint = maxsize
    unit = const.SIPrefixNames[expint]
    return numfmt.format(num / float(const.OneK ** expint)) + filler + unit

def human_size(num, precision = 3):
    ''' DocTests:
    >>> human_size(1000, 0) == '1000B'
    True
    >>> human_size(1025) == '1.001kB'
    True
    '''
    return human_num(num, precision) + 'B'

def human_speed(speed, precision = 0):
    return human_num(speed, precision) + 'B/s'