Skip to content

Commit

Permalink
Merge branch 'colour' into devel
Browse files Browse the repository at this point in the history
  • Loading branch information
casperdcl committed Sep 27, 2020
2 parents e835860 + 06fb6ec commit ea2367e
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 13 deletions.
2 changes: 2 additions & 0 deletions README.rst
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
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
12 changes: 12 additions & 0 deletions tqdm/notebook.py
Expand Up @@ -184,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 @@ -198,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 @@ -212,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
56 changes: 48 additions & 8 deletions tqdm/std.py
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 Down Expand Up @@ -1029,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 @@ -1453,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
27 changes: 25 additions & 2 deletions tqdm/tests/tests_tqdm.py
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,26 @@ 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
9 changes: 8 additions & 1 deletion tqdm/tqdm.1
@@ -1,4 +1,4 @@
.\" Automatically generated by Pandoc 1.19.2.1
.\" Automatically generated by Pandoc 1.19.2
.\"
.TH "TQDM" "1" "2015\-2020" "tqdm User Manuals" ""
.hy
Expand Down Expand Up @@ -227,6 +227,13 @@ The fallback is 20.
.RS
.RE
.TP
.B \-\-colour=\f[I]colour\f[]
str, optional.
Bar colour (e.g.
\f[C]\[aq]green\[aq]\f[], \f[C]\[aq]#00ff00\[aq]\f[]).
.RS
.RE
.TP
.B \-\-delim=\f[I]delim\f[]
chr, optional.
Delimiting character [default: \[aq]\\n\[aq]].
Expand Down

0 comments on commit ea2367e

Please sign in to comment.