ProgressBar initial replacement outline
This commit is contained in:
parent
271db52da3
commit
b691bb9b25
1 changed files with 169 additions and 0 deletions
169
core/text.py
169
core/text.py
|
@ -41,6 +41,144 @@ def lexical_join(words, oxford=False):
|
||||||
|
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
|
|
||||||
|
class _ProgressBarChannel:
|
||||||
|
def __init__(self, unit, top, prefix_base2, precision):
|
||||||
|
self.unit = unit
|
||||||
|
self.top = top
|
||||||
|
self.prefix_base2 = prefix_base2
|
||||||
|
self.precision = precision
|
||||||
|
|
||||||
|
self.value = 0
|
||||||
|
self.set()
|
||||||
|
|
||||||
|
if prefix_base2:
|
||||||
|
_print("Unit does not yet support base2 prefixes (e.g. Gi, Mi), using decadic (G, M) instead", prefix.warn)
|
||||||
|
|
||||||
|
def set(self, value=None):
|
||||||
|
if value is not None:
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
self.ratio = self.value / self.top
|
||||||
|
s = Unit(self.value, self.unit, format="%.{:d}f pU".format(self.precision))
|
||||||
|
self.text = str(s).split(" ", 1)
|
||||||
|
|
||||||
|
class ProgressBar2:
|
||||||
|
"""
|
||||||
|
A configurable text progressbar.
|
||||||
|
|
||||||
|
Each atom consists of three characters: a literal §, an operator and a channel.
|
||||||
|
An operator is one of:
|
||||||
|
% - a percentage (value from 0 to 100, padded to three characters)
|
||||||
|
r - displays the raw value of the channel
|
||||||
|
z - displays the maximum (total) value
|
||||||
|
s - displays the rate of change in units/s
|
||||||
|
m - displays the rate of change in units/min
|
||||||
|
h - displays the rate of change in units/h
|
||||||
|
t - displays the elapsed time in s (use with uppercase channel to get an ETA)
|
||||||
|
T - displays the elapsed time in hh:mm:ss (use with uppercase channel to get an ETA)
|
||||||
|
any other character - a bar consisting of these characters filling the line so that
|
||||||
|
at 100% it fills the entirety of the remaining space
|
||||||
|
|
||||||
|
A channel ID as a lowercase letter is the channel's actual value. An uppercase letter
|
||||||
|
is that channel's complement.
|
||||||
|
|
||||||
|
Use §§ to display a literal §.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
Format: §%a [§=a>§ A] §tA
|
||||||
|
Output: 42 % [============> ] 27 s
|
||||||
|
|
||||||
|
Format: §%a (§ra/§ma) [§-a>§ A] §sa [§rb/§rB] (ETA §tA)
|
||||||
|
Output: 53 % (21.0/39.6 kf) [---------------------> ] 27.1 f/s [233/439 Mio] (ETA 00:11:26)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, format, channels, width=None, space_before_unit=True):
|
||||||
|
"""
|
||||||
|
Initialize the ProgressBar.
|
||||||
|
|
||||||
|
width is the desired size of the progressbar drawing area in characters (columns)
|
||||||
|
and defaults to terminal width.
|
||||||
|
|
||||||
|
space_before_unit enables a space character between a value and its unit.
|
||||||
|
|
||||||
|
channels is a dict that for each channel lists its properties:
|
||||||
|
|
||||||
|
{
|
||||||
|
"a": {
|
||||||
|
"unit": "f",
|
||||||
|
"prefix_base2": False,
|
||||||
|
"top": 39600,
|
||||||
|
"precision": 1
|
||||||
|
},
|
||||||
|
"b": {
|
||||||
|
"unit": "o",
|
||||||
|
"prefix_base2": True,
|
||||||
|
"top": measure_file_size_closure("/path/to/file"),
|
||||||
|
"precision": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Channel IDs (the "a", "b") are arbitrary lowercase letters ([a-z]).
|
||||||
|
|
||||||
|
Properties "unit" and "prefix_base2" are passed to over.core.text.Unit.
|
||||||
|
"top" is the value of the channel that corresponds to 100%. Channels are
|
||||||
|
allowed to exceed this value. It can either be a number or a callable. If
|
||||||
|
it's a callable, it will be called without arguments and shall return a number.
|
||||||
|
"precision" is the displayed floating point precision. Use 0 to force an integer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.format = format
|
||||||
|
self.channels = {id: _ProgressBarChannel(**conf) for id, conf in channels.items()}
|
||||||
|
self.space_before_unit = space_before_unit
|
||||||
|
self.time_start = time.time()
|
||||||
|
self.width = width
|
||||||
|
|
||||||
|
def set(self, channel_id, value):
|
||||||
|
"""
|
||||||
|
Sets the channel's value.
|
||||||
|
"""
|
||||||
|
|
||||||
|
c = self.channels[channel_id]
|
||||||
|
c.set(value)
|
||||||
|
|
||||||
|
def render(self, clear=True, stream=sys.stderr):
|
||||||
|
"""
|
||||||
|
Renders the progressbar into a stream. If clear is True, clears the previous content first.
|
||||||
|
"""
|
||||||
|
|
||||||
|
width = self.width or get_terminal_size()[1]
|
||||||
|
raw = self.format
|
||||||
|
|
||||||
|
for tag in re.findall("§.[a-zA-Z]", raw):
|
||||||
|
op = tag[1]
|
||||||
|
ch = tag[2]
|
||||||
|
inverse = ch.isupper()
|
||||||
|
|
||||||
|
# display literal §s
|
||||||
|
raw = raw.replace("§§", "§")
|
||||||
|
|
||||||
|
# pave over previous render and draw the new one
|
||||||
|
if clear:
|
||||||
|
stream.write("\r" + "_" * width)
|
||||||
|
|
||||||
|
stream.write("\r" + raw)
|
||||||
|
|
||||||
|
def end(self, finish=False):
|
||||||
|
"""
|
||||||
|
Print a newline (heh :-)
|
||||||
|
|
||||||
|
If finish is True, set all channels to 100% and draw the progressbar first.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if finish:
|
||||||
|
for c in self.channels.values():
|
||||||
|
c.set(c.top)
|
||||||
|
|
||||||
|
self.render()
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
class ProgressBar:
|
class ProgressBar:
|
||||||
'''
|
'''
|
||||||
An animated progress bar.
|
An animated progress bar.
|
||||||
|
@ -512,3 +650,34 @@ def get_terminal_size():
|
||||||
return struct.unpack('HHHH', fcntl.ioctl(terminal, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))
|
return struct.unpack('HHHH', fcntl.ioctl(terminal, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))
|
||||||
except IOError:
|
except IOError:
|
||||||
return (40, 80)
|
return (40, 80)
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
|
||||||
|
_print = Output('over.core.text', stream=sys.stderr)
|
||||||
|
|
||||||
|
# --------------------------------------------------
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
pb = ProgressBar2(
|
||||||
|
"§%a (§ra/§ma) [§-a>§ A] §sa [§rb/§rB] (ETA §tA)",
|
||||||
|
{
|
||||||
|
"a": {
|
||||||
|
"unit": "f",
|
||||||
|
"prefix_base2": False,
|
||||||
|
"top": 39600,
|
||||||
|
"precision": 1
|
||||||
|
},
|
||||||
|
"b": {
|
||||||
|
"unit": "o",
|
||||||
|
"prefix_base2": True,
|
||||||
|
"top": 3200,
|
||||||
|
"precision": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
80
|
||||||
|
)
|
||||||
|
|
||||||
|
pb.set("a", 12000)
|
||||||
|
pb.set("b", 1500)
|
||||||
|
pb.render()
|
||||||
|
pb.end(not True)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue