Print human readable sizes in downloads

This commit is contained in:
Florian Bruhin 2014-06-13 07:13:47 +02:00
parent 8c673ee66c
commit efd83f40ca
3 changed files with 60 additions and 3 deletions

View File

@ -26,7 +26,8 @@ import qutebrowser.config.config as config
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
from qutebrowser.utils.log import downloads as logger from qutebrowser.utils.log import downloads as logger
from qutebrowser.utils.usertypes import PromptMode from qutebrowser.utils.usertypes import PromptMode
from qutebrowser.utils.misc import interpolate_color, format_seconds from qutebrowser.utils.misc import (interpolate_color, format_seconds,
format_size)
class DownloadItem(QObject): class DownloadItem(QObject):
@ -94,9 +95,12 @@ class DownloadItem(QObject):
remaining = (format_seconds(self.remaining_time) remaining = (format_seconds(self.remaining_time)
if self.remaining_time is not None else if self.remaining_time is not None else
'?') '?')
speed = format_size(self.speed, suffix='B/s')
down = format_size(self.bytes_done, suffix='B')
total = format_size(self.bytes_total, suffix='B')
return '{name} [{speed}|{remaining}|{perc: 2}%|{down}/{total}]'.format( return '{name} [{speed}|{remaining}|{perc: 2}%|{down}/{total}]'.format(
name=self.basename, speed=self.speed, remaining=remaining, name=self.basename, speed=speed, remaining=remaining, perc=perc,
perc=perc, down=self.bytes_done, total=self.bytes_total) down=down, total=total)
def _die(self, msg): def _die(self, msg):
"""Abort the download and emit an error.""" """Abort the download and emit an error."""

View File

@ -553,5 +553,43 @@ class FormatSecondsTests(TestCase):
self.assertEqual(utils.format_seconds(seconds), out, seconds) self.assertEqual(utils.format_seconds(seconds), out, seconds)
class FormatSizeTests(TestCase):
"""Tests for format_size.
Class attributes:
TESTS: A list of (input, output) tuples.
"""
TESTS = [
(-1024, '-1.00k'),
(-1, '-1.00'),
(0, '0.00'),
(1023, '1023.00'),
(1024, '1.00k'),
(1034.24, '1.01k'),
(1024 * 1024 * 2, '2.00M'),
(1024 ** 10, '1024.00Y'),
(None, '?.??'),
]
def test_format_size(self):
"""Test format_size with several tests."""
for size, out in self.TESTS:
self.assertEqual(utils.format_size(size), out, size)
def test_suffix(self):
"""Test the suffix option."""
for size, out in self.TESTS:
self.assertEqual(utils.format_size(size, suffix='B'), out + 'B',
size)
def test_base(self):
"""Test with an alternative base."""
kilo_tests = [(999, '999.00'), (1000, '1.00k'), (1010, '1.01k')]
for size, out in kilo_tests:
self.assertEqual(utils.format_size(size, base=1000), out, size)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -370,3 +370,18 @@ def format_seconds(total_seconds):
chunks.append(min_format.format(minutes)) chunks.append(min_format.format(minutes))
chunks.append('{:02}'.format(seconds)) chunks.append('{:02}'.format(seconds))
return prefix + ':'.join(chunks) return prefix + ':'.join(chunks)
def format_size(size, base=1024, suffix=''):
"""Format a byte size so it's human readable.
Inspired by http://stackoverflow.com/q/1094841
"""
prefixes = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
if size is None:
return '?.??' + suffix
for p in prefixes:
if -base < size < base:
return '{:.02f}{}{}'.format(size, p, suffix)
size /= base
return '{:.02f}{}{}'.format(size, prefixes[-1], suffix)