Skip to content

Commit

Permalink
bump version, merge branch 'devel'
Browse files Browse the repository at this point in the history
- fix `str.isnumeric` #605
- fix `WeakSet` `KeyError` #548, #553, #596 -> #607
- stop `tqdm_notebook` description truncation #582 -> #599
- include `unit_scale` for `rate` #608
- add `auto` -> nowarning `autonotebook`
- add better postfix numeric formatting #621
- minor refactoring #609 -> #616
- update documentation
- add unit tests
- fix py26 CI
  • Loading branch information
casperdcl committed Oct 15, 2018
2 parents 96d8a3c + 5aa5924 commit 71f13f4
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 54 deletions.
4 changes: 3 additions & 1 deletion .mailmap
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
Casper da Costa-Luis <tqdm@caspersci.uk.to> casperdcl
Stephen Larroque <lrq3000@gmail.com>
Guangshuo Chen <guangshuo.chen@inria.fr> Guangshuo CHEN
Guangshuo Chen <guangshuo.chen@gmail.com> Guangshuo CHEN
Guangshuo Chen <guangshuo.chen@gmail.com> <guangshuo.chen@inria.fr>
Noam Yorav-Raphael <noamraph@gmail.com>
Max Nordlund <max.nordlund@gmail.com>
Julien Chaumont <git@julienc.io>
Greg Gandenberger <greg@gandenberger.org>
Todd <toddrme2178@gmail.com>
Sergei Izmailov <sergei.a.izmailov@gmail.com>
James Lu <CrazyPython@users.noreply.github.com>
Expand Down
19 changes: 10 additions & 9 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ Documentation
maxinterval=10.0, miniters=None, ascii=None, disable=False,
unit='it', unit_scale=False, dynamic_ncols=False,
smoothing=0.3, bar_format=None, initial=0, position=None,
postfix=None):
postfix=None, unit_divisor=1000):
Parameters
~~~~~~~~~~
Expand All @@ -277,7 +277,7 @@ Parameters
* desc : str, optional
Prefix for the progressbar.
* total : int, optional
The number of expected iterations. If (default: None),
The number of expected iterations. If unspecified,
len(iterable) is used if possible. As a last resort, only basic
progress statistics are displayed (no ETA, no progressbar).
If ``gui`` is True and this parameter needs subsequent updating,
Expand All @@ -297,9 +297,9 @@ Parameters
fallback is a meter width of 10 and no limit for the counter and
statistics. If 0, will not print any meter (only stats).
* mininterval : float, optional
Minimum progress display update interval, in seconds [default: 0.1].
Minimum progress display update interval [default: 0.1] seconds.
* maxinterval : float, optional
Maximum progress display update interval, in seconds [default: 10].
Maximum progress display update interval [default: 10] seconds.
Automatically adjusts ``miniters`` to correspond to ``mininterval``
after long display update lag. Only works if ``dynamic_miniters``
or monitor thread is enabled.
Expand All @@ -316,7 +316,7 @@ Parameters
the meter. The fallback is to use ASCII characters ``1-9 #``.
* disable : bool, optional
Whether to disable the entire progressbar wrapper
[default: False].
[default: False]. If set to None, disable on non-TTY.
* unit : str, optional
String that will be used to define the unit of each iteration
[default: it].
Expand All @@ -338,10 +338,10 @@ Parameters
[default: '{l_bar}{bar}{r_bar}'], where
l_bar='{desc}: {percentage:3.0f}%|' and
r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, '
'{rate_fmt}{postfix}]'
'{rate_fmt}{postfix}]'
Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt,
percentage, rate, rate_fmt, rate_noinv, rate_noinv_fmt,
rate_inv, rate_inv_fmt, elapsed, remaining, desc, postfix.
percentage, rate, rate_fmt, rate_noinv, rate_noinv_fmt,
rate_inv, rate_inv_fmt, elapsed, remaining, desc, postfix.
Note that a trailing ": " is automatically removed after {desc}
if the latter is empty.
* initial : int, optional
Expand Down Expand Up @@ -675,7 +675,8 @@ console or notebook versions by using the ``autonotebook`` submodule:
Note that this will issue a ``TqdmExperimentalWarning`` if run in a notebook
since it is not meant to be possible to distinguish between ``jupyter notebook``
and ``jupyter console``.
and ``jupyter console``. Use ``auto`` instead of ``autonotebook`` to suppress
this warning.

Writing messages
~~~~~~~~~~~~~~~~
Expand Down
6 changes: 5 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ commands =

[testenv:py26]
# no codecov and timer for py26
deps = {[coverage]deps}
deps =
nose
coverage
coveralls==1.2.0
pycparser==2.18
commands = {[coverage]commands}

[testenv:pypy]
Expand Down
4 changes: 2 additions & 2 deletions tqdm.1
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ If 0, will not print any meter (only stats).
.TP
.B \-\-mininterval=\f[I]mininterval\f[]
float, optional.
Minimum progress display update interval, in seconds [default: 0.1].
Minimum progress display update interval [default: 0.1] seconds.
.RS
.RE
.TP
.B \-\-maxinterval=\f[I]maxinterval\f[]
float, optional.
Maximum progress display update interval, in seconds [default: 10].
Maximum progress display update interval [default: 10] seconds.
Automatically adjusts \f[C]miniters\f[] to correspond to
\f[C]mininterval\f[] after long display update lag.
Only works if \f[C]dynamic_miniters\f[] or monitor thread is enabled.
Expand Down
74 changes: 56 additions & 18 deletions tqdm/_tqdm.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,44 @@ def format_interval(t):
else:
return '{0:02d}:{1:02d}'.format(m, s)

@staticmethod
def format_num(n):
"""
Intelligent scientific notation (.3g).
Parameters
----------
n : int or float or Numeric
A Number.
Returns
-------
out : str
Formatted number.
"""
f = '{0:.3g}'.format(n).replace('+0', '+').replace('-0', '-')
n = str(n)
return f if len(f) < len(n) else n

@staticmethod
def ema(x, mu=None, alpha=0.3):
"""
Exponential moving average: smoothing to give progressively lower
weights to older values.
Parameters
----------
x : float
New value to include in EMA.
mu : float, optional
Previous EMA value.
alpha : float, optional
Smoothing factor in range [0, 1], [default: 0.3].
Increase to give more weight to recent values.
Ranges from 0 (yields mu) to 1 (yields x).
"""
return x if mu is None else (alpha * x) + (1 - alpha) * mu

@staticmethod
def status_printer(file):
"""
Expand Down Expand Up @@ -267,6 +305,8 @@ def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False,
if unit_scale and unit_scale not in (True, 1):
total *= unit_scale
n *= unit_scale
if rate:
rate *= unit_scale # by default rate = 1 / self.avg_time
unit_scale = False

format_interval = tqdm.format_interval
Expand Down Expand Up @@ -440,9 +480,11 @@ def _decr_instances(cls, instance):
try:
cls._instances.remove(instance)
except KeyError:
if not instance.gui: # pragma: no cover
raise
else:
# if not instance.gui: # pragma: no cover
# raise
pass # py2: maybe magically removed already
# else:
if not instance.gui:
for inst in cls._instances:
# negative `pos` means fixed
if inst.pos > abs(instance.pos):
Expand Down Expand Up @@ -679,9 +721,9 @@ def __init__(self, iterable=None, desc=None, total=None, leave=True,
fallback is a meter width of 10 and no limit for the counter and
statistics. If 0, will not print any meter (only stats).
mininterval : float, optional
Minimum progress display update interval, in seconds [default: 0.1].
Minimum progress display update interval [default: 0.1] seconds.
maxinterval : float, optional
Maximum progress display update interval, in seconds [default: 10].
Maximum progress display update interval [default: 10] seconds.
Automatically adjusts `miniters` to correspond to `mininterval`
after long display update lag. Only works if `dynamic_miniters`
or monitor thread is enabled.
Expand Down Expand Up @@ -948,10 +990,8 @@ def __iter__(self):
delta_it = n - last_print_n
# EMA (not just overall average)
if smoothing and delta_t and delta_it:
avg_time = delta_t / delta_it \
if avg_time is None \
else smoothing * delta_t / delta_it + \
(1 - smoothing) * avg_time
rate = delta_t / delta_it
avg_time = self.ema(rate, avg_time, smoothing)
self.avg_time = avg_time

self.n = n
Expand All @@ -977,10 +1017,10 @@ def __iter__(self):
elif smoothing:
# EMA-weight miniters to converge
# towards the timeframe of mininterval
miniters = smoothing * delta_it * \
(mininterval / delta_t
if mininterval and delta_t else 1) + \
(1 - smoothing) * miniters
rate = delta_it
if mininterval and delta_t:
rate *= mininterval / delta_t
miniters = self.ema(rate, miniters, smoothing)
else:
# Maximum nb of iterations between 2 prints
miniters = max(miniters, delta_it)
Expand Down Expand Up @@ -1034,10 +1074,8 @@ def update(self, n=1):
# elapsed = cur_t - self.start_t
# EMA (not just overall average)
if self.smoothing and delta_t and delta_it:
self.avg_time = delta_t / delta_it \
if self.avg_time is None \
else self.smoothing * delta_t / delta_it + \
(1 - self.smoothing) * self.avg_time
rate = delta_t / delta_it
self.avg_time = self.ema(rate, self.avg_time, self.smoothing)

if not hasattr(self, "sp"):
raise TqdmDeprecationWarning("""\
Expand Down Expand Up @@ -1181,7 +1219,7 @@ def set_postfix(self, ordered_dict=None, refresh=True, **kwargs):
for key in postfix.keys():
# Number: limit the length of the string
if isinstance(postfix[key], Number):
postfix[key] = '{0:2.3g}'.format(postfix[key])
postfix[key] = self.format_num(postfix[key])
# Else for any other type, try to get the string conversion
elif not isinstance(postfix[key], _basestring):
postfix[key] = str(postfix[key])
Expand Down
25 changes: 11 additions & 14 deletions tqdm/_tqdm_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,9 @@ def __iter__(self):
if delta_t >= mininterval:
elapsed = cur_t - start_t
# EMA (not just overall average)
if smoothing and delta_t:
avg_time = delta_t / delta_it \
if avg_time is None \
else smoothing * delta_t / delta_it + \
(1 - smoothing) * avg_time
if smoothing and delta_t and delta_it:
rate = delta_t / delta_it
avg_time = self.ema(rate, avg_time, smoothing)

# Inline due to multiple calls
total = self.total
Expand Down Expand Up @@ -208,11 +206,12 @@ def __iter__(self):
elif mininterval and delta_t:
# EMA-weight miniters to converge
# towards the timeframe of mininterval
miniters = smoothing * delta_it * mininterval \
/ delta_t + (1 - smoothing) * miniters
rate = delta_it
if mininterval and delta_t:
rate *= mininterval / delta_t
miniters = self.ema(rate, miniters, smoothing)
else:
miniters = smoothing * delta_it + \
(1 - smoothing) * miniters
miniters = self.ema(delta_it, miniters, smoothing)

# Store old values for next call
last_print_n = n
Expand Down Expand Up @@ -242,11 +241,9 @@ def update(self, n=1):
if delta_t >= self.mininterval:
elapsed = cur_t - self.start_t
# EMA (not just overall average)
if self.smoothing and delta_t:
self.avg_time = delta_t / delta_it \
if self.avg_time is None \
else self.smoothing * delta_t / delta_it + \
(1 - self.smoothing) * self.avg_time
if self.smoothing and delta_t and delta_it:
rate = delta_t / delta_it
self.avg_time = self.ema(rate, self.avg_time, self.smoothing)

# Inline due to multiple calls
total = self.total
Expand Down
18 changes: 15 additions & 3 deletions tqdm/_tqdm_notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@

if True: # pragma: no cover
# import IPython/Jupyter base widget and display utilities
IPY = 0
IPYW = 0
try: # IPython 4.x
import ipywidgets
IPY = 4
try:
IPYW = int(ipywidgets.__version__.split('.')[0])
except AttributeError: # __version__ may not exist in old versions
pass
except ImportError: # IPython 3.x / 2.x
IPY = 32
import warnings
Expand Down Expand Up @@ -108,6 +114,8 @@ def status_printer(_, total=None, desc=None, ncols=None):

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
Expand All @@ -116,9 +124,11 @@ def status_printer(_, total=None, desc=None, ncols=None):
if ncols is not None: # use default style of ipywidgets
# ncols could be 100, "100px", "100%"
ncols = str(ncols) # ipywidgets only accepts string
if ncols[-1].isnumeric():
# if last value is digit, assume the value is digit
ncols += 'px'
try:
if int(ncols) > 0: # isnumeric and positive
ncols += 'px'
except ValueError:
pass
pbar.layout.flex = '2'
container.layout.width = ncols
container.layout.display = 'inline-flex'
Expand Down Expand Up @@ -170,6 +180,8 @@ def print_status(s='', close=False, bar_style=None, desc=None):
# Update description
if desc:
pbar.description = desc
if IPYW >= 7:
pbar.style.description_width = 'initial'

return print_status

Expand Down
2 changes: 1 addition & 1 deletion tqdm/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
__all__ = ["__version__"]

# major, minor, patch, -extra
version_info = 4, 26, 0
version_info = 4, 27, 0

# Nice string for the version
__version__ = '.'.join(map(str, version_info))
Expand Down
6 changes: 6 additions & 0 deletions tqdm/auto/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import warnings
from .._tqdm import TqdmExperimentalWarning
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=TqdmExperimentalWarning)
from ..autonotebook import tqdm, trange
__all__ = ["tqdm", "trange"]
26 changes: 21 additions & 5 deletions tqdm/tests/tests_tqdm.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,15 @@ def test_format_interval():
assert format_interval(238113) == '66:08:33'


def test_format_num():
"""Test number format"""
format_num = tqdm.format_num

assert float(format_num(1337)) == 1337
assert format_num(int(1e6)) == '1e+6'
assert format_num(1239876) == '1''239''876'


def test_format_meter():
"""Test statistics and progress bar formatting"""
try:
Expand Down Expand Up @@ -1604,14 +1613,21 @@ def internal(our_file, disable):
internal(our_file, True)


@with_setup(pretest, posttest)
def test_autonotebook():
"""Test autonotebook fallback"""
from tqdm.autonotebook import tqdm as tn
from tqdm.autonotebook import trange as tr
def backendCheck(module):
"""Test tqdm-like module fallback"""
tn = module.tqdm
tr = module.trange

with closing(StringIO()) as our_file:
with tn(total=10, file=our_file) as t:
assert len(t) == 10
with tr(1337) as t:
assert len(t) == 1337


@with_setup(pretest, posttest)
def test_auto():
"""Test auto fallback"""
from tqdm import autonotebook, auto
backendCheck(autonotebook)
backendCheck(auto)

0 comments on commit 71f13f4

Please sign in to comment.