tests: Add full test coverage for progress text output
Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
parent
078178f476
commit
58837a7641
|
@ -3,7 +3,7 @@ source=virtinst/
|
||||||
|
|
||||||
[report]
|
[report]
|
||||||
skip_covered = yes
|
skip_covered = yes
|
||||||
omit=virtinst/_progresspriv.py
|
#omit=virtinst/_progresspriv.py
|
||||||
|
|
||||||
exclude_lines =
|
exclude_lines =
|
||||||
# Have to re-enable the standard pragma
|
# Have to re-enable the standard pragma
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
Meter text test 0% [ ] 0 B/s | 0 B --:-- ETA
|
||||||
|
|
||||||
|
Meter text test 1% [ ] 0 B/s | 100 B --:-- ETA
|
||||||
|
|
||||||
|
Meter text test 2% [ ] 67 B/s | 200 B 02:27 ETA
|
||||||
|
|
||||||
|
Meter text test 20% [=== ] 413 B/s | 2.0 kB 00:19 ETA
|
||||||
|
|
||||||
|
Meter text test 40% [======- ] 731 B/s | 3.9 kB 00:08 ETA
|
||||||
|
|
||||||
|
Meter text test | 3.9 kB 00:04 ...
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
Meter text test 0% [ ] 0 B/s | 0 B --:--:-- ETA
|
||||||
|
|
||||||
|
Meter text test 1% [ ] 0 B/s | 100 B --:--:-- ETA
|
||||||
|
|
||||||
|
Meter text test 2% [- ] 67 B/s | 200 B 00:02:27 ETA
|
||||||
|
|
||||||
|
Meter text test 20% [======= ] 413 B/s | 2.0 kB 00:00:19 ETA
|
||||||
|
|
||||||
|
Meter text test 40% [============== ] 731 B/s | 3.9 kB 00:00:08 ETA
|
||||||
|
|
||||||
|
Meter text test | 3.9 kB 00:00:04 ...
|
|
@ -0,0 +1,7 @@
|
||||||
|
Meter text test 0 B/s | 0 B 00:00
|
||||||
|
Meter text test 0 B/s | 100 B 00:00
|
||||||
|
Meter text test 67 B/s | 200 B 00:02
|
||||||
|
Meter text test 413 B/s | 2.0 kB 00:03
|
||||||
|
Meter text test 731 B/s | 3.9 kB 00:04
|
||||||
|
|
||||||
|
Meter text test | 3.9 kB 00:04
|
|
@ -0,0 +1,7 @@
|
||||||
|
12345678 | 0 B
|
||||||
|
12345678 | 100 B
|
||||||
|
12345678 | 200 B
|
||||||
|
12345678 | 2.0 kB
|
||||||
|
12345678 | 3.9 kB
|
||||||
|
|
||||||
|
1234567890
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
Meter text test 0% [ ] 0 B/s | 0 B --:-- ETA
|
||||||
|
|
||||||
|
Meter text test 50% [========- ] 0 B/s | 100 B --:-- ETA
|
||||||
|
|
||||||
|
Meter text test 100% [================] 67 B/s | 200 B 00:00 ETA
|
||||||
|
|
||||||
|
Meter text test 1000% [================] 413 B/s | 2.0 kB --:-- ETA
|
||||||
|
|
||||||
|
Meter text test 2000% [================] 731 B/s | 3.9 kB --:-- ETA
|
||||||
|
|
||||||
|
Meter text test | 3.9 kB 00:04 !!!
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
Meter text test 100% [================] 0 B/s | 0 B --:-- ETA
|
||||||
|
|
||||||
|
Meter text test 100% [================] 0 B/s | 100 B --:-- ETA
|
||||||
|
|
||||||
|
Meter text test 100% [================] 67 B/s | 200 B --:-- ETA
|
||||||
|
|
||||||
|
Meter text test 100% [================] 413 B/s | 2.0 kB --:-- ETA
|
||||||
|
|
||||||
|
Meter text test 100% [================] 731 B/s | 3.9 kB --:-- ETA
|
||||||
|
|
||||||
|
Meter text test | 3.9 kB 00:04
|
|
@ -3,6 +3,10 @@
|
||||||
# This work is licensed under the GNU GPLv2 or later.
|
# This work is licensed under the GNU GPLv2 or later.
|
||||||
# See the COPYING file in the top-level directory.
|
# See the COPYING file in the top-level directory.
|
||||||
|
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
import virtinst
|
import virtinst
|
||||||
|
|
||||||
from tests import utils
|
from tests import utils
|
||||||
|
@ -124,3 +128,74 @@ def test_misc_cpu_cornercases():
|
||||||
guest.cpu.model = "idontexist"
|
guest.cpu.model = "idontexist"
|
||||||
guest.cpu._validate_default_host_model_only(guest)
|
guest.cpu._validate_default_host_model_only(guest)
|
||||||
assert guest.cpu.model is None
|
assert guest.cpu.model is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_misc_meter():
|
||||||
|
"""
|
||||||
|
Test coverage of our urlgrabber meter copy
|
||||||
|
"""
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
from virtinst import _progresspriv
|
||||||
|
|
||||||
|
def _test_meter_values(m, startval=10000, text="Meter text test"):
|
||||||
|
with unittest.mock.patch("time.time", return_value=1.0):
|
||||||
|
m.start(text, startval)
|
||||||
|
with unittest.mock.patch("time.time", return_value=1.1):
|
||||||
|
m.update(0)
|
||||||
|
with unittest.mock.patch("time.time", return_value=1.5):
|
||||||
|
m.update(0)
|
||||||
|
with unittest.mock.patch("time.time", return_value=2.0):
|
||||||
|
m.update(100)
|
||||||
|
with unittest.mock.patch("time.time", return_value=3.0):
|
||||||
|
m.update(200)
|
||||||
|
with unittest.mock.patch("time.time", return_value=4.0):
|
||||||
|
m.update(2000)
|
||||||
|
with unittest.mock.patch("time.time", return_value=5.0):
|
||||||
|
m.update(4000)
|
||||||
|
with unittest.mock.patch("time.time", return_value=6.0):
|
||||||
|
m.end()
|
||||||
|
|
||||||
|
# Basic output testing
|
||||||
|
meter = _progresspriv.TextMeter(output=io.StringIO())
|
||||||
|
_test_meter_values(meter)
|
||||||
|
out = meter.output.getvalue().replace("\r", "\n")
|
||||||
|
utils.diff_compare(out, os.path.join(utils.DATADIR, "meter", "meter1.txt"))
|
||||||
|
|
||||||
|
# Fake having a longer terminal, it affects output a bit
|
||||||
|
meter = _progresspriv.TextMeter(output=io.StringIO())
|
||||||
|
_progresspriv._term_width_val = 120
|
||||||
|
_test_meter_values(meter)
|
||||||
|
_progresspriv._term_width_val = 80
|
||||||
|
out = meter.output.getvalue().replace("\r", "\n")
|
||||||
|
utils.diff_compare(out, os.path.join(utils.DATADIR, "meter", "meter2.txt"))
|
||||||
|
|
||||||
|
# meter with size=None
|
||||||
|
meter = _progresspriv.TextMeter(output=io.StringIO())
|
||||||
|
_test_meter_values(meter, None)
|
||||||
|
out = meter.output.getvalue().replace("\r", "\n")
|
||||||
|
utils.diff_compare(out, os.path.join(utils.DATADIR, "meter", "meter3.txt"))
|
||||||
|
|
||||||
|
# meter with size=None and small terminal size
|
||||||
|
meter = _progresspriv.TextMeter(output=io.StringIO())
|
||||||
|
_progresspriv._term_width_val = 11
|
||||||
|
_test_meter_values(meter, None, "1234567890")
|
||||||
|
assert meter.re.fraction_read() is None
|
||||||
|
_progresspriv._term_width_val = 80
|
||||||
|
out = meter.output.getvalue().replace("\r", "\n")
|
||||||
|
utils.diff_compare(out, os.path.join(utils.DATADIR, "meter", "meter4.txt"))
|
||||||
|
|
||||||
|
# meter with size exceeded by the update() values
|
||||||
|
meter = _progresspriv.TextMeter(output=io.StringIO())
|
||||||
|
_test_meter_values(meter, 200)
|
||||||
|
out = meter.output.getvalue().replace("\r", "\n")
|
||||||
|
utils.diff_compare(out, os.path.join(utils.DATADIR, "meter", "meter5.txt"))
|
||||||
|
|
||||||
|
# meter with size 0
|
||||||
|
meter = _progresspriv.TextMeter(output=io.StringIO())
|
||||||
|
_test_meter_values(meter, 0)
|
||||||
|
out = meter.output.getvalue().replace("\r", "\n")
|
||||||
|
utils.diff_compare(out, os.path.join(utils.DATADIR, "meter", "meter6.txt"))
|
||||||
|
|
||||||
|
# BaseMeter coverage
|
||||||
|
meter = _progresspriv.BaseMeter()
|
||||||
|
_test_meter_values(meter)
|
||||||
|
|
|
@ -10,12 +10,11 @@
|
||||||
# we are just copying this for now.
|
# we are just copying this for now.
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import math
|
|
||||||
import fcntl
|
import fcntl
|
||||||
import struct
|
import struct
|
||||||
|
import sys
|
||||||
import termios
|
import termios
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
# Code from https://mail.python.org/pipermail/python-list/2000-May/033365.html
|
# Code from https://mail.python.org/pipermail/python-list/2000-May/033365.html
|
||||||
|
@ -24,11 +23,8 @@ def terminal_width(fd=1):
|
||||||
try:
|
try:
|
||||||
buf = 'abcdefgh'
|
buf = 'abcdefgh'
|
||||||
buf = fcntl.ioctl(fd, termios.TIOCGWINSZ, buf)
|
buf = fcntl.ioctl(fd, termios.TIOCGWINSZ, buf)
|
||||||
ret = struct.unpack('hhhh', buf)[1]
|
ret = struct.unpack('hhhh', buf)[1] # pragma: no cover
|
||||||
if ret == 0:
|
return ret or 80 # pragma: no cover
|
||||||
return 80
|
|
||||||
# Add minimum too?
|
|
||||||
return ret
|
|
||||||
except IOError:
|
except IOError:
|
||||||
return 80
|
return 80
|
||||||
|
|
||||||
|
@ -66,9 +62,7 @@ class TerminalLine:
|
||||||
def rest_split(self, fixed, elements=2):
|
def rest_split(self, fixed, elements=2):
|
||||||
""" After a fixed length, split the rest of the line length among
|
""" After a fixed length, split the rest of the line length among
|
||||||
a number of different elements (default=2). """
|
a number of different elements (default=2). """
|
||||||
if self.llen < fixed:
|
return max(self.llen - fixed, 0) // elements
|
||||||
return 0
|
|
||||||
return (self.llen - fixed) // elements
|
|
||||||
|
|
||||||
def add(self, element, full_len=None):
|
def add(self, element, full_len=None):
|
||||||
""" If there is room left in the line, above min_len, add element.
|
""" If there is room left in the line, above min_len, add element.
|
||||||
|
@ -93,71 +87,48 @@ class BaseMeter:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.update_period = 0.3 # seconds
|
self.update_period = 0.3 # seconds
|
||||||
|
|
||||||
self.url = None
|
|
||||||
self.basename = None
|
|
||||||
self.text = None
|
self.text = None
|
||||||
self.size = None
|
self.size = None
|
||||||
self.start_time = None
|
self.start_time = None
|
||||||
self.fsize = None
|
|
||||||
self.last_amount_read = 0
|
self.last_amount_read = 0
|
||||||
self.last_update_time = None
|
self.last_update_time = None
|
||||||
self.re = RateEstimator()
|
self.re = RateEstimator()
|
||||||
|
|
||||||
def set_text(self, text):
|
|
||||||
self.text = text
|
|
||||||
|
|
||||||
def start(self, text, size):
|
def start(self, text, size):
|
||||||
self.text = text
|
self.text = text
|
||||||
|
|
||||||
self.size = size
|
self.size = size
|
||||||
if size is not None:
|
assert type(size) in [int, type(None)]
|
||||||
self.fsize = format_number(size) + 'B'
|
assert self.text is not None
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
self.start_time = now
|
self.start_time = now
|
||||||
self.re.start(size, now)
|
self.re.start(size, now)
|
||||||
self.last_amount_read = 0
|
self.last_amount_read = 0
|
||||||
self.last_update_time = now
|
self.last_update_time = now
|
||||||
self._do_start(now)
|
|
||||||
|
|
||||||
def _do_start(self, now=None):
|
def update(self, amount_read):
|
||||||
pass
|
|
||||||
|
|
||||||
def update(self, amount_read, now=None):
|
|
||||||
# for a real gui, you probably want to override and put a call
|
# for a real gui, you probably want to override and put a call
|
||||||
# to your mainloop iteration function here
|
# to your mainloop iteration function here
|
||||||
if now is None:
|
assert type(amount_read) is int
|
||||||
now = time.time()
|
|
||||||
|
now = time.time()
|
||||||
if (not self.last_update_time or
|
if (not self.last_update_time or
|
||||||
(now >= self.last_update_time + self.update_period)):
|
(now >= self.last_update_time + self.update_period)):
|
||||||
self.re.update(amount_read, now)
|
self.re.update(amount_read, now)
|
||||||
self.last_amount_read = amount_read
|
self.last_amount_read = amount_read
|
||||||
self.last_update_time = now
|
self.last_update_time = now
|
||||||
self._do_update(amount_read, now)
|
self._do_update(amount_read)
|
||||||
|
|
||||||
def _do_update(self, amount_read, now=None):
|
def _do_update(self, amount_read):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def end(self):
|
def end(self):
|
||||||
self._do_end(self.last_amount_read, self.last_update_time)
|
self._do_end()
|
||||||
|
|
||||||
def _do_end(self, amount_read, now=None):
|
def _do_end(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# This is kind of a hack, but progress is gotten from grabber which doesn't
|
|
||||||
# know about the total size to download. So we do this so we can get the data
|
|
||||||
# out of band here. This will be "fixed" one way or anther soon.
|
|
||||||
_text_meter_total_size = 0
|
|
||||||
_text_meter_sofar_size = 0
|
|
||||||
|
|
||||||
|
|
||||||
def text_meter_total_size(size, downloaded=0):
|
|
||||||
global _text_meter_total_size
|
|
||||||
global _text_meter_sofar_size
|
|
||||||
_text_meter_total_size = size
|
|
||||||
_text_meter_sofar_size = downloaded
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# update: No size (minimal: 17 chars)
|
# update: No size (minimal: 17 chars)
|
||||||
# -----------------------------------
|
# -----------------------------------
|
||||||
|
@ -230,20 +201,11 @@ class TextMeter(BaseMeter):
|
||||||
BaseMeter.__init__(self)
|
BaseMeter.__init__(self)
|
||||||
self.output = output
|
self.output = output
|
||||||
|
|
||||||
def _do_update(self, amount_read, now=None):
|
def _do_update(self, amount_read):
|
||||||
etime = self.re.elapsed_time()
|
etime = self.re.elapsed_time()
|
||||||
fread = format_number(amount_read)
|
fread = format_number(amount_read)
|
||||||
# self.size = None
|
|
||||||
if self.text is not None:
|
|
||||||
text = self.text
|
|
||||||
else:
|
|
||||||
text = self.basename
|
|
||||||
|
|
||||||
ave_dl = format_number(self.re.average_rate())
|
ave_dl = format_number(self.re.average_rate())
|
||||||
sofar_size = None
|
|
||||||
if _text_meter_total_size:
|
|
||||||
sofar_size = _text_meter_sofar_size + amount_read
|
|
||||||
sofar_pc = (sofar_size * 100) // _text_meter_total_size
|
|
||||||
|
|
||||||
# Include text + ui_rate in minimal
|
# Include text + ui_rate in minimal
|
||||||
tl = TerminalLine(8, 8 + 1 + 8)
|
tl = TerminalLine(8, 8 + 1 + 8)
|
||||||
|
@ -254,7 +216,7 @@ class TextMeter(BaseMeter):
|
||||||
ui_time = tl.add(' %s' % format_time(etime, use_hours))
|
ui_time = tl.add(' %s' % format_time(etime, use_hours))
|
||||||
ui_end = tl.add(' ' * 5)
|
ui_end = tl.add(' ' * 5)
|
||||||
ui_rate = tl.add(' %5sB/s' % ave_dl)
|
ui_rate = tl.add(' %5sB/s' % ave_dl)
|
||||||
out = '%-*.*s%s%s%s%s\r' % (tl.rest(), tl.rest(), text,
|
out = '%-*.*s%s%s%s%s\r' % (tl.rest(), tl.rest(), self.text,
|
||||||
ui_rate, ui_size, ui_time, ui_end)
|
ui_rate, ui_size, ui_time, ui_end)
|
||||||
else:
|
else:
|
||||||
rtime = self.re.remaining_time()
|
rtime = self.re.remaining_time()
|
||||||
|
@ -264,35 +226,23 @@ class TextMeter(BaseMeter):
|
||||||
ui_time = tl.add(' %s' % frtime)
|
ui_time = tl.add(' %s' % frtime)
|
||||||
ui_end = tl.add(' ETA ')
|
ui_end = tl.add(' ETA ')
|
||||||
|
|
||||||
if sofar_size is None:
|
|
||||||
ui_sofar_pc = ''
|
|
||||||
else:
|
|
||||||
ui_sofar_pc = tl.add(' (%i%%)' % sofar_pc,
|
|
||||||
full_len=len(" (100%)"))
|
|
||||||
|
|
||||||
ui_pc = tl.add(' %2i%%' % (frac * 100))
|
ui_pc = tl.add(' %2i%%' % (frac * 100))
|
||||||
ui_rate = tl.add(' %5sB/s' % ave_dl)
|
ui_rate = tl.add(' %5sB/s' % ave_dl)
|
||||||
# Make text grow a bit before we start growing the bar too
|
# Make text grow a bit before we start growing the bar too
|
||||||
blen = 4 + tl.rest_split(8 + 8 + 4)
|
blen = 4 + tl.rest_split(8 + 8 + 4)
|
||||||
ui_bar = _term_add_bar(tl, blen, frac)
|
ui_bar = _term_add_bar(tl, blen, frac)
|
||||||
out = '\r%-*.*s%s%s%s%s%s%s%s\r' % (
|
out = '\r%-*.*s%s%s%s%s%s%s\r' % (
|
||||||
tl.rest(), tl.rest(), text,
|
tl.rest(), tl.rest(), self.text,
|
||||||
ui_sofar_pc, ui_pc, ui_bar,
|
ui_pc, ui_bar,
|
||||||
ui_rate, ui_size, ui_time, ui_end
|
ui_rate, ui_size, ui_time, ui_end
|
||||||
)
|
)
|
||||||
|
|
||||||
self.output.write(out)
|
self.output.write(out)
|
||||||
self.output.flush()
|
self.output.flush()
|
||||||
|
|
||||||
def _do_end(self, amount_read, now=None):
|
def _do_end(self):
|
||||||
global _text_meter_total_size
|
amount_read = self.last_amount_read
|
||||||
global _text_meter_sofar_size
|
|
||||||
|
|
||||||
total_size = format_number(amount_read)
|
total_size = format_number(amount_read)
|
||||||
if self.text is not None:
|
|
||||||
text = self.text
|
|
||||||
else:
|
|
||||||
text = self.basename
|
|
||||||
|
|
||||||
tl = TerminalLine(8)
|
tl = TerminalLine(8)
|
||||||
# For big screens, make it more readable.
|
# For big screens, make it more readable.
|
||||||
|
@ -301,29 +251,16 @@ class TextMeter(BaseMeter):
|
||||||
ui_time = tl.add(' %s' % format_time(self.re.elapsed_time(),
|
ui_time = tl.add(' %s' % format_time(self.re.elapsed_time(),
|
||||||
use_hours))
|
use_hours))
|
||||||
ui_end, not_done = _term_add_end(tl, self.size, amount_read)
|
ui_end, not_done = _term_add_end(tl, self.size, amount_read)
|
||||||
out = '\r%-*.*s%s%s%s\n' % (tl.rest(), tl.rest(), text,
|
dummy = not_done
|
||||||
|
out = '\r%-*.*s%s%s%s\n' % (tl.rest(), tl.rest(), self.text,
|
||||||
ui_size, ui_time, ui_end)
|
ui_size, ui_time, ui_end)
|
||||||
self.output.write(out)
|
self.output.write(out)
|
||||||
self.output.flush()
|
self.output.flush()
|
||||||
|
|
||||||
# Don't add size to the sofar size until we have all of it.
|
|
||||||
# If we don't have a size, then just pretend/hope we got all of it.
|
|
||||||
if not_done:
|
|
||||||
return
|
|
||||||
|
|
||||||
if _text_meter_total_size:
|
|
||||||
_text_meter_sofar_size += amount_read
|
|
||||||
if _text_meter_total_size <= _text_meter_sofar_size:
|
|
||||||
_text_meter_total_size = 0
|
|
||||||
_text_meter_sofar_size = 0
|
|
||||||
|
|
||||||
|
|
||||||
text_progress_meter = TextMeter
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# support classes and functions
|
# support classes and functions
|
||||||
|
|
||||||
|
|
||||||
class RateEstimator:
|
class RateEstimator:
|
||||||
def __init__(self, timescale=5.0):
|
def __init__(self, timescale=5.0):
|
||||||
self.timescale = timescale
|
self.timescale = timescale
|
||||||
|
@ -333,22 +270,14 @@ class RateEstimator:
|
||||||
self.last_amount_read = 0
|
self.last_amount_read = 0
|
||||||
self.ave_rate = None
|
self.ave_rate = None
|
||||||
|
|
||||||
def start(self, total=None, now=None):
|
def start(self, total, now):
|
||||||
if now is None:
|
|
||||||
now = time.time()
|
|
||||||
self.total = total
|
self.total = total
|
||||||
self.start_time = now
|
self.start_time = now
|
||||||
self.last_update_time = now
|
self.last_update_time = now
|
||||||
self.last_amount_read = 0
|
self.last_amount_read = 0
|
||||||
self.ave_rate = None
|
self.ave_rate = None
|
||||||
|
|
||||||
def update(self, amount_read, now=None):
|
def update(self, amount_read, now):
|
||||||
if now is None:
|
|
||||||
now = time.time()
|
|
||||||
# libcurl calls the progress callback when fetching headers
|
|
||||||
# too, thus amount_read = 0 .. hdr_size .. 0 .. content_size.
|
|
||||||
# Occasionally we miss the 2nd zero and report avg speed < 0.
|
|
||||||
# Handle read_diff < 0 here. BZ 1001767.
|
|
||||||
if amount_read == 0 or amount_read < self.last_amount_read:
|
if amount_read == 0 or amount_read < self.last_amount_read:
|
||||||
# if we just started this file, all bets are off
|
# if we just started this file, all bets are off
|
||||||
self.last_update_time = now
|
self.last_update_time = now
|
||||||
|
@ -386,10 +315,9 @@ class RateEstimator:
|
||||||
(can be None for unknown transfer size)"""
|
(can be None for unknown transfer size)"""
|
||||||
if self.total is None:
|
if self.total is None:
|
||||||
return None
|
return None
|
||||||
elif self.total == 0:
|
if self.total == 0:
|
||||||
return 1.0
|
return 1.0 # pragma: no cover
|
||||||
else:
|
return float(self.last_amount_read) / self.total
|
||||||
return float(self.last_amount_read) / self.total
|
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
# support methods
|
# support methods
|
||||||
|
@ -413,37 +341,16 @@ class RateEstimator:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
recent_rate = read_diff / time_diff
|
recent_rate = read_diff / time_diff
|
||||||
except ZeroDivisionError:
|
except ZeroDivisionError: # pragma: no cover
|
||||||
recent_rate = None
|
recent_rate = None
|
||||||
if last_ave is None:
|
if last_ave is None:
|
||||||
return recent_rate
|
return recent_rate
|
||||||
elif recent_rate is None:
|
if recent_rate is None:
|
||||||
return last_ave
|
return last_ave # pragma: no cover
|
||||||
|
|
||||||
# at this point, both last_ave and recent_rate are numbers
|
# at this point, both last_ave and recent_rate are numbers
|
||||||
return epsilon * recent_rate + (1 - epsilon) * last_ave
|
return epsilon * recent_rate + (1 - epsilon) * last_ave
|
||||||
|
|
||||||
def _round_remaining_time(self, rt, start_time=15.0):
|
|
||||||
"""round the remaining time, depending on its size
|
|
||||||
If rt is between n*start_time and (n+1)*start_time round downward
|
|
||||||
to the nearest multiple of n (for any counting number n).
|
|
||||||
If rt < start_time, round down to the nearest 1.
|
|
||||||
For example (for start_time = 15.0):
|
|
||||||
2.7 -> 2.0
|
|
||||||
25.2 -> 25.0
|
|
||||||
26.4 -> 26.0
|
|
||||||
35.3 -> 34.0
|
|
||||||
63.6 -> 60.0
|
|
||||||
"""
|
|
||||||
|
|
||||||
if rt < 0:
|
|
||||||
return 0.0
|
|
||||||
shift = int(math.log(rt / start_time) / math.log(2))
|
|
||||||
rt = int(rt)
|
|
||||||
if shift <= 0:
|
|
||||||
return rt
|
|
||||||
return float(int(rt) >> shift << shift)
|
|
||||||
|
|
||||||
|
|
||||||
def format_time(seconds, use_hours=0):
|
def format_time(seconds, use_hours=0):
|
||||||
if seconds is None or seconds < 0:
|
if seconds is None or seconds < 0:
|
||||||
|
@ -452,7 +359,7 @@ def format_time(seconds, use_hours=0):
|
||||||
else:
|
else:
|
||||||
return '--:--'
|
return '--:--'
|
||||||
elif seconds == float('inf'):
|
elif seconds == float('inf'):
|
||||||
return 'Infinite'
|
return 'Infinite' # pragma: no cover
|
||||||
else:
|
else:
|
||||||
seconds = int(seconds)
|
seconds = int(seconds)
|
||||||
minutes = seconds // 60
|
minutes = seconds // 60
|
||||||
|
@ -465,7 +372,7 @@ def format_time(seconds, use_hours=0):
|
||||||
return '%02i:%02i' % (minutes, seconds)
|
return '%02i:%02i' % (minutes, seconds)
|
||||||
|
|
||||||
|
|
||||||
def format_number(number, SI=0, space=' '):
|
def format_number(number):
|
||||||
"""Turn numbers into human-readable metric-like numbers"""
|
"""Turn numbers into human-readable metric-like numbers"""
|
||||||
symbols = ['', # (none)
|
symbols = ['', # (none)
|
||||||
'k', # kilo
|
'k', # kilo
|
||||||
|
@ -477,11 +384,7 @@ def format_number(number, SI=0, space=' '):
|
||||||
'Z', # zetta
|
'Z', # zetta
|
||||||
'Y'] # yotta
|
'Y'] # yotta
|
||||||
|
|
||||||
if SI:
|
step = 1024.0
|
||||||
step = 1000.0
|
|
||||||
else:
|
|
||||||
step = 1024.0
|
|
||||||
|
|
||||||
thresh = 999
|
thresh = 999
|
||||||
depth = 0
|
depth = 0
|
||||||
max_depth = len(symbols) - 1
|
max_depth = len(symbols) - 1
|
||||||
|
@ -505,4 +408,4 @@ def format_number(number, SI=0, space=' '):
|
||||||
else:
|
else:
|
||||||
fmt = '%.0f%s%s'
|
fmt = '%.0f%s%s'
|
||||||
|
|
||||||
return(fmt % (float(number or 0), space, symbols[depth]))
|
return fmt % (float(number or 0), " ", symbols[depth])
|
||||||
|
|
Loading…
Reference in New Issue