Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next release v4.50.0 #1041

Merged
merged 16 commits into from
Sep 28, 2020
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,8 @@ Parameters
The screen height. If specified, hides nested bars outside this
bound. If unspecified, attempts to use environment height.
The fallback is 20.
* colour : str, optional
Bar colour (e.g. ``'green'``, ``'#00ff00'``).

Extra CLI Options
~~~~~~~~~~~~~~~~~
Expand Down
4 changes: 2 additions & 2 deletions tqdm/completion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ _tqdm(){
prv="${COMP_WORDS[COMP_CWORD - 1]}"

case ${prv} in
--bar_format|--buf_size|--comppath|--delim|--desc|--initial|--lock_args|--manpath|--maxinterval|--mininterval|--miniters|--ncols|--nrows|--position|--postfix|--smoothing|--total|--unit|--unit_divisor)
--bar_format|--buf_size|--colour|--comppath|--delim|--desc|--initial|--lock_args|--manpath|--maxinterval|--mininterval|--miniters|--ncols|--nrows|--position|--postfix|--smoothing|--total|--unit|--unit_divisor)
# await user input
;;
"--log")
COMPREPLY=($(compgen -W 'CRITICAL FATAL ERROR WARN WARNING INFO DEBUG NOTSET' -- ${cur}))
;;
*)
COMPREPLY=($(compgen -W '--ascii --bar_format --buf_size --bytes --comppath --delim --desc --disable --dynamic_ncols --help --initial --leave --lock_args --log --manpath --maxinterval --mininterval --miniters --ncols --nrows --null --position --postfix --smoothing --tee --total --unit --unit_divisor --unit_scale --update --update_to --version --write_bytes -h -v' -- ${cur}))
COMPREPLY=($(compgen -W '--ascii --bar_format --buf_size --bytes --colour --comppath --delim --desc --disable --dynamic_ncols --help --initial --leave --lock_args --log --manpath --maxinterval --mininterval --miniters --ncols --nrows --null --position --postfix --smoothing --tee --total --unit --unit_divisor --unit_scale --update --update_to --version --write_bytes -h -v' -- ${cur}))
;;
esac
}
Expand Down
37 changes: 23 additions & 14 deletions tqdm/notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,11 @@ def status_printer(_, total=None, desc=None, ncols=None):
if ncols is None:
pbar.layout.width = "20px"

ltext = HTML()
rtext = HTML()
if desc:
pbar.description = desc
if IPYW >= 7:
pbar.style.description_width = 'initial'
# Prepare status text
ptext = HTML()
# Only way to place text to the right of the bar is to use a container
container = HBox(children=[pbar, ptext])
ltext.value = desc
container = HBox(children=[ltext, pbar, rtext])
# Prepare layout
if ncols is not None: # use default style of ipywidgets
# ncols could be 100, "100px", "100%"
Expand Down Expand Up @@ -151,7 +148,7 @@ def display(self, msg=None, pos=None,
if not msg and not close:
msg = self.__repr__()

pbar, ptext = self.container.children
ltext, pbar, rtext = self.container.children
pbar.value = self.n

if msg:
Expand All @@ -168,13 +165,10 @@ def display(self, msg=None, pos=None,
right = right[1:]

# Update description
pbar.description = left
if IPYW >= 7:
pbar.style.description_width = 'initial'

ltext.value = left
# never clear the bar (signal: msg='')
if right:
ptext.value = right
rtext.value = right

# Change bar style
if bar_style:
Expand All @@ -190,6 +184,16 @@ def display(self, msg=None, pos=None,
except AttributeError:
self.container.visible = False

@property
def colour(self):
if hasattr(self, 'container'):
return self.container.children[-2].style.bar_color

@colour.setter
def colour(self, bar_color):
if hasattr(self, 'container'):
self.container.children[-2].style.bar_color = bar_color

def __init__(self, *args, **kwargs):
kwargs = kwargs.copy()
# Setup default output
Expand All @@ -204,6 +208,7 @@ def __init__(self, *args, **kwargs):
'{bar}', '<bar/>')
# convert disable = None to False
kwargs['disable'] = bool(kwargs.get('disable', False))
colour = kwargs.pop('colour', None)
super(tqdm_notebook, self).__init__(*args, **kwargs)
if self.disable or not kwargs['gui']:
self.sp = lambda *_, **__: None
Expand All @@ -218,6 +223,7 @@ def __init__(self, *args, **kwargs):
self.container = self.status_printer(
self.fp, total, self.desc, self.ncols)
self.sp = self.display
self.colour = colour

# Print initial bar state
if not self.disable:
Expand Down Expand Up @@ -273,9 +279,12 @@ def reset(self, total=None):
----------
total : int or float, optional. Total to use for the new bar.
"""
_, pbar, _ = self.container.children
pbar.bar_style = ''
if total is not None:
pbar, _ = self.container.children
pbar.max = total
if not self.total and self.ncols is None: # no longer unknown total
pbar.layout.width = None # reset width
return super(tqdm_notebook, self).reset(total=total)


Expand Down
60 changes: 51 additions & 9 deletions tqdm/std.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .utils import _supports_unicode, _screen_shape_wrapper, _range, _unich, \
_term_move_up, _unicode, WeakSet, _basestring, _OrderedDict, \
Comparable, _is_ascii, FormatReplace, disp_len, disp_trim, \
SimpleTextIOWrapper, CallbackIOWrapper
SimpleTextIOWrapper, DisableOnWriteError, CallbackIOWrapper
from ._monitor import TMonitor
# native libraries
from contextlib import contextmanager
Expand Down Expand Up @@ -140,15 +140,44 @@ class Bar(object):
ASCII = " 123456789#"
UTF = u" " + u''.join(map(_unich, range(0x258F, 0x2587, -1)))
BLANK = " "
COLOUR_RESET = '\x1b[0m'
COLOUR_RGB = '\x1b[38;2;%d;%d;%dm'
COLOURS = dict(BLACK='\x1b[30m', RED='\x1b[31m', GREEN='\x1b[32m',
YELLOW='\x1b[33m', BLUE='\x1b[34m', MAGENTA='\x1b[35m',
CYAN='\x1b[36m', WHITE='\x1b[37m')

def __init__(self, frac, default_len=10, charset=UTF):
def __init__(self, frac, default_len=10, charset=UTF, colour=None):
if not (0 <= frac <= 1):
warn("clamping frac to range [0, 1]", TqdmWarning, stacklevel=2)
frac = max(0, min(1, frac))
assert default_len > 0
self.frac = frac
self.default_len = default_len
self.charset = charset
self.colour = colour

@property
def colour(self):
return self._colour

@colour.setter
def colour(self, value):
if not value:
self._colour = None
return
try:
if value.upper() in self.COLOURS:
self._colour = self.COLOURS[value.upper()]
elif value[0] == '#' and len(value) == 7:
self._colour = self.COLOUR_RGB % tuple(
int(i, 16) for i in (value[1:3], value[3:5], value[5:7]))
else:
raise KeyError
except (KeyError, AttributeError):
warn("Unknown colour (%s); valid choices: [hex (#00ff00), %s]" % (
value, ", ".join(self.COLOURS)),
TqdmWarning, stacklevel=2)
self._colour = None

def __format__(self, format_spec):
if format_spec:
Expand Down Expand Up @@ -178,8 +207,10 @@ def __format__(self, format_spec):

# whitespace padding
if bar_length < N_BARS:
return bar + frac_bar + \
bar = bar + frac_bar + \
charset[0] * (N_BARS - bar_length - 1)
if self.colour:
return self.colour + bar + self.COLOUR_RESET
return bar


Expand Down Expand Up @@ -309,7 +340,7 @@ def print_status(s):
@staticmethod
def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False,
unit='it', unit_scale=False, rate=None, bar_format=None,
postfix=None, unit_divisor=1000, initial=0,
postfix=None, unit_divisor=1000, initial=0, colour=None,
**extra_kwargs):
"""
Return a string-based progress bar given some parameters
Expand Down Expand Up @@ -368,6 +399,8 @@ def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False,
[default: 1000], ignored unless `unit_scale` is True.
initial : int or float, optional
The initial counter value [default: 0].
colour : str, optional
Bar colour (e.g. `'green'`, `'#00ff00'`).

Returns
-------
Expand Down Expand Up @@ -442,6 +475,7 @@ def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False,
rate_noinv_fmt=rate_noinv_fmt, rate_inv=inv_rate,
rate_inv_fmt=rate_inv_fmt,
postfix=postfix, unit_divisor=unit_divisor,
colour=colour,
# plus more useful definitions
remaining=remaining_str, remaining_s=remaining,
l_bar=l_bar, r_bar=r_bar,
Expand Down Expand Up @@ -483,7 +517,8 @@ def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False,
frac,
max(1, ncols - disp_len(nobar))
if ncols else 10,
charset=Bar.ASCII if ascii is True else ascii or Bar.UTF)
charset=Bar.ASCII if ascii is True else ascii or Bar.UTF,
colour=colour)
if not _is_ascii(full_bar.charset) and _is_ascii(bar_format):
bar_format = _unicode(bar_format)
res = bar_format.format(bar=full_bar, **format_dict)
Expand All @@ -501,7 +536,8 @@ def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False,
0,
max(1, ncols - disp_len(nobar))
if ncols else 10,
charset=Bar.BLANK)
charset=Bar.BLANK,
colour=colour)
res = bar_format.format(bar=full_bar, **format_dict)
return disp_trim(res, ncols) if ncols else res
else:
Expand Down Expand Up @@ -802,7 +838,7 @@ def __init__(self, iterable=None, desc=None, total=None, leave=True,
unit_scale=False, dynamic_ncols=False, smoothing=0.3,
bar_format=None, initial=0, position=None, postfix=None,
unit_divisor=1000, write_bytes=None, lock_args=None,
nrows=None,
nrows=None, colour=None,
gui=False, **kwargs):
"""
Parameters
Expand Down Expand Up @@ -908,6 +944,8 @@ def __init__(self, iterable=None, desc=None, total=None, leave=True,
The screen height. If specified, hides nested bars outside this
bound. If unspecified, attempts to use environment height.
The fallback is 20.
colour : str, optional
Bar colour (e.g. `'green'`, `'#00ff00'`).
gui : bool, optional
WARNING: internal parameter - do not use.
Use tqdm.gui.tqdm(...) instead. If set, will attempt to use
Expand All @@ -929,6 +967,8 @@ def __init__(self, iterable=None, desc=None, total=None, leave=True,
file = SimpleTextIOWrapper(
file, encoding=getattr(file, 'encoding', None) or 'utf-8')

file = DisableOnWriteError(file, tqdm_instance=self)

if disable is None and hasattr(file, "isatty") and not file.isatty():
disable = True

Expand Down Expand Up @@ -1027,9 +1067,10 @@ def __init__(self, iterable=None, desc=None, total=None, leave=True,
self.dynamic_ncols = dynamic_ncols
self.smoothing = smoothing
self.avg_time = None
self._time = time
self.bar_format = bar_format
self.postfix = None
self.colour = colour
self._time = time
if postfix:
try:
self.set_postfix(refresh=False, **postfix)
Expand Down Expand Up @@ -1451,7 +1492,8 @@ def format_dict(self):
unit_scale=self.unit_scale,
rate=1 / self.avg_time if self.avg_time else None,
bar_format=self.bar_format, postfix=self.postfix,
unit_divisor=self.unit_divisor, initial=self.initial)
unit_divisor=self.unit_divisor, initial=self.initial,
colour=self.colour)

def display(self, msg=None, pos=None):
"""
Expand Down
32 changes: 16 additions & 16 deletions tqdm/tests/tests_perf.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,13 @@ def test_manual_overhead_hard():
total = int(1e5)

with closing(MockIO()) as our_file:
t = tqdm(total=total * 10, file=our_file, leave=True, miniters=1,
mininterval=0, maxinterval=0)
a = 0
with relative_timer() as time_tqdm:
for i in _range(total):
a += i
t.update(10)
with tqdm(total=total * 10, file=our_file, leave=True, miniters=1,
mininterval=0, maxinterval=0) as t:
a = 0
with relative_timer() as time_tqdm:
for i in _range(total):
a += i
t.update(10)

a = 0
with relative_timer() as time_bench:
Expand Down Expand Up @@ -334,7 +334,7 @@ def test_iter_overhead_simplebar_hard():
a += i

assert_performance(
7.5, 'trange', time_tqdm(), 'simple_progress', time_bench())
8, 'trange', time_tqdm(), 'simple_progress', time_bench())


@with_setup(pretest, posttest)
Expand All @@ -345,13 +345,13 @@ def test_manual_overhead_simplebar_hard():
total = int(1e4)

with closing(MockIO()) as our_file:
t = tqdm(total=total * 10, file=our_file, leave=True, miniters=1,
mininterval=0, maxinterval=0)
a = 0
with relative_timer() as time_tqdm:
for i in _range(total):
a += i
t.update(10)
with tqdm(total=total * 10, file=our_file, leave=True, miniters=1,
mininterval=0, maxinterval=0) as t:
a = 0
with relative_timer() as time_tqdm:
for i in _range(total):
a += i
t.update(10)

simplebar_update = simple_progress(
total=total * 10, file=our_file, leave=True, miniters=1,
Expand All @@ -363,4 +363,4 @@ def test_manual_overhead_simplebar_hard():
simplebar_update(10)

assert_performance(
7.5, 'tqdm', time_tqdm(), 'simple_progress', time_bench())
8, 'tqdm', time_tqdm(), 'simple_progress', time_bench())
36 changes: 34 additions & 2 deletions tqdm/tests/tests_tqdm.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from tqdm import tqdm
from tqdm import trange
from tqdm import TqdmDeprecationWarning
from tqdm import TqdmDeprecationWarning, TqdmWarning
from tqdm.std import Bar
from tqdm.contrib import DummyTqdmFile

Expand Down Expand Up @@ -1895,7 +1895,7 @@ def test_float_progress():
with closing(StringIO()) as our_file:
with trange(10, total=9.6, file=our_file) as t:
with catch_warnings(record=True) as w:
simplefilter("always")
simplefilter("always", category=TqdmWarning)
for i in t:
if i < 9:
assert not w
Expand Down Expand Up @@ -1987,3 +1987,35 @@ def test_initial():
out = our_file.getvalue()
assert '10/19' in out
assert '19/19' in out


@with_setup(pretest, posttest)
def test_colour():
"""Test `colour`"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(9), file=our_file, colour="#beefed"):
pass
out = our_file.getvalue()
assert '\x1b[38;2;%d;%d;%dm' % (0xbe, 0xef, 0xed) in out

with catch_warnings(record=True) as w:
simplefilter("always", category=TqdmWarning)
with tqdm(total=1, file=our_file, colour="charm") as t:
assert w
t.update()
assert "Unknown colour" in str(w[-1].message)

with closing(StringIO()) as our_file2:
for _ in tqdm(_range(9), file=our_file2, colour="blue"):
pass
out = our_file2.getvalue()
assert '\x1b[34m' in out


@with_setup(pretest, posttest)
def test_closed():
"""Test writing to closed file"""
with closing(StringIO()) as our_file:
for i in trange(9, file=our_file, miniters=1, mininterval=0):
if i == 5:
our_file.close()