summaryrefslogtreecommitdiffhomepage
path: root/libs/tqdm
diff options
context:
space:
mode:
Diffstat (limited to 'libs/tqdm')
-rw-r--r--libs/tqdm/__init__.py21
-rw-r--r--libs/tqdm/__main__.py1
-rw-r--r--libs/tqdm/_main.py4
-rw-r--r--libs/tqdm/_monitor.py32
-rw-r--r--libs/tqdm/_tqdm.py4
-rw-r--r--libs/tqdm/_tqdm_gui.py4
-rw-r--r--libs/tqdm/_tqdm_notebook.py4
-rw-r--r--libs/tqdm/_tqdm_pandas.py38
-rw-r--r--libs/tqdm/_utils.py10
-rw-r--r--libs/tqdm/_version.py59
-rw-r--r--libs/tqdm/asyncio.py93
-rw-r--r--libs/tqdm/auto.py40
-rw-r--r--libs/tqdm/autonotebook.py16
-rw-r--r--libs/tqdm/cli.py155
-rwxr-xr-x[-rw-r--r--]libs/tqdm/completion.sh4
-rw-r--r--libs/tqdm/contrib/__init__.py80
-rw-r--r--libs/tqdm/contrib/bells.py24
-rw-r--r--libs/tqdm/contrib/concurrent.py66
-rw-r--r--libs/tqdm/contrib/discord.py121
-rw-r--r--libs/tqdm/contrib/itertools.py8
-rw-r--r--libs/tqdm/contrib/logging.py128
-rw-r--r--libs/tqdm/contrib/telegram.py153
-rw-r--r--libs/tqdm/contrib/utils_worker.py40
-rw-r--r--libs/tqdm/dask.py46
-rw-r--r--libs/tqdm/gui.py216
-rw-r--r--libs/tqdm/keras.py47
-rw-r--r--libs/tqdm/notebook.py201
-rw-r--r--libs/tqdm/rich.py152
-rw-r--r--libs/tqdm/std.py581
-rw-r--r--libs/tqdm/tests/tests_concurrent.py58
-rw-r--r--libs/tqdm/tests/tests_contrib.py61
-rw-r--r--libs/tqdm/tests/tests_itertools.py27
-rw-r--r--libs/tqdm/tests/tests_keras.py97
-rw-r--r--libs/tqdm/tests/tests_main.py172
-rw-r--r--libs/tqdm/tests/tests_notebook.py9
-rw-r--r--libs/tqdm/tests/tests_pandas.py264
-rw-r--r--libs/tqdm/tests/tests_perf.py367
-rw-r--r--libs/tqdm/tests/tests_synchronisation.py213
-rw-r--r--libs/tqdm/tests/tests_tqdm.py1966
-rw-r--r--libs/tqdm/tests/tests_version.py12
-rw-r--r--libs/tqdm/tk.py207
-rw-r--r--libs/tqdm/tqdm.174
-rw-r--r--libs/tqdm/utils.py227
-rw-r--r--libs/tqdm/version.py9
44 files changed, 1882 insertions, 4229 deletions
diff --git a/libs/tqdm/__init__.py b/libs/tqdm/__init__.py
index 670d6457e..a021d16e9 100644
--- a/libs/tqdm/__init__.py
+++ b/libs/tqdm/__init__.py
@@ -1,13 +1,12 @@
-from .std import tqdm, trange
-from .gui import tqdm as tqdm_gui # TODO: remove in v5.0.0
-from .gui import trange as tgrange # TODO: remove in v5.0.0
+from ._monitor import TMonitor, TqdmSynchronisationWarning
from ._tqdm_pandas import tqdm_pandas
from .cli import main # TODO: remove in v5.0.0
-from ._monitor import TMonitor, TqdmSynchronisationWarning
-from ._version import __version__ # NOQA
-from .std import TqdmTypeError, TqdmKeyError, TqdmWarning, \
- TqdmDeprecationWarning, TqdmExperimentalWarning, \
- TqdmMonitorWarning
+from .gui import tqdm as tqdm_gui # TODO: remove in v5.0.0
+from .gui import trange as tgrange # TODO: remove in v5.0.0
+from .std import (
+ TqdmDeprecationWarning, TqdmExperimentalWarning, TqdmKeyError, TqdmMonitorWarning,
+ TqdmTypeError, TqdmWarning, tqdm, trange)
+from .version import __version__
__all__ = ['tqdm', 'tqdm_gui', 'trange', 'tgrange', 'tqdm_pandas',
'tqdm_notebook', 'tnrange', 'main', 'TMonitor',
@@ -20,8 +19,9 @@ __all__ = ['tqdm', 'tqdm_gui', 'trange', 'tgrange', 'tqdm_pandas',
def tqdm_notebook(*args, **kwargs): # pragma: no cover
"""See tqdm.notebook.tqdm for full documentation"""
- from .notebook import tqdm as _tqdm_notebook
from warnings import warn
+
+ from .notebook import tqdm as _tqdm_notebook
warn("This function will be removed in tqdm==5.0.0\n"
"Please use `tqdm.notebook.tqdm` instead of `tqdm.tqdm_notebook`",
TqdmDeprecationWarning, stacklevel=2)
@@ -33,8 +33,9 @@ def tnrange(*args, **kwargs): # pragma: no cover
A shortcut for `tqdm.notebook.tqdm(xrange(*args), **kwargs)`.
On Python3+, `range` is used instead of `xrange`.
"""
- from .notebook import trange as _tnrange
from warnings import warn
+
+ from .notebook import trange as _tnrange
warn("Please use `tqdm.notebook.trange` instead of `tqdm.tnrange`",
TqdmDeprecationWarning, stacklevel=2)
return _tnrange(*args, **kwargs)
diff --git a/libs/tqdm/__main__.py b/libs/tqdm/__main__.py
index 130bc6375..4e28416e1 100644
--- a/libs/tqdm/__main__.py
+++ b/libs/tqdm/__main__.py
@@ -1,2 +1,3 @@
from .cli import main
+
main()
diff --git a/libs/tqdm/_main.py b/libs/tqdm/_main.py
index 07b6730b1..04fdeeff1 100644
--- a/libs/tqdm/_main.py
+++ b/libs/tqdm/_main.py
@@ -1,7 +1,9 @@
+from warnings import warn
+
from .cli import * # NOQA
from .cli import __all__ # NOQA
from .std import TqdmDeprecationWarning
-from warnings import warn
+
warn("This function will be removed in tqdm==5.0.0\n"
"Please use `tqdm.cli.*` instead of `tqdm._main.*`",
TqdmDeprecationWarning, stacklevel=2)
diff --git a/libs/tqdm/_monitor.py b/libs/tqdm/_monitor.py
index e1e257069..f71aa5681 100644
--- a/libs/tqdm/_monitor.py
+++ b/libs/tqdm/_monitor.py
@@ -1,7 +1,8 @@
+import atexit
from threading import Event, Thread, current_thread
from time import time
from warnings import warn
-import atexit
+
__all__ = ["TMonitor", "TqdmSynchronisationWarning"]
@@ -21,29 +22,19 @@ class TMonitor(Thread):
----------
tqdm_cls : class
tqdm class to use (can be core tqdm or a submodule).
- sleep_interval : fload
+ sleep_interval : float
Time to sleep between monitoring checks.
"""
-
- # internal vars for unit testing
- _time = None
- _event = None
+ _test = {} # internal vars for unit testing
def __init__(self, tqdm_cls, sleep_interval):
Thread.__init__(self)
self.daemon = True # kill thread when main killed (KeyboardInterrupt)
- self.was_killed = Event()
self.woken = 0 # last time woken up, to sync with monitor
self.tqdm_cls = tqdm_cls
self.sleep_interval = sleep_interval
- if TMonitor._time is not None:
- self._time = TMonitor._time
- else:
- self._time = time
- if TMonitor._event is not None:
- self._event = TMonitor._event
- else:
- self._event = Event
+ self._time = self._test.get("time", time)
+ self.was_killed = self._test.get("Event", Event)()
atexit.register(self.exit)
self.start()
@@ -82,18 +73,23 @@ class TMonitor(Thread):
return
# Only if mininterval > 1 (else iterations are just slow)
# and last refresh exceeded maxinterval
- if instance.miniters > 1 and \
- (cur_t - instance.last_print_t) >= \
- instance.maxinterval:
+ if (
+ instance.miniters > 1
+ and (cur_t - instance.last_print_t) >= instance.maxinterval
+ ):
# force bypassing miniters on next iteration
# (dynamic_miniters adjusts mininterval automatically)
instance.miniters = 1
# Refresh now! (works only for manual tqdm)
instance.refresh(nolock=True)
+ # Remove accidental long-lived strong reference
+ del instance
if instances != self.get_instances(): # pragma: nocover
warn("Set changed size during iteration" +
" (see https://github.com/tqdm/tqdm/issues/481)",
TqdmSynchronisationWarning, stacklevel=2)
+ # Remove accidental long-lived strong references
+ del instances
def report(self):
return not self.was_killed.is_set()
diff --git a/libs/tqdm/_tqdm.py b/libs/tqdm/_tqdm.py
index 694318ee7..7fc496277 100644
--- a/libs/tqdm/_tqdm.py
+++ b/libs/tqdm/_tqdm.py
@@ -1,7 +1,9 @@
+from warnings import warn
+
from .std import * # NOQA
from .std import __all__ # NOQA
from .std import TqdmDeprecationWarning
-from warnings import warn
+
warn("This function will be removed in tqdm==5.0.0\n"
"Please use `tqdm.std.*` instead of `tqdm._tqdm.*`",
TqdmDeprecationWarning, stacklevel=2)
diff --git a/libs/tqdm/_tqdm_gui.py b/libs/tqdm/_tqdm_gui.py
index 541f104fb..f32aa894f 100644
--- a/libs/tqdm/_tqdm_gui.py
+++ b/libs/tqdm/_tqdm_gui.py
@@ -1,7 +1,9 @@
+from warnings import warn
+
from .gui import * # NOQA
from .gui import __all__ # NOQA
from .std import TqdmDeprecationWarning
-from warnings import warn
+
warn("This function will be removed in tqdm==5.0.0\n"
"Please use `tqdm.gui.*` instead of `tqdm._tqdm_gui.*`",
TqdmDeprecationWarning, stacklevel=2)
diff --git a/libs/tqdm/_tqdm_notebook.py b/libs/tqdm/_tqdm_notebook.py
index dde999817..f225fbf5b 100644
--- a/libs/tqdm/_tqdm_notebook.py
+++ b/libs/tqdm/_tqdm_notebook.py
@@ -1,7 +1,9 @@
+from warnings import warn
+
from .notebook import * # NOQA
from .notebook import __all__ # NOQA
from .std import TqdmDeprecationWarning
-from warnings import warn
+
warn("This function will be removed in tqdm==5.0.0\n"
"Please use `tqdm.notebook.*` instead of `tqdm._tqdm_notebook.*`",
TqdmDeprecationWarning, stacklevel=2)
diff --git a/libs/tqdm/_tqdm_pandas.py b/libs/tqdm/_tqdm_pandas.py
index 234fafffe..c4fe6efdc 100644
--- a/libs/tqdm/_tqdm_pandas.py
+++ b/libs/tqdm/_tqdm_pandas.py
@@ -4,43 +4,21 @@ __author__ = "github.com/casperdcl"
__all__ = ['tqdm_pandas']
-def tqdm_pandas(tclass, *targs, **tkwargs):
+def tqdm_pandas(tclass, **tqdm_kwargs):
"""
Registers the given `tqdm` instance with
`pandas.core.groupby.DataFrameGroupBy.progress_apply`.
- It will even close() the `tqdm` instance upon completion.
-
- Parameters
- ----------
- tclass : tqdm class you want to use (eg, tqdm, tqdm_notebook, etc)
- targs and tkwargs : arguments for the tqdm instance
-
- Examples
- --------
- >>> import pandas as pd
- >>> import numpy as np
- >>> from tqdm import tqdm, tqdm_pandas
- >>>
- >>> df = pd.DataFrame(np.random.randint(0, 100, (100000, 6)))
- >>> tqdm_pandas(tqdm, leave=True) # can use tqdm_gui, optional kwargs, etc
- >>> # Now you can use `progress_apply` instead of `apply`
- >>> df.groupby(0).progress_apply(lambda x: x**2)
-
- References
- ----------
- https://stackoverflow.com/questions/18603270/
- progress-indicator-during-pandas-operations-python
"""
from tqdm import TqdmDeprecationWarning
if isinstance(tclass, type) or (getattr(tclass, '__name__', '').startswith(
'tqdm_')): # delayed adapter case
- TqdmDeprecationWarning("""\
-Please use `tqdm.pandas(...)` instead of `tqdm_pandas(tqdm, ...)`.
-""", fp_write=getattr(tkwargs.get('file', None), 'write', sys.stderr.write))
- tclass.pandas(*targs, **tkwargs)
+ TqdmDeprecationWarning(
+ "Please use `tqdm.pandas(...)` instead of `tqdm_pandas(tqdm, ...)`.",
+ fp_write=getattr(tqdm_kwargs.get('file', None), 'write', sys.stderr.write))
+ tclass.pandas(**tqdm_kwargs)
else:
- TqdmDeprecationWarning("""\
-Please use `tqdm.pandas(...)` instead of `tqdm_pandas(tqdm(...))`.
-""", fp_write=getattr(tclass.fp, 'write', sys.stderr.write))
+ TqdmDeprecationWarning(
+ "Please use `tqdm.pandas(...)` instead of `tqdm_pandas(tqdm(...))`.",
+ fp_write=getattr(tclass.fp, 'write', sys.stderr.write))
type(tclass).pandas(deprecated_t=tclass)
diff --git a/libs/tqdm/_utils.py b/libs/tqdm/_utils.py
index 084327f47..2cf10909f 100644
--- a/libs/tqdm/_utils.py
+++ b/libs/tqdm/_utils.py
@@ -1,6 +1,12 @@
-from .utils import CUR_OS, IS_WIN, IS_NIX, RE_ANSI, _range, _unich, _unicode, colorama, WeakSet, _basestring, _OrderedDict, FormatReplace, Comparable, SimpleTextIOWrapper, _is_utf, _supports_unicode, _is_ascii, _screen_shape_wrapper, _screen_shape_windows, _screen_shape_tput, _screen_shape_linux, _environ_cols_wrapper, _term_move_up # NOQA
-from .std import TqdmDeprecationWarning
from warnings import warn
+
+from .std import TqdmDeprecationWarning
+from .utils import ( # NOQA, pylint: disable=unused-import
+ CUR_OS, IS_NIX, IS_WIN, RE_ANSI, Comparable, FormatReplace, SimpleTextIOWrapper, _basestring,
+ _environ_cols_wrapper, _is_ascii, _is_utf, _range, _screen_shape_linux, _screen_shape_tput,
+ _screen_shape_windows, _screen_shape_wrapper, _supports_unicode, _term_move_up, _unich,
+ _unicode, colorama)
+
warn("This function will be removed in tqdm==5.0.0\n"
"Please use `tqdm.utils.*` instead of `tqdm._utils.*`",
TqdmDeprecationWarning, stacklevel=2)
diff --git a/libs/tqdm/_version.py b/libs/tqdm/_version.py
deleted file mode 100644
index 26606cb03..000000000
--- a/libs/tqdm/_version.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Definition of the version number
-import os
-from io import open as io_open
-
-__all__ = ["__version__"]
-
-# major, minor, patch, -extra
-version_info = 4, 46, 1
-
-# Nice string for the version
-__version__ = '.'.join(map(str, version_info))
-
-
-# auto -extra based on commit hash (if not tagged as release)
-scriptdir = os.path.dirname(__file__)
-gitdir = os.path.abspath(os.path.join(scriptdir, "..", ".git"))
-if os.path.isdir(gitdir): # pragma: nocover
- extra = None
- # Open config file to check if we are in tqdm project
- with io_open(os.path.join(gitdir, "config"), 'r') as fh_config:
- if 'tqdm' in fh_config.read():
- # Open the HEAD file
- with io_open(os.path.join(gitdir, "HEAD"), 'r') as fh_head:
- extra = fh_head.readline().strip()
- # in a branch => HEAD points to file containing last commit
- if 'ref:' in extra:
- # reference file path
- ref_file = extra[5:]
- branch_name = ref_file.rsplit('/', 1)[-1]
-
- ref_file_path = os.path.abspath(os.path.join(gitdir, ref_file))
- # check that we are in git folder
- # (by stripping the git folder from the ref file path)
- if os.path.relpath(
- ref_file_path, gitdir).replace('\\', '/') != ref_file:
- # out of git folder
- extra = None
- else:
- # open the ref file
- with io_open(ref_file_path, 'r') as fh_branch:
- commit_hash = fh_branch.readline().strip()
- extra = commit_hash[:8]
- if branch_name != "master":
- extra += '.' + branch_name
-
- # detached HEAD mode, already have commit hash
- else:
- extra = extra[:8]
-
- # Append commit hash (and branch) to version string if not tagged
- if extra is not None:
- try:
- with io_open(os.path.join(gitdir, "refs", "tags",
- 'v' + __version__)) as fdv:
- if fdv.readline().strip()[:8] != extra[:8]:
- __version__ += '-' + extra
- except Exception as e:
- if "No such file" not in str(e):
- raise
diff --git a/libs/tqdm/asyncio.py b/libs/tqdm/asyncio.py
new file mode 100644
index 000000000..97c5f88fc
--- /dev/null
+++ b/libs/tqdm/asyncio.py
@@ -0,0 +1,93 @@
+"""
+Asynchronous progressbar decorator for iterators.
+Includes a default `range` iterator printing to `stderr`.
+
+Usage:
+>>> from tqdm.asyncio import trange, tqdm
+>>> async for i in trange(10):
+... ...
+"""
+import asyncio
+from sys import version_info
+
+from .std import tqdm as std_tqdm
+
+__author__ = {"github.com/": ["casperdcl"]}
+__all__ = ['tqdm_asyncio', 'tarange', 'tqdm', 'trange']
+
+
+class tqdm_asyncio(std_tqdm):
+ """
+ Asynchronous-friendly version of tqdm (Python 3.6+).
+ """
+ def __init__(self, iterable=None, *args, **kwargs):
+ super(tqdm_asyncio, self).__init__(iterable, *args, **kwargs)
+ self.iterable_awaitable = False
+ if iterable is not None:
+ if hasattr(iterable, "__anext__"):
+ self.iterable_next = iterable.__anext__
+ self.iterable_awaitable = True
+ elif hasattr(iterable, "__next__"):
+ self.iterable_next = iterable.__next__
+ else:
+ self.iterable_iterator = iter(iterable)
+ self.iterable_next = self.iterable_iterator.__next__
+
+ def __aiter__(self):
+ return self
+
+ async def __anext__(self):
+ try:
+ if self.iterable_awaitable:
+ res = await self.iterable_next()
+ else:
+ res = self.iterable_next()
+ self.update()
+ return res
+ except StopIteration:
+ self.close()
+ raise StopAsyncIteration
+ except BaseException:
+ self.close()
+ raise
+
+ def send(self, *args, **kwargs):
+ return self.iterable.send(*args, **kwargs)
+
+ @classmethod
+ def as_completed(cls, fs, *, loop=None, timeout=None, total=None, **tqdm_kwargs):
+ """
+ Wrapper for `asyncio.as_completed`.
+ """
+ if total is None:
+ total = len(fs)
+ kwargs = {}
+ if version_info[:2] < (3, 10):
+ kwargs['loop'] = loop
+ yield from cls(asyncio.as_completed(fs, timeout=timeout, **kwargs),
+ total=total, **tqdm_kwargs)
+
+ @classmethod
+ async def gather(cls, *fs, loop=None, timeout=None, total=None, **tqdm_kwargs):
+ """
+ Wrapper for `asyncio.gather`.
+ """
+ async def wrap_awaitable(i, f):
+ return i, await f
+
+ ifs = [wrap_awaitable(i, f) for i, f in enumerate(fs)]
+ res = [await f for f in cls.as_completed(ifs, loop=loop, timeout=timeout,
+ total=total, **tqdm_kwargs)]
+ return [i for _, i in sorted(res)]
+
+
+def tarange(*args, **kwargs):
+ """
+ A shortcut for `tqdm.asyncio.tqdm(range(*args), **kwargs)`.
+ """
+ return tqdm_asyncio(range(*args), **kwargs)
+
+
+# Aliases
+tqdm = tqdm_asyncio
+trange = tarange
diff --git a/libs/tqdm/auto.py b/libs/tqdm/auto.py
index 4dd171754..cffca206f 100644
--- a/libs/tqdm/auto.py
+++ b/libs/tqdm/auto.py
@@ -1,6 +1,44 @@
+"""
+Enables multiple commonly used features.
+
+Method resolution order:
+
+- `tqdm.autonotebook` without import warnings
+- `tqdm.asyncio` on Python3.6+
+- `tqdm.std` base class
+
+Usage:
+>>> from tqdm.auto import trange, tqdm
+>>> for i in trange(10):
+... ...
+"""
+import sys
import warnings
+
from .std import TqdmExperimentalWarning
+
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=TqdmExperimentalWarning)
- from .autonotebook import tqdm, trange
+ from .autonotebook import tqdm as notebook_tqdm
+ from .autonotebook import trange as notebook_trange
+
+if sys.version_info[:2] < (3, 6):
+ tqdm = notebook_tqdm
+ trange = notebook_trange
+else: # Python3.6+
+ from .asyncio import tqdm as asyncio_tqdm
+ from .std import tqdm as std_tqdm
+
+ if notebook_tqdm != std_tqdm:
+ class tqdm(notebook_tqdm, asyncio_tqdm): # pylint: disable=inconsistent-mro
+ pass
+ else:
+ tqdm = asyncio_tqdm
+
+ def trange(*args, **kwargs):
+ """
+ A shortcut for `tqdm.auto.tqdm(range(*args), **kwargs)`.
+ """
+ return tqdm(range(*args), **kwargs)
+
__all__ = ["tqdm", "trange"]
diff --git a/libs/tqdm/autonotebook.py b/libs/tqdm/autonotebook.py
index 0bcd42a13..b032061bf 100644
--- a/libs/tqdm/autonotebook.py
+++ b/libs/tqdm/autonotebook.py
@@ -1,17 +1,27 @@
+"""
+Automatically choose between `tqdm.notebook` and `tqdm.std`.
+
+Usage:
+>>> from tqdm.autonotebook import trange, tqdm
+>>> for i in trange(10):
+... ...
+"""
import os
+import sys
try:
- from IPython import get_ipython
+ get_ipython = sys.modules['IPython'].get_ipython
if 'IPKernelApp' not in get_ipython().config: # pragma: no cover
raise ImportError("console")
if 'VSCODE_PID' in os.environ: # pragma: no cover
raise ImportError("vscode")
-except:
+except Exception:
from .std import tqdm, trange
else: # pragma: no cover
+ from warnings import warn
+
from .notebook import tqdm, trange
from .std import TqdmExperimentalWarning
- from warnings import warn
warn("Using `tqdm.autonotebook.tqdm` in notebook mode."
" Use `tqdm.tqdm` instead to force console mode"
" (e.g. in jupyter console)", TqdmExperimentalWarning, stacklevel=2)
diff --git a/libs/tqdm/cli.py b/libs/tqdm/cli.py
index bf1cddeba..b5a16142b 100644
--- a/libs/tqdm/cli.py
+++ b/libs/tqdm/cli.py
@@ -1,13 +1,19 @@
-from .std import tqdm, TqdmTypeError, TqdmKeyError
-from ._version import __version__ # NOQA
-import sys
-import re
+"""
+Module version for monitoring CLI pipes (`... | python -m tqdm | ...`).
+"""
import logging
+import re
+import sys
+from ast import literal_eval as numeric
+
+from .std import TqdmKeyError, TqdmTypeError, tqdm
+from .version import __version__
+
__all__ = ["main"]
+log = logging.getLogger(__name__)
def cast(val, typ):
- log = logging.getLogger(__name__)
log.debug((val, typ))
if " or " in typ:
for t in typ.split(" or "):
@@ -27,40 +33,40 @@ def cast(val, typ):
raise TqdmTypeError(val + ' : ' + typ)
try:
return eval(typ + '("' + val + '")')
- except:
+ except Exception:
if typ == 'chr':
- return chr(ord(eval('"' + val + '"')))
+ return chr(ord(eval('"' + val + '"'))).encode()
else:
raise TqdmTypeError(val + ' : ' + typ)
-def posix_pipe(fin, fout, delim='\n', buf_size=256,
- callback=lambda int: None # pragma: no cover
- ):
+def posix_pipe(fin, fout, delim=b'\\n', buf_size=256,
+ callback=lambda float: None, callback_len=True):
"""
Params
------
- fin : file with `read(buf_size : int)` method
- fout : file with `write` (and optionally `flush`) methods.
- callback : function(int), e.g.: `tqdm.update`
+ fin : binary file with `read(buf_size : int)` method
+ fout : binary file with `write` (and optionally `flush`) methods.
+ callback : function(float), e.g.: `tqdm.update`
+ callback_len : If (default: True) do `callback(len(buffer))`.
+ Otherwise, do `callback(data) for data in buffer.split(delim)`.
"""
fp_write = fout.write
- # tmp = ''
if not delim:
while True:
tmp = fin.read(buf_size)
# flush at EOF
if not tmp:
- getattr(fout, 'flush', lambda: None)() # pragma: no cover
+ getattr(fout, 'flush', lambda: None)()
return
fp_write(tmp)
callback(len(tmp))
# return
- buf = ''
+ buf = b''
# n = 0
while True:
tmp = fin.read(buf_size)
@@ -69,8 +75,13 @@ def posix_pipe(fin, fout, delim='\n', buf_size=256,
if not tmp:
if buf:
fp_write(buf)
- callback(1 + buf.count(delim)) # n += 1 + buf.count(delim)
- getattr(fout, 'flush', lambda: None)() # pragma: no cover
+ if callback_len:
+ # n += 1 + buf.count(delim)
+ callback(1 + buf.count(delim))
+ else:
+ for i in buf.split(delim):
+ callback(i)
+ getattr(fout, 'flush', lambda: None)()
return # n
while True:
@@ -81,8 +92,9 @@ def posix_pipe(fin, fout, delim='\n', buf_size=256,
break
else:
fp_write(buf + tmp[:i + len(delim)])
- callback(1) # n += 1
- buf = ''
+ # n += 1
+ callback(1 if callback_len else (buf + tmp[:i]))
+ buf = b''
tmp = tmp[i + len(delim):]
@@ -109,6 +121,18 @@ CLI_EXTRA_DOC = r"""
bytes : bool, optional
If true, will count bytes, ignore `delim`, and default
`unit_scale` to True, `unit_divisor` to 1024, and `unit` to 'B'.
+ tee : bool, optional
+ If true, passes `stdin` to both `stderr` and `stdout`.
+ update : bool, optional
+ If true, will treat input as newly elapsed iterations,
+ i.e. numbers to pass to `update()`. Note that this is slow
+ (~2e5 it/s) since every input must be decoded as a number.
+ update_to : bool, optional
+ If true, will treat input as total elapsed iterations,
+ i.e. numbers to assign to `self.n`. Note that this is slow
+ (~2e5 it/s) since every input must be decoded as a number.
+ null : bool, optional
+ If true, will discard input (no stdout).
manpath : str, optional
Directory in which to install tqdm man pages.
comppath : str, optional
@@ -128,7 +152,7 @@ def main(fp=sys.stderr, argv=None):
if argv is None:
argv = sys.argv[1:]
try:
- log = argv.index('--log')
+ log_idx = argv.index('--log')
except ValueError:
for i in argv:
if i.startswith('--log='):
@@ -137,13 +161,11 @@ def main(fp=sys.stderr, argv=None):
else:
logLevel = 'INFO'
else:
- # argv.pop(log)
- # logLevel = argv.pop(log)
- logLevel = argv[log + 1]
- logging.basicConfig(
- level=getattr(logging, logLevel),
- format="%(levelname)s:%(module)s:%(lineno)d:%(message)s")
- log = logging.getLogger(__name__)
+ # argv.pop(log_idx)
+ # logLevel = argv.pop(log_idx)
+ logLevel = argv[log_idx + 1]
+ logging.basicConfig(level=getattr(logging, logLevel),
+ format="%(levelname)s:%(module)s:%(lineno)d:%(message)s")
d = tqdm.__init__.__doc__ + CLI_EXTRA_DOC
@@ -158,16 +180,17 @@ def main(fp=sys.stderr, argv=None):
# d = RE_OPTS.sub(r' --\1=<\1> : \2', d)
split = RE_OPTS.split(d)
opt_types_desc = zip(split[1::3], split[2::3], split[3::3])
- d = ''.join('\n --{0}=<{0}> : {1}{2}'.format(*otd)
+ d = ''.join(('\n --{0} : {2}{3}' if otd[1] == 'bool' else
+ '\n --{0}=<{1}> : {2}{3}').format(
+ otd[0].replace('_', '-'), otd[0], *otd[1:])
for otd in opt_types_desc if otd[0] not in UNSUPPORTED_OPTS)
d = """Usage:
tqdm [--help | options]
Options:
- -h, --help Print this help and exit
- -v, --version Print version and exit
-
+ -h, --help Print this help and exit.
+ -v, --version Print version and exit.
""" + d.strip('\n') + '\n'
# opts = docopt(d, version=__version__)
@@ -187,28 +210,43 @@ Options:
tqdm_args = {'file': fp}
try:
for (o, v) in opts.items():
+ o = o.replace('-', '_')
try:
tqdm_args[o] = cast(v, opt_types[o])
except KeyError as e:
raise TqdmKeyError(str(e))
log.debug('args:' + str(tqdm_args))
- except:
+
+ delim_per_char = tqdm_args.pop('bytes', False)
+ update = tqdm_args.pop('update', False)
+ update_to = tqdm_args.pop('update_to', False)
+ if sum((delim_per_char, update, update_to)) > 1:
+ raise TqdmKeyError("Can only have one of --bytes --update --update_to")
+ except Exception:
fp.write('\nError:\nUsage:\n tqdm [--help | options]\n')
for i in sys.stdin:
sys.stdout.write(i)
raise
else:
buf_size = tqdm_args.pop('buf_size', 256)
- delim = tqdm_args.pop('delim', '\n')
- delim_per_char = tqdm_args.pop('bytes', False)
+ delim = tqdm_args.pop('delim', b'\\n')
+ tee = tqdm_args.pop('tee', False)
manpath = tqdm_args.pop('manpath', None)
comppath = tqdm_args.pop('comppath', None)
+ if tqdm_args.pop('null', False):
+ class stdout(object):
+ @staticmethod
+ def write(_):
+ pass
+ else:
+ stdout = sys.stdout
+ stdout = getattr(stdout, 'buffer', stdout)
stdin = getattr(sys.stdin, 'buffer', sys.stdin)
- stdout = getattr(sys.stdout, 'buffer', sys.stdout)
if manpath or comppath:
from os import path
from shutil import copyfile
- from pkg_resources import resource_filename, Requirement
+
+ from pkg_resources import Requirement, resource_filename
def cp(src, dst):
"""copies from src path to dst"""
@@ -218,10 +256,19 @@ Options:
cp(resource_filename(Requirement.parse('tqdm'), 'tqdm/tqdm.1'),
path.join(manpath, 'tqdm.1'))
if comppath is not None:
- cp(resource_filename(Requirement.parse('tqdm'),
- 'tqdm/completion.sh'),
+ cp(resource_filename(Requirement.parse('tqdm'), 'tqdm/completion.sh'),
path.join(comppath, 'tqdm_completion.sh'))
sys.exit(0)
+ if tee:
+ stdout_write = stdout.write
+ fp_write = getattr(fp, 'buffer', fp).write
+
+ class stdout(object): # pylint: disable=function-redefined
+ @staticmethod
+ def write(x):
+ with tqdm.external_write_mode(file=fp):
+ fp_write(x)
+ stdout_write(x)
if delim_per_char:
tqdm_args.setdefault('unit', 'B')
tqdm_args.setdefault('unit_scale', True)
@@ -229,11 +276,33 @@ Options:
log.debug(tqdm_args)
with tqdm(**tqdm_args) as t:
posix_pipe(stdin, stdout, '', buf_size, t.update)
- elif delim == '\n':
+ elif delim == b'\\n':
log.debug(tqdm_args)
- for i in tqdm(stdin, **tqdm_args):
- stdout.write(i)
+ if update or update_to:
+ with tqdm(**tqdm_args) as t:
+ if update:
+ def callback(i):
+ t.update(numeric(i.decode()))
+ else: # update_to
+ def callback(i):
+ t.update(numeric(i.decode()) - t.n)
+ for i in stdin:
+ stdout.write(i)
+ callback(i)
+ else:
+ for i in tqdm(stdin, **tqdm_args):
+ stdout.write(i)
else:
log.debug(tqdm_args)
with tqdm(**tqdm_args) as t:
- posix_pipe(stdin, stdout, delim, buf_size, t.update)
+ callback_len = False
+ if update:
+ def callback(i):
+ t.update(numeric(i.decode()))
+ elif update_to:
+ def callback(i):
+ t.update(numeric(i.decode()) - t.n)
+ else:
+ callback = t.update
+ callback_len = True
+ posix_pipe(stdin, stdout, delim, buf_size, callback, callback_len)
diff --git a/libs/tqdm/completion.sh b/libs/tqdm/completion.sh
index fabd3f2d3..9f61c7f14 100644..100755
--- a/libs/tqdm/completion.sh
+++ b/libs/tqdm/completion.sh
@@ -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|--delay|--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 --position --postfix --smoothing --total --unit --unit_divisor --unit_scale --version --write_bytes -h -v' -- ${cur}))
+ COMPREPLY=($(compgen -W '--ascii --bar_format --buf_size --bytes --colour --comppath --delay --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
}
diff --git a/libs/tqdm/contrib/__init__.py b/libs/tqdm/contrib/__init__.py
index 01312cd05..0b5217707 100644
--- a/libs/tqdm/contrib/__init__.py
+++ b/libs/tqdm/contrib/__init__.py
@@ -3,26 +3,55 @@ Thin wrappers around common functions.
Subpackages contain potentially unstable extensions.
"""
-from tqdm import tqdm
-from tqdm.auto import tqdm as tqdm_auto
-from tqdm.utils import ObjectWrapper
-from copy import deepcopy
-import functools
import sys
+from functools import wraps
+
+from ..auto import tqdm as tqdm_auto
+from ..std import tqdm
+from ..utils import ObjectWrapper
+
__author__ = {"github.com/": ["casperdcl"]}
__all__ = ['tenumerate', 'tzip', 'tmap']
class DummyTqdmFile(ObjectWrapper):
"""Dummy file-like that will write to tqdm"""
+
+ def __init__(self, wrapped):
+ super(DummyTqdmFile, self).__init__(wrapped)
+ self._buf = []
+
def write(self, x, nolock=False):
- # Avoid print() second call (useless \n)
- if len(x.rstrip()) > 0:
- tqdm.write(x, file=self._wrapped, nolock=nolock)
+ nl = b"\n" if isinstance(x, bytes) else "\n"
+ pre, sep, post = x.rpartition(nl)
+ if sep:
+ blank = type(nl)()
+ tqdm.write(blank.join(self._buf + [pre, sep]),
+ end=blank, file=self._wrapped, nolock=nolock)
+ self._buf = [post]
+ else:
+ self._buf.append(x)
+
+ def __del__(self):
+ if self._buf:
+ blank = type(self._buf[0])()
+ try:
+ tqdm.write(blank.join(self._buf), end=blank, file=self._wrapped)
+ except (OSError, ValueError):
+ pass
-def tenumerate(iterable, start=0, total=None, tqdm_class=tqdm_auto,
- **tqdm_kwargs):
+def builtin_iterable(func):
+ """Wraps `func()` output in a `list()` in py2"""
+ if sys.version_info[:1] < (3,):
+ @wraps(func)
+ def inner(*args, **kwargs):
+ return list(func(*args, **kwargs))
+ return inner
+ return func
+
+
+def tenumerate(iterable, start=0, total=None, tqdm_class=tqdm_auto, **tqdm_kwargs):
"""
Equivalent of `numpy.ndenumerate` or builtin `enumerate`.
@@ -36,12 +65,13 @@ def tenumerate(iterable, start=0, total=None, tqdm_class=tqdm_auto,
pass
else:
if isinstance(iterable, np.ndarray):
- return tqdm_class(np.ndenumerate(iterable),
- total=total or iterable.size, **tqdm_kwargs)
- return enumerate(tqdm_class(iterable, **tqdm_kwargs), start)
+ return tqdm_class(np.ndenumerate(iterable), total=total or iterable.size,
+ **tqdm_kwargs)
+ return enumerate(tqdm_class(iterable, total=total, **tqdm_kwargs), start)
-def _tzip(iter1, *iter2plus, **tqdm_kwargs):
+@builtin_iterable
+def tzip(iter1, *iter2plus, **tqdm_kwargs):
"""
Equivalent of builtin `zip`.
@@ -49,13 +79,14 @@ def _tzip(iter1, *iter2plus, **tqdm_kwargs):
----------
tqdm_class : [default: tqdm.auto.tqdm].
"""
- kwargs = deepcopy(tqdm_kwargs)
+ kwargs = tqdm_kwargs.copy()
tqdm_class = kwargs.pop("tqdm_class", tqdm_auto)
- for i in zip(tqdm_class(iter1, **tqdm_kwargs), *iter2plus):
+ for i in zip(tqdm_class(iter1, **kwargs), *iter2plus):
yield i
-def _tmap(function, *sequences, **tqdm_kwargs):
+@builtin_iterable
+def tmap(function, *sequences, **tqdm_kwargs):
"""
Equivalent of builtin `map`.
@@ -63,18 +94,5 @@ def _tmap(function, *sequences, **tqdm_kwargs):
----------
tqdm_class : [default: tqdm.auto.tqdm].
"""
- for i in _tzip(*sequences, **tqdm_kwargs):
+ for i in tzip(*sequences, **tqdm_kwargs):
yield function(*i)
-
-
-if sys.version_info[:1] < (3,):
- @functools.wraps(_tzip)
- def tzip(*args, **kwargs):
- return list(_tzip(*args, **kwargs))
-
- @functools.wraps(_tmap)
- def tmap(*args, **kwargs):
- return list(_tmap(*args, **kwargs))
-else:
- tzip = _tzip
- tmap = _tmap
diff --git a/libs/tqdm/contrib/bells.py b/libs/tqdm/contrib/bells.py
new file mode 100644
index 000000000..be2276884
--- /dev/null
+++ b/libs/tqdm/contrib/bells.py
@@ -0,0 +1,24 @@
+"""
+Even more features than `tqdm.auto` (all the bells & whistles):
+
+- `tqdm.auto`
+- `tqdm.tqdm.pandas`
+- `tqdm.contrib.telegram`
+ + uses `${TQDM_TELEGRAM_TOKEN}` and `${TQDM_TELEGRAM_CHAT_ID}`
+- `tqdm.contrib.discord`
+ + uses `${TQDM_DISCORD_TOKEN}` and `${TQDM_DISCORD_CHANNEL_ID}`
+"""
+__all__ = ['tqdm', 'trange']
+import warnings
+from os import getenv
+
+if getenv("TQDM_TELEGRAM_TOKEN") and getenv("TQDM_TELEGRAM_CHAT_ID"):
+ from .telegram import tqdm, trange
+elif getenv("TQDM_DISCORD_TOKEN") and getenv("TQDM_DISCORD_CHANNEL_ID"):
+ from .discord import tqdm, trange
+else:
+ from ..auto import tqdm, trange
+
+with warnings.catch_warnings():
+ warnings.simplefilter("ignore", category=FutureWarning)
+ tqdm.pandas()
diff --git a/libs/tqdm/contrib/concurrent.py b/libs/tqdm/contrib/concurrent.py
index 197a5f8c5..ccb5e1252 100644
--- a/libs/tqdm/contrib/concurrent.py
+++ b/libs/tqdm/contrib/concurrent.py
@@ -2,9 +2,12 @@
Thin wrappers around `concurrent.futures`.
"""
from __future__ import absolute_import
-from tqdm import TqdmWarning
-from tqdm.auto import tqdm as tqdm_auto
-from copy import deepcopy
+
+from contextlib import contextmanager
+
+from ..auto import tqdm as tqdm_auto
+from ..std import TqdmWarning
+
try:
from operator import length_hint
except ImportError:
@@ -23,10 +26,25 @@ except ImportError:
def cpu_count():
return 4
import sys
+
__author__ = {"github.com/": ["casperdcl"]}
__all__ = ['thread_map', 'process_map']
+@contextmanager
+def ensure_lock(tqdm_class, lock_name=""):
+ """get (create if necessary) and then restore `tqdm_class`'s lock"""
+ old_lock = getattr(tqdm_class, '_lock', None) # don't create a new lock
+ lock = old_lock or tqdm_class.get_lock() # maybe create a new lock
+ lock = getattr(lock, lock_name, lock) # maybe subtype
+ tqdm_class.set_lock(lock)
+ yield lock
+ if old_lock is None:
+ del tqdm_class._lock
+ else:
+ tqdm_class.set_lock(old_lock)
+
+
def _executor_map(PoolExecutor, fn, *iterables, **tqdm_kwargs):
"""
Implementation of `thread_map` and `process_map`.
@@ -36,25 +54,26 @@ def _executor_map(PoolExecutor, fn, *iterables, **tqdm_kwargs):
tqdm_class : [default: tqdm.auto.tqdm].
max_workers : [default: min(32, cpu_count() + 4)].
chunksize : [default: 1].
+ lock_name : [default: "":str].
"""
- kwargs = deepcopy(tqdm_kwargs)
+ kwargs = tqdm_kwargs.copy()
if "total" not in kwargs:
- kwargs["total"] = len(iterables[0])
+ kwargs["total"] = length_hint(iterables[0])
tqdm_class = kwargs.pop("tqdm_class", tqdm_auto)
max_workers = kwargs.pop("max_workers", min(32, cpu_count() + 4))
chunksize = kwargs.pop("chunksize", 1)
- pool_kwargs = dict(max_workers=max_workers)
- sys_version = sys.version_info[:2]
- if sys_version >= (3, 7):
- # share lock in case workers are already using `tqdm`
- pool_kwargs.update(
- initializer=tqdm_class.set_lock, initargs=(tqdm_class.get_lock(),))
- map_args = {}
- if not (3, 0) < sys_version < (3, 5):
- map_args.update(chunksize=chunksize)
- with PoolExecutor(**pool_kwargs) as ex:
- return list(tqdm_class(
- ex.map(fn, *iterables, **map_args), **kwargs))
+ lock_name = kwargs.pop("lock_name", "")
+ with ensure_lock(tqdm_class, lock_name=lock_name) as lk:
+ pool_kwargs = {'max_workers': max_workers}
+ sys_version = sys.version_info[:2]
+ if sys_version >= (3, 7):
+ # share lock in case workers are already using `tqdm`
+ pool_kwargs.update(initializer=tqdm_class.set_lock, initargs=(lk,))
+ map_args = {}
+ if not (3, 0) < sys_version < (3, 5):
+ map_args.update(chunksize=chunksize)
+ with PoolExecutor(**pool_kwargs) as ex:
+ return list(tqdm_class(ex.map(fn, *iterables, **map_args), **kwargs))
def thread_map(fn, *iterables, **tqdm_kwargs):
@@ -64,9 +83,9 @@ def thread_map(fn, *iterables, **tqdm_kwargs):
Parameters
----------
- tqdm_class : optional
+ tqdm_class : optional
`tqdm` class to use for bars [default: tqdm.auto.tqdm].
- max_workers : int, optional
+ max_workers : int, optional
Maximum number of workers to spawn; passed to
`concurrent.futures.ThreadPoolExecutor.__init__`.
[default: max(32, cpu_count() + 4)].
@@ -84,13 +103,15 @@ def process_map(fn, *iterables, **tqdm_kwargs):
----------
tqdm_class : optional
`tqdm` class to use for bars [default: tqdm.auto.tqdm].
- max_workers : int, optional
+ max_workers : int, optional
Maximum number of workers to spawn; passed to
`concurrent.futures.ProcessPoolExecutor.__init__`.
[default: min(32, cpu_count() + 4)].
- chunksize : int, optional
+ chunksize : int, optional
Size of chunks sent to worker processes; passed to
`concurrent.futures.ProcessPoolExecutor.map`. [default: 1].
+ lock_name : str, optional
+ Member of `tqdm_class.get_lock()` to use [default: mp_lock].
"""
from concurrent.futures import ProcessPoolExecutor
if iterables and "chunksize" not in tqdm_kwargs:
@@ -103,4 +124,7 @@ def process_map(fn, *iterables, **tqdm_kwargs):
" This may seriously degrade multiprocess performance."
" Set `chunksize=1` or more." % longest_iterable_len,
TqdmWarning, stacklevel=2)
+ if "lock_name" not in tqdm_kwargs:
+ tqdm_kwargs = tqdm_kwargs.copy()
+ tqdm_kwargs["lock_name"] = "mp_lock"
return _executor_map(ProcessPoolExecutor, fn, *iterables, **tqdm_kwargs)
diff --git a/libs/tqdm/contrib/discord.py b/libs/tqdm/contrib/discord.py
new file mode 100644
index 000000000..713a2f822
--- /dev/null
+++ b/libs/tqdm/contrib/discord.py
@@ -0,0 +1,121 @@
+"""
+Sends updates to a Discord bot.
+
+Usage:
+>>> from tqdm.contrib.discord import tqdm, trange
+>>> for i in tqdm(iterable, token='{token}', channel_id='{channel_id}'):
+... ...
+
+![screenshot](https://img.tqdm.ml/screenshot-discord.png)
+"""
+from __future__ import absolute_import
+
+import logging
+from os import getenv
+
+try:
+ from disco.client import Client, ClientConfig
+except ImportError:
+ raise ImportError("Please `pip install disco-py`")
+
+from ..auto import tqdm as tqdm_auto
+from ..utils import _range
+from .utils_worker import MonoWorker
+
+__author__ = {"github.com/": ["casperdcl"]}
+__all__ = ['DiscordIO', 'tqdm_discord', 'tdrange', 'tqdm', 'trange']
+
+
+class DiscordIO(MonoWorker):
+ """Non-blocking file-like IO using a Discord Bot."""
+ def __init__(self, token, channel_id):
+ """Creates a new message in the given `channel_id`."""
+ super(DiscordIO, self).__init__()
+ config = ClientConfig()
+ config.token = token
+ client = Client(config)
+ self.text = self.__class__.__name__
+ try:
+ self.message = client.api.channels_messages_create(channel_id, self.text)
+ except Exception as e:
+ tqdm_auto.write(str(e))
+
+ def write(self, s):
+ """Replaces internal `message`'s text with `s`."""
+ if not s:
+ s = "..."
+ s = s.replace('\r', '').strip()
+ if s == self.text:
+ return # skip duplicate message
+ self.text = s
+ try:
+ future = self.submit(self.message.edit, '`' + s + '`')
+ except Exception as e:
+ tqdm_auto.write(str(e))
+ else:
+ return future
+
+
+class tqdm_discord(tqdm_auto):
+ """
+ Standard `tqdm.auto.tqdm` but also sends updates to a Discord Bot.
+ May take a few seconds to create (`__init__`).
+
+ - create a discord bot (not public, no requirement of OAuth2 code
+ grant, only send message permissions) & invite it to a channel:
+ <https://discordpy.readthedocs.io/en/latest/discord.html>
+ - copy the bot `{token}` & `{channel_id}` and paste below
+
+ >>> from tqdm.contrib.discord import tqdm, trange
+ >>> for i in tqdm(iterable, token='{token}', channel_id='{channel_id}'):
+ ... ...
+ """
+ def __init__(self, *args, **kwargs):
+ """
+ Parameters
+ ----------
+ token : str, required. Discord token
+ [default: ${TQDM_DISCORD_TOKEN}].
+ channel_id : int, required. Discord channel ID
+ [default: ${TQDM_DISCORD_CHANNEL_ID}].
+ mininterval : float, optional.
+ Minimum of [default: 1.5] to avoid rate limit.
+
+ See `tqdm.auto.tqdm.__init__` for other parameters.
+ """
+ if not kwargs.get('disable'):
+ kwargs = kwargs.copy()
+ logging.getLogger("HTTPClient").setLevel(logging.WARNING)
+ self.dio = DiscordIO(
+ kwargs.pop('token', getenv("TQDM_DISCORD_TOKEN")),
+ kwargs.pop('channel_id', getenv("TQDM_DISCORD_CHANNEL_ID")))
+ kwargs['mininterval'] = max(1.5, kwargs.get('mininterval', 1.5))
+ super(tqdm_discord, self).__init__(*args, **kwargs)
+
+ def display(self, **kwargs):
+ super(tqdm_discord, self).display(**kwargs)
+ fmt = self.format_dict
+ if fmt.get('bar_format', None):
+ fmt['bar_format'] = fmt['bar_format'].replace(
+ '<bar/>', '{bar:10u}').replace('{bar}', '{bar:10u}')
+ else:
+ fmt['bar_format'] = '{l_bar}{bar:10u}{r_bar}'
+ self.dio.write(self.format_meter(**fmt))
+
+ def clear(self, *args, **kwargs):
+ super(tqdm_discord, self).clear(*args, **kwargs)
+ if not self.disable:
+ self.dio.write("")
+
+
+def tdrange(*args, **kwargs):
+ """
+ A shortcut for `tqdm.contrib.discord.tqdm(xrange(*args), **kwargs)`.
+ On Python3+, `range` is used instead of `xrange`.
+ """
+ return tqdm_discord(_range(*args), **kwargs)
+
+
+# Aliases
+tqdm = tqdm_discord
+trange = tdrange
diff --git a/libs/tqdm/contrib/itertools.py b/libs/tqdm/contrib/itertools.py
index 0f2a2a42b..9cce75e8f 100644
--- a/libs/tqdm/contrib/itertools.py
+++ b/libs/tqdm/contrib/itertools.py
@@ -2,9 +2,11 @@
Thin wrappers around `itertools`.
"""
from __future__ import absolute_import
-from tqdm.auto import tqdm as tqdm_auto
-from copy import deepcopy
+
import itertools
+
+from ..auto import tqdm as tqdm_auto
+
__author__ = {"github.com/": ["casperdcl"]}
__all__ = ['product']
@@ -17,7 +19,7 @@ def product(*iterables, **tqdm_kwargs):
----------
tqdm_class : [default: tqdm.auto.tqdm].
"""
- kwargs = deepcopy(tqdm_kwargs)
+ kwargs = tqdm_kwargs.copy()
tqdm_class = kwargs.pop("tqdm_class", tqdm_auto)
try:
lens = list(map(len, iterables))
diff --git a/libs/tqdm/contrib/logging.py b/libs/tqdm/contrib/logging.py
new file mode 100644
index 000000000..cd9925ec1
--- /dev/null
+++ b/libs/tqdm/contrib/logging.py
@@ -0,0 +1,128 @@
+"""
+Helper functionality for interoperability with stdlib `logging`.
+"""
+from __future__ import absolute_import
+
+import logging
+import sys
+from contextlib import contextmanager
+
+try:
+ from typing import Iterator, List, Optional, Type # pylint: disable=unused-import
+except ImportError:
+ pass
+
+from ..std import tqdm as std_tqdm
+
+
+class _TqdmLoggingHandler(logging.StreamHandler):
+ def __init__(
+ self,
+ tqdm_class=std_tqdm # type: Type[std_tqdm]
+ ):
+ super(_TqdmLoggingHandler, self).__init__()
+ self.tqdm_class = tqdm_class
+
+ def emit(self, record):
+ try:
+ msg = self.format(record)
+ self.tqdm_class.write(msg, file=self.stream)
+ self.flush()
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except: # noqa pylint: disable=bare-except
+ self.handleError(record)
+
+
+def _is_console_logging_handler(handler):
+ return (isinstance(handler, logging.StreamHandler)
+ and handler.stream in {sys.stdout, sys.stderr})
+
+
+def _get_first_found_console_logging_handler(handlers):
+ for handler in handlers:
+ if _is_console_logging_handler(handler):
+ return handler
+
+
+@contextmanager
+def logging_redirect_tqdm(
+ loggers=None, # type: Optional[List[logging.Logger]],
+ tqdm_class=std_tqdm # type: Type[std_tqdm]
+):
+ # type: (...) -> Iterator[None]
+ """
+ Context manager redirecting console logging to `tqdm.write()`, leaving
+ other logging handlers (e.g. log files) unaffected.
+
+ Parameters
+ ----------
+ loggers : list, optional
+ Which handlers to redirect (default: [logging.root]).
+ tqdm_class : optional
+
+ Example
+ -------
+ ```python
+ import logging
+ from tqdm import trange
+ from tqdm.contrib.logging import logging_redirect_tqdm
+
+ LOG = logging.getLogger(__name__)
+
+ if __name__ == '__main__':
+ logging.basicConfig(level=logging.INFO)
+ with logging_redirect_tqdm():
+ for i in trange(9):
+ if i == 4:
+ LOG.info("console logging redirected to `tqdm.write()`")
+ # logging restored
+ ```
+ """
+ if loggers is None:
+ loggers = [logging.root]
+ original_handlers_list = [logger.handlers for logger in loggers]
+ try:
+ for logger in loggers:
+ tqdm_handler = _TqdmLoggingHandler(tqdm_class)
+ orig_handler = _get_first_found_console_logging_handler(logger.handlers)
+ if orig_handler is not None:
+ tqdm_handler.setFormatter(orig_handler.formatter)
+ tqdm_handler.stream = orig_handler.stream
+ logger.handlers = [
+ handler for handler in logger.handlers
+ if not _is_console_logging_handler(handler)] + [tqdm_handler]
+ yield
+ finally:
+ for logger, original_handlers in zip(loggers, original_handlers_list):
+ logger.handlers = original_handlers
+
+
+@contextmanager
+def tqdm_logging_redirect(
+ *args,
+ # loggers=None, # type: Optional[List[logging.Logger]]
+ # tqdm=None, # type: Optional[Type[tqdm.tqdm]]
+ **kwargs
+):
+ # type: (...) -> Iterator[None]
+ """
+ Convenience shortcut for:
+ ```python
+ with tqdm_class(*args, **tqdm_kwargs) as pbar:
+ with logging_redirect_tqdm(loggers=loggers, tqdm_class=tqdm_class):
+ yield pbar
+ ```
+
+ Parameters
+ ----------
+ tqdm_class : optional, (default: tqdm.std.tqdm).
+ loggers : optional, list.
+ **tqdm_kwargs : passed to `tqdm_class`.
+ """
+ tqdm_kwargs = kwargs.copy()
+ loggers = tqdm_kwargs.pop('loggers', None)
+ tqdm_class = tqdm_kwargs.pop('tqdm_class', std_tqdm)
+ with tqdm_class(*args, **tqdm_kwargs) as pbar:
+ with logging_redirect_tqdm(loggers=loggers, tqdm_class=tqdm_class):
+ yield pbar
diff --git a/libs/tqdm/contrib/telegram.py b/libs/tqdm/contrib/telegram.py
index 5654dc99c..99cbe8c88 100644
--- a/libs/tqdm/contrib/telegram.py
+++ b/libs/tqdm/contrib/telegram.py
@@ -1,126 +1,149 @@
"""
Sends updates to a Telegram bot.
+
+Usage:
+>>> from tqdm.contrib.telegram import tqdm, trange
+>>> for i in trange(10, token='{token}', chat_id='{chat_id}'):
+... ...
+
+![screenshot](https://img.tqdm.ml/screenshot-telegram.gif)
"""
from __future__ import absolute_import
-from concurrent.futures import ThreadPoolExecutor
+from os import getenv
+from warnings import warn
+
from requests import Session
-from tqdm.auto import tqdm as tqdm_auto
-from tqdm.utils import _range
+from ..auto import tqdm as tqdm_auto
+from ..std import TqdmWarning
+from ..utils import _range
+from .utils_worker import MonoWorker
+
__author__ = {"github.com/": ["casperdcl"]}
__all__ = ['TelegramIO', 'tqdm_telegram', 'ttgrange', 'tqdm', 'trange']
-class TelegramIO():
- """Non-blocking file-like IO to a Telegram Bot."""
+class TelegramIO(MonoWorker):
+ """Non-blocking file-like IO using a Telegram Bot."""
API = 'https://api.telegram.org/bot'
def __init__(self, token, chat_id):
"""Creates a new message in the given `chat_id`."""
+ super(TelegramIO, self).__init__()
self.token = token
self.chat_id = chat_id
- self.session = session = Session()
+ self.session = Session()
self.text = self.__class__.__name__
- self.pool = ThreadPoolExecutor()
- self.futures = []
+ self.message_id
+
+ @property
+ def message_id(self):
+ if hasattr(self, '_message_id'):
+ return self._message_id
try:
- res = session.post(
+ res = self.session.post(
self.API + '%s/sendMessage' % self.token,
- data=dict(text='`' + self.text + '`', chat_id=self.chat_id,
- parse_mode='MarkdownV2'))
+ data={'text': '`' + self.text + '`', 'chat_id': self.chat_id,
+ 'parse_mode': 'MarkdownV2'}).json()
except Exception as e:
tqdm_auto.write(str(e))
else:
- self.message_id = res.json()['result']['message_id']
+ if res.get('error_code') == 429:
+ warn("Creation rate limit: try increasing `mininterval`.",
+ TqdmWarning, stacklevel=2)
+ else:
+ self._message_id = res['result']['message_id']
+ return self._message_id
def write(self, s):
"""Replaces internal `message_id`'s text with `s`."""
if not s:
- return
- s = s.strip().replace('\r', '')
+ s = "..."
+ s = s.replace('\r', '').strip()
if s == self.text:
return # avoid duplicate message Bot error
+ message_id = self.message_id
+ if message_id is None:
+ return
self.text = s
try:
- f = self.pool.submit(
- self.session.post,
- self.API + '%s/editMessageText' % self.token,
- data=dict(
- text='`' + s + '`', chat_id=self.chat_id,
- message_id=self.message_id, parse_mode='MarkdownV2'))
+ future = self.submit(
+ self.session.post, self.API + '%s/editMessageText' % self.token,
+ data={'text': '`' + s + '`', 'chat_id': self.chat_id,
+ 'message_id': message_id, 'parse_mode': 'MarkdownV2'})
except Exception as e:
tqdm_auto.write(str(e))
else:
- self.futures.append(f)
- return f
+ return future
- def flush(self):
- """Ensure the last `write` has been processed."""
- [f.cancel() for f in self.futures[-2::-1]]
+ def delete(self):
+ """Deletes internal `message_id`."""
try:
- return self.futures[-1].result()
- except IndexError:
- pass
- finally:
- self.futures = []
-
- def __del__(self):
- self.flush()
+ future = self.submit(
+ self.session.post, self.API + '%s/deleteMessage' % self.token,
+ data={'chat_id': self.chat_id, 'message_id': self.message_id})
+ except Exception as e:
+ tqdm_auto.write(str(e))
+ else:
+ return future
class tqdm_telegram(tqdm_auto):
"""
- Standard `tqdm.auto.tqdm` but also sends updates to a Telegram bot.
- May take a few seconds to create (`__init__`) and clear (`__del__`).
+ Standard `tqdm.auto.tqdm` but also sends updates to a Telegram Bot.
+ May take a few seconds to create (`__init__`).
+
+ - create a bot <https://core.telegram.org/bots#6-botfather>
+ - copy its `{token}`
+ - add the bot to a chat and send it a message such as `/start`
+ - go to <https://api.telegram.org/bot`{token}`/getUpdates> to find out
+ the `{chat_id}`
+ - paste the `{token}` & `{chat_id}` below
>>> from tqdm.contrib.telegram import tqdm, trange
- >>> for i in tqdm(
- ... iterable,
- ... token='1234567890:THIS1SSOMETOKEN0BTAINeDfrOmTELEGrAM',
- ... chat_id='0246813579'):
+ >>> for i in tqdm(iterable, token='{token}', chat_id='{chat_id}'):
+ ... ...
"""
def __init__(self, *args, **kwargs):
"""
Parameters
----------
- token : str, required. Telegram token.
- chat_id : str, required. Telegram chat ID.
+ token : str, required. Telegram token
+ [default: ${TQDM_TELEGRAM_TOKEN}].
+ chat_id : str, required. Telegram chat ID
+ [default: ${TQDM_TELEGRAM_CHAT_ID}].
See `tqdm.auto.tqdm.__init__` for other parameters.
"""
- self.tgio = TelegramIO(kwargs.pop('token'), kwargs.pop('chat_id'))
+ if not kwargs.get('disable'):
+ kwargs = kwargs.copy()
+ self.tgio = TelegramIO(
+ kwargs.pop('token', getenv('TQDM_TELEGRAM_TOKEN')),
+ kwargs.pop('chat_id', getenv('TQDM_TELEGRAM_CHAT_ID')))
super(tqdm_telegram, self).__init__(*args, **kwargs)
def display(self, **kwargs):
super(tqdm_telegram, self).display(**kwargs)
fmt = self.format_dict
- if 'bar_format' in fmt and fmt['bar_format']:
- fmt['bar_format'] = fmt['bar_format'].replace('<bar/>', '{bar}')
+ if fmt.get('bar_format', None):
+ fmt['bar_format'] = fmt['bar_format'].replace(
+ '<bar/>', '{bar:10u}').replace('{bar}', '{bar:10u}')
else:
- fmt['bar_format'] = '{l_bar}{bar}{r_bar}'
- fmt['bar_format'] = fmt['bar_format'].replace('{bar}', '{bar:10u}')
+ fmt['bar_format'] = '{l_bar}{bar:10u}{r_bar}'
self.tgio.write(self.format_meter(**fmt))
- def __new__(cls, *args, **kwargs):
- """
- Workaround for mixed-class same-stream nested progressbars.
- See [#509](https://github.com/tqdm/tqdm/issues/509)
- """
- with cls.get_lock():
- try:
- cls._instances = tqdm_auto._instances
- except AttributeError:
- pass
- instance = super(tqdm_telegram, cls).__new__(cls, *args, **kwargs)
- with cls.get_lock():
- try:
- # `tqdm_auto` may have been changed so update
- cls._instances.update(tqdm_auto._instances)
- except AttributeError:
- pass
- tqdm_auto._instances = cls._instances
- return instance
+ def clear(self, *args, **kwargs):
+ super(tqdm_telegram, self).clear(*args, **kwargs)
+ if not self.disable:
+ self.tgio.write("")
+
+ def close(self):
+ if self.disable:
+ return
+ super(tqdm_telegram, self).close()
+ if not (self.leave or (self.leave is None and self.pos == 0)):
+ self.tgio.delete()
def ttgrange(*args, **kwargs):
diff --git a/libs/tqdm/contrib/utils_worker.py b/libs/tqdm/contrib/utils_worker.py
new file mode 100644
index 000000000..17adda667
--- /dev/null
+++ b/libs/tqdm/contrib/utils_worker.py
@@ -0,0 +1,40 @@
+"""
+IO/concurrency helpers for `tqdm.contrib`.
+"""
+from __future__ import absolute_import
+
+from collections import deque
+from concurrent.futures import ThreadPoolExecutor
+
+from ..auto import tqdm as tqdm_auto
+
+__author__ = {"github.com/": ["casperdcl"]}
+__all__ = ['MonoWorker']
+
+
+class MonoWorker(object):
+ """
+ Supports one running task and one waiting task.
+ The waiting task is the most recent submitted (others are discarded).
+ """
+ def __init__(self):
+ self.pool = ThreadPoolExecutor(max_workers=1)
+ self.futures = deque([], 2)
+
+ def submit(self, func, *args, **kwargs):
+ """`func(*args, **kwargs)` may replace currently waiting task."""
+ futures = self.futures
+ if len(futures) == futures.maxlen:
+ running = futures.popleft()
+ if not running.done():
+ if len(futures): # clear waiting
+ waiting = futures.pop()
+ waiting.cancel()
+ futures.appendleft(running) # re-insert running
+ try:
+ waiting = self.pool.submit(func, *args, **kwargs)
+ except Exception as e:
+ tqdm_auto.write(str(e))
+ else:
+ futures.append(waiting)
+ return waiting
diff --git a/libs/tqdm/dask.py b/libs/tqdm/dask.py
new file mode 100644
index 000000000..6fc7504c7
--- /dev/null
+++ b/libs/tqdm/dask.py
@@ -0,0 +1,46 @@
+from __future__ import absolute_import
+
+from functools import partial
+
+from dask.callbacks import Callback
+
+from .auto import tqdm as tqdm_auto
+
+__author__ = {"github.com/": ["casperdcl"]}
+__all__ = ['TqdmCallback']
+
+
+class TqdmCallback(Callback):
+ """Dask callback for task progress."""
+ def __init__(self, start=None, pretask=None, tqdm_class=tqdm_auto,
+ **tqdm_kwargs):
+ """
+ Parameters
+ ----------
+ tqdm_class : optional
+ `tqdm` class to use for bars [default: `tqdm.auto.tqdm`].
+ tqdm_kwargs : optional
+ Any other arguments used for all bars.
+ """
+ super(TqdmCallback, self).__init__(start=start, pretask=pretask)
+ if tqdm_kwargs:
+ tqdm_class = partial(tqdm_class, **tqdm_kwargs)
+ self.tqdm_class = tqdm_class
+
+ def _start_state(self, _, state):
+ self.pbar = self.tqdm_class(total=sum(
+ len(state[k]) for k in ['ready', 'waiting', 'running', 'finished']))
+
+ def _posttask(self, *_, **__):
+ self.pbar.update()
+
+ def _finish(self, *_, **__):
+ self.pbar.close()
+
+ def display(self):
+ """Displays in the current cell in Notebooks."""
+ container = getattr(self.bar, 'container', None)
+ if container is None:
+ return
+ from .notebook import display
+ display(container)
diff --git a/libs/tqdm/gui.py b/libs/tqdm/gui.py
index 35f5c5e55..4612701d2 100644
--- a/libs/tqdm/gui.py
+++ b/libs/tqdm/gui.py
@@ -1,50 +1,47 @@
"""
-GUI progressbar decorator for iterators.
-Includes a default (x)range iterator printing to stderr.
+Matplotlib GUI progressbar decorator for iterators.
Usage:
- >>> from tqdm.gui import trange[, tqdm]
- >>> for i in trange(10): #same as: for i in tqdm(xrange(10))
- ... ...
+>>> from tqdm.gui import trange, tqdm
+>>> for i in trange(10):
+... ...
"""
# future division is important to divide integers and get as
# a result precise floating numbers (instead of truncated int)
-from __future__ import division, absolute_import
-# import compatibility functions and utilities
-from .utils import _range
-# to inherit from the tqdm class
-from .std import tqdm as std_tqdm
-from .std import TqdmExperimentalWarning
+from __future__ import absolute_import, division
+
+import re
from warnings import warn
+# to inherit from the tqdm class
+from .std import TqdmExperimentalWarning
+from .std import tqdm as std_tqdm
+# import compatibility functions and utilities
+from .utils import _range
__author__ = {"github.com/": ["casperdcl", "lrq3000"]}
__all__ = ['tqdm_gui', 'tgrange', 'tqdm', 'trange']
class tqdm_gui(std_tqdm): # pragma: no cover
- """
- Experimental GUI version of tqdm!
- """
-
+ """Experimental Matplotlib GUI version of tqdm!"""
# TODO: @classmethod: write() on GUI?
-
def __init__(self, *args, **kwargs):
+ from collections import deque
+
import matplotlib as mpl
import matplotlib.pyplot as plt
- from collections import deque
+ kwargs = kwargs.copy()
kwargs['gui'] = True
-
+ colour = kwargs.pop('colour', 'g')
super(tqdm_gui, self).__init__(*args, **kwargs)
- # Initialize the GUI display
- if self.disable or not kwargs['gui']:
+ if self.disable:
return
- warn('GUI is experimental/alpha', TqdmExperimentalWarning, stacklevel=2)
+ warn("GUI is experimental/alpha", TqdmExperimentalWarning, stacklevel=2)
self.mpl = mpl
self.plt = plt
- self.sp = None
# Remember if external environment uses toolbars
self.toolbar = self.mpl.rcParams['toolbar']
@@ -53,7 +50,7 @@ class tqdm_gui(std_tqdm): # pragma: no cover
self.mininterval = max(self.mininterval, 0.5)
self.fig, ax = plt.subplots(figsize=(9, 2.2))
# self.fig.subplots_adjust(bottom=0.2)
- total = len(self)
+ total = self.__len__() # avoids TypeError on None #971
if total is not None:
self.xdata = []
self.ydata = []
@@ -67,24 +64,22 @@ class tqdm_gui(std_tqdm): # pragma: no cover
ax.set_ylim(0, 0.001)
if total is not None:
ax.set_xlim(0, 100)
- ax.set_xlabel('percent')
- self.fig.legend((self.line1, self.line2), ('cur', 'est'),
+ ax.set_xlabel("percent")
+ self.fig.legend((self.line1, self.line2), ("cur", "est"),
loc='center right')
# progressbar
- self.hspan = plt.axhspan(0, 0.001,
- xmin=0, xmax=0, color='g')
+ self.hspan = plt.axhspan(0, 0.001, xmin=0, xmax=0, color=colour)
else:
# ax.set_xlim(-60, 0)
ax.set_xlim(0, 60)
ax.invert_xaxis()
- ax.set_xlabel('seconds')
- ax.legend(('cur', 'est'), loc='lower left')
+ ax.set_xlabel("seconds")
+ ax.legend(("cur", "est"), loc='lower left')
ax.grid()
# ax.set_xlabel('seconds')
- ax.set_ylabel((self.unit if self.unit else 'it') + '/s')
+ ax.set_ylabel((self.unit if self.unit else "it") + "/s")
if self.unit_scale:
- plt.ticklabel_format(style='sci', axis='y',
- scilimits=(0, 0))
+ plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
ax.yaxis.get_offset_text().set_x(-0.15)
# Remember if external environment is interactive
@@ -92,138 +87,7 @@ class tqdm_gui(std_tqdm): # pragma: no cover
plt.ion()
self.ax = ax
- def __iter__(self):
- # TODO: somehow allow the following:
- # if not self.gui:
- # return super(tqdm_gui, self).__iter__()
- iterable = self.iterable
- if self.disable:
- for obj in iterable:
- yield obj
- return
-
- # ncols = self.ncols
- mininterval = self.mininterval
- maxinterval = self.maxinterval
- miniters = self.miniters
- dynamic_miniters = self.dynamic_miniters
- last_print_t = self.last_print_t
- last_print_n = self.last_print_n
- n = self.n
- # dynamic_ncols = self.dynamic_ncols
- smoothing = self.smoothing
- avg_time = self.avg_time
- time = self._time
-
- for obj in iterable:
- yield obj
- # Update and possibly print the progressbar.
- # Note: does not call self.update(1) for speed optimisation.
- n += 1
- # check counter first to avoid calls to time()
- if n - last_print_n >= self.miniters:
- miniters = self.miniters # watch monitoring thread changes
- delta_t = time() - last_print_t
- if delta_t >= mininterval:
- cur_t = time()
- delta_it = n - last_print_n
- # EMA (not just overall average)
- if smoothing and delta_t and delta_it:
- rate = delta_t / delta_it
- avg_time = self.ema(rate, avg_time, smoothing)
- self.avg_time = avg_time
-
- self.n = n
- self.display()
-
- # If no `miniters` was specified, adjust automatically
- # to the max iteration rate seen so far between 2 prints
- if dynamic_miniters:
- if maxinterval and delta_t >= maxinterval:
- # Adjust miniters to time interval by rule of 3
- if mininterval:
- # Set miniters to correspond to mininterval
- miniters = delta_it * mininterval / delta_t
- else:
- # Set miniters to correspond to maxinterval
- miniters = delta_it * maxinterval / delta_t
- elif smoothing:
- # EMA-weight miniters to converge
- # towards the timeframe of mininterval
- 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)
-
- # Store old values for next call
- self.n = self.last_print_n = last_print_n = n
- self.last_print_t = last_print_t = cur_t
- self.miniters = miniters
-
- # Closing the progress bar.
- # Update some internal variables for close().
- self.last_print_n = last_print_n
- self.n = n
- self.miniters = miniters
- self.close()
-
- def update(self, n=1):
- # if not self.gui:
- # return super(tqdm_gui, self).close()
- if self.disable:
- return
-
- if n < 0:
- self.last_print_n += n # for auto-refresh logic to work
- self.n += n
-
- # check counter first to reduce calls to time()
- if self.n - self.last_print_n >= self.miniters:
- delta_t = self._time() - self.last_print_t
- if delta_t >= self.mininterval:
- cur_t = self._time()
- delta_it = self.n - self.last_print_n # >= n
- # elapsed = cur_t - self.start_t
- # EMA (not just overall average)
- 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)
-
- self.display()
-
- # If no `miniters` was specified, adjust automatically to the
- # maximum iteration rate seen so far between two prints.
- # e.g.: After running `tqdm.update(5)`, subsequent
- # calls to `tqdm.update()` will only cause an update after
- # at least 5 more iterations.
- if self.dynamic_miniters:
- if self.maxinterval and delta_t >= self.maxinterval:
- if self.mininterval:
- self.miniters = delta_it * self.mininterval \
- / delta_t
- else:
- self.miniters = delta_it * self.maxinterval \
- / delta_t
- elif self.smoothing:
- self.miniters = self.smoothing * delta_it * \
- (self.mininterval / delta_t
- if self.mininterval and delta_t
- else 1) + \
- (1 - self.smoothing) * self.miniters
- else:
- self.miniters = max(self.miniters, delta_it)
-
- # Store old values for next call
- self.last_print_n = self.n
- self.last_print_t = cur_t
-
def close(self):
- # if not self.gui:
- # return super(tqdm_gui, self).close()
if self.disable:
return
@@ -237,10 +101,15 @@ class tqdm_gui(std_tqdm): # pragma: no cover
# Return to non-interactive mode
if not self.wasion:
self.plt.ioff()
- if not self.leave:
+ if self.leave:
+ self.display()
+ else:
self.plt.close(self.fig)
- def display(self):
+ def clear(self, *_, **__):
+ pass
+
+ def display(self, *_, **__):
n = self.n
cur_t = self._time()
elapsed = cur_t - self.start_t
@@ -284,8 +153,7 @@ class tqdm_gui(std_tqdm): # pragma: no cover
try:
poly_lims = self.hspan.get_xy()
except AttributeError:
- self.hspan = self.plt.axhspan(
- 0, 0.001, xmin=0, xmax=0, color='g')
+ self.hspan = self.plt.axhspan(0, 0.001, xmin=0, xmax=0, color='g')
poly_lims = self.hspan.get_xy()
poly_lims[0, 1] = ymin
poly_lims[1, 1] = ymax
@@ -299,12 +167,14 @@ class tqdm_gui(std_tqdm): # pragma: no cover
line1.set_data(t_ago, ydata)
line2.set_data(t_ago, zdata)
- ax.set_title(self.format_meter(
- n, total, elapsed, 0,
- self.desc, self.ascii, self.unit, self.unit_scale,
- 1 / self.avg_time if self.avg_time else None, self.bar_format,
- self.postfix, self.unit_divisor),
- fontname="DejaVu Sans Mono", fontsize=11)
+ d = self.format_dict
+ # remove {bar}
+ d['bar_format'] = (d['bar_format'] or "{l_bar}<bar/>{r_bar}").replace(
+ "{bar}", "<bar/>")
+ msg = self.format_meter(**d)
+ if '<bar/>' in msg:
+ msg = "".join(re.split(r'\|?<bar/>\|?', msg, 1))
+ ax.set_title(msg, fontname="DejaVu Sans Mono", fontsize=11)
self.plt.pause(1e-9)
diff --git a/libs/tqdm/keras.py b/libs/tqdm/keras.py
index 27623c099..523e62e94 100644
--- a/libs/tqdm/keras.py
+++ b/libs/tqdm/keras.py
@@ -1,9 +1,13 @@
from __future__ import absolute_import, division
+
+from copy import copy
+from functools import partial
+
from .auto import tqdm as tqdm_auto
-from copy import deepcopy
+
try:
import keras
-except ImportError as e:
+except (ImportError, AttributeError) as e:
try:
from tensorflow import keras
except ImportError:
@@ -13,14 +17,14 @@ __all__ = ['TqdmCallback']
class TqdmCallback(keras.callbacks.Callback):
- """`keras` callback for epoch and batch progress"""
+ """Keras callback for epoch and batch progress."""
@staticmethod
def bar2callback(bar, pop=None, delta=(lambda logs: 1)):
def callback(_, logs=None):
n = delta(logs)
if logs:
if pop:
- logs = deepcopy(logs)
+ logs = copy(logs)
[logs.pop(i, 0) for i in pop]
bar.set_postfix(logs, refresh=False)
bar.update(n)
@@ -28,7 +32,7 @@ class TqdmCallback(keras.callbacks.Callback):
return callback
def __init__(self, epochs=None, data_size=None, batch_size=None, verbose=1,
- tqdm_class=tqdm_auto):
+ tqdm_class=tqdm_auto, **tqdm_kwargs):
"""
Parameters
----------
@@ -41,9 +45,13 @@ class TqdmCallback(keras.callbacks.Callback):
0: epoch, 1: batch (transient), 2: batch. [default: 1].
Will be set to `0` unless both `data_size` and `batch_size`
are given.
- tqdm_class : optional
+ tqdm_class : optional
`tqdm` class to use for bars [default: `tqdm.auto.tqdm`].
+ tqdm_kwargs : optional
+ Any other arguments used for all bars.
"""
+ if tqdm_kwargs:
+ tqdm_class = partial(tqdm_class, **tqdm_kwargs)
self.tqdm_class = tqdm_class
self.epoch_bar = tqdm_class(total=epochs, unit='epoch')
self.on_epoch_end = self.bar2callback(self.epoch_bar)
@@ -53,20 +61,21 @@ class TqdmCallback(keras.callbacks.Callback):
self.batches = batches = None
self.verbose = verbose
if verbose == 1:
- self.batch_bar = tqdm_class(total=batches, unit='batch',
- leave=False)
+ self.batch_bar = tqdm_class(total=batches, unit='batch', leave=False)
self.on_batch_end = self.bar2callback(
- self.batch_bar,
- pop=['batch', 'size'],
+ self.batch_bar, pop=['batch', 'size'],
delta=lambda logs: logs.get('size', 1))
def on_train_begin(self, *_, **__):
params = self.params.get
auto_total = params('epochs', params('nb_epoch', None))
- if auto_total is not None:
+ if auto_total is not None and auto_total != self.epoch_bar.total:
self.epoch_bar.reset(total=auto_total)
- def on_epoch_begin(self, *_, **__):
+ def on_epoch_begin(self, epoch, *_, **__):
+ if self.epoch_bar.n < epoch:
+ ebar = self.epoch_bar
+ ebar.n = ebar.last_print_n = ebar.initial = epoch
if self.verbose:
params = self.params.get
total = params('samples', params(
@@ -78,8 +87,7 @@ class TqdmCallback(keras.callbacks.Callback):
total=total, unit='batch', leave=True,
unit_scale=1 / (params('batch_size', 1) or 1))
self.on_batch_end = self.bar2callback(
- self.batch_bar,
- pop=['batch', 'size'],
+ self.batch_bar, pop=['batch', 'size'],
delta=lambda logs: logs.get('size', 1))
elif self.verbose == 1:
self.batch_bar.unit_scale = 1 / (params('batch_size', 1) or 1)
@@ -92,6 +100,17 @@ class TqdmCallback(keras.callbacks.Callback):
self.batch_bar.close()
self.epoch_bar.close()
+ def display(self):
+ """Displays in the current cell in Notebooks."""
+ container = getattr(self.epoch_bar, 'container', None)
+ if container is None:
+ return
+ from .notebook import display
+ display(container)
+ batch_bar = getattr(self, 'batch_bar', None)
+ if batch_bar is not None:
+ display(batch_bar.container)
+
@staticmethod
def _implements_train_batch_hooks():
return True
diff --git a/libs/tqdm/notebook.py b/libs/tqdm/notebook.py
index 570510370..1f488d25f 100644
--- a/libs/tqdm/notebook.py
+++ b/libs/tqdm/notebook.py
@@ -1,61 +1,62 @@
"""
IPython/Jupyter Notebook progressbar decorator for iterators.
-Includes a default (x)range iterator printing to stderr.
+Includes a default `range` iterator printing to `stderr`.
Usage:
- >>> from tqdm.notebook import trange[, tqdm]
- >>> for i in trange(10): #same as: for i in tqdm(xrange(10))
- ... ...
+>>> from tqdm.notebook import trange, tqdm
+>>> for i in trange(10):
+... ...
"""
# future division is important to divide integers and get as
# a result precise floating numbers (instead of truncated int)
-from __future__ import division, absolute_import
+from __future__ import absolute_import, division
+
# import compatibility functions and utilities
+import re
import sys
-from .utils import _range
+from weakref import proxy
+
# to inherit from the tqdm class
from .std import tqdm as std_tqdm
-
+from .utils import _range
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
with warnings.catch_warnings():
warnings.filterwarnings(
- 'ignore',
- message=".*The `IPython.html` package has been deprecated.*")
+ 'ignore', message=".*The `IPython.html` package has been deprecated.*")
try:
- import IPython.html.widgets as ipywidgets
+ import IPython.html.widgets as ipywidgets # NOQA: F401
except ImportError:
pass
try: # IPython 4.x / 3.x
if IPY == 32:
+ from IPython.html.widgets import HTML
from IPython.html.widgets import FloatProgress as IProgress
- from IPython.html.widgets import HBox, HTML
+ from IPython.html.widgets import HBox
IPY = 3
else:
+ from ipywidgets import HTML
from ipywidgets import FloatProgress as IProgress
- from ipywidgets import HBox, HTML
+ from ipywidgets import HBox
except ImportError:
try: # IPython 2.x
- from IPython.html.widgets import FloatProgressWidget as IProgress
- from IPython.html.widgets import ContainerWidget as HBox
from IPython.html.widgets import HTML
+ from IPython.html.widgets import ContainerWidget as HBox
+ from IPython.html.widgets import FloatProgressWidget as IProgress
IPY = 2
except ImportError:
IPY = 0
+ IProgress = None
+ HBox = object
try:
from IPython.display import display # , clear_output
@@ -68,16 +69,35 @@ if True: # pragma: no cover
except ImportError: # Py2
from cgi import escape
-
__author__ = {"github.com/": ["lrq3000", "casperdcl", "alexanderkuk"]}
__all__ = ['tqdm_notebook', 'tnrange', 'tqdm', 'trange']
+class TqdmHBox(HBox):
+ """`ipywidgets.HBox` with a pretty representation"""
+ def _repr_json_(self, pretty=None):
+ pbar = getattr(self, 'pbar', None)
+ if pbar is None:
+ return {}
+ d = pbar.format_dict
+ if pretty is not None:
+ d["ascii"] = not pretty
+ return d
+
+ def __repr__(self, pretty=False):
+ pbar = getattr(self, 'pbar', None)
+ if pbar is None:
+ return super(TqdmHBox, self).__repr__()
+ return pbar.format_meter(**self._repr_json_(pretty))
+
+ def _repr_pretty_(self, pp, *_, **__):
+ pp.text(self.__repr__(True))
+
+
class tqdm_notebook(std_tqdm):
"""
Experimental IPython/Jupyter Notebook widget using tqdm!
"""
-
@staticmethod
def status_printer(_, total=None, desc=None, ncols=None):
"""
@@ -91,28 +111,25 @@ class tqdm_notebook(std_tqdm):
# fp = file
# Prepare IPython progress bar
- try:
- if total:
- pbar = IProgress(min=0, max=total)
- else: # No total? Show info style bar with no progress tqdm status
- pbar = IProgress(min=0, max=1)
- pbar.value = 1
- pbar.bar_style = 'info'
- except NameError:
- # #187 #451 #558
+ if IProgress is None: # #187 #451 #558 #872
raise ImportError(
- "FloatProgress not found. Please update jupyter and ipywidgets."
+ "IProgress not found. Please update jupyter and ipywidgets."
" See https://ipywidgets.readthedocs.io/en/stable"
"/user_install.html")
-
+ if total:
+ pbar = IProgress(min=0, max=total)
+ else: # No total? Show info style bar with no progress tqdm status
+ pbar = IProgress(min=0, max=1)
+ pbar.value = 1
+ pbar.bar_style = 'info'
+ 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 = TqdmHBox(children=[ltext, pbar, rtext])
# Prepare layout
if ncols is not None: # use default style of ipywidgets
# ncols could be 100, "100px", "100%"
@@ -126,13 +143,12 @@ class tqdm_notebook(std_tqdm):
container.layout.width = ncols
container.layout.display = 'inline-flex'
container.layout.flex_flow = 'row wrap'
- display(container)
return container
def display(self, msg=None, pos=None,
# additional signals
- close=False, bar_style=None):
+ close=False, bar_style=None, check_delay=True):
# Note: contrary to native tqdm, msg='' does NOT clear bar
# goal is to keep all infos if error happens so user knows
# at which iteration the loop failed.
@@ -141,38 +157,33 @@ class tqdm_notebook(std_tqdm):
# clear_output(wait=1)
if not msg and not close:
- msg = self.__repr__()
+ d = self.format_dict
+ # remove {bar}
+ d['bar_format'] = (d['bar_format'] or "{l_bar}<bar/>{r_bar}").replace(
+ "{bar}", "<bar/>")
+ msg = self.format_meter(**d)
- pbar, ptext = self.container.children
+ ltext, pbar, rtext = self.container.children
pbar.value = self.n
if msg:
# html escape special characters (like '&')
if '<bar/>' in msg:
- left, right = map(escape, msg.split('<bar/>', 1))
+ left, right = map(escape, re.split(r'\|?<bar/>\|?', msg, 1))
else:
left, right = '', escape(msg)
- # remove inesthetical pipes
- if left and left[-1] == '|':
- left = left[:-1]
- if right and right[0] == '|':
- 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:
# Hack-ish way to avoid the danger bar_style being overridden by
# success because the bar gets closed after the error...
- if not (pbar.bar_style == 'danger' and bar_style == 'success'):
+ if pbar.bar_style != 'danger' or bar_style != 'success':
pbar.bar_style = bar_style
# Special signal to close the bar
@@ -182,7 +193,30 @@ class tqdm_notebook(std_tqdm):
except AttributeError:
self.container.visible = False
+ if check_delay and self.delay > 0 and not self.displayed:
+ display(self.container)
+ self.displayed = True
+
+ @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):
+ """
+ Supports the usual `tqdm.tqdm` parameters as well as those listed below.
+
+ Parameters
+ ----------
+ display : Whether to call `display(self.container)` immediately
+ [default: True].
+ """
+ kwargs = kwargs.copy()
# Setup default output
file_kwarg = kwargs.get('file', sys.stderr)
if file_kwarg is sys.stderr or file_kwarg is None:
@@ -190,13 +224,13 @@ class tqdm_notebook(std_tqdm):
# Initialize parent class + avoid printing by using gui=True
kwargs['gui'] = True
- kwargs.setdefault('bar_format', '{l_bar}{bar}{r_bar}')
- kwargs['bar_format'] = kwargs['bar_format'].replace('{bar}', '<bar/>')
# convert disable = None to False
kwargs['disable'] = bool(kwargs.get('disable', False))
+ colour = kwargs.pop('colour', None)
+ display_here = kwargs.pop('display', True)
super(tqdm_notebook, self).__init__(*args, **kwargs)
if self.disable or not kwargs['gui']:
- self.sp = lambda *_, **__: None
+ self.disp = lambda *_, **__: None
return
# Get bar width
@@ -205,53 +239,59 @@ class tqdm_notebook(std_tqdm):
# Replace with IPython progress bar display (with correct total)
unit_scale = 1 if self.unit_scale is True else self.unit_scale or 1
total = self.total * unit_scale if self.total else self.total
- self.container = self.status_printer(
- self.fp, total, self.desc, self.ncols)
- self.sp = self.display
+ self.container = self.status_printer(self.fp, total, self.desc, self.ncols)
+ self.container.pbar = proxy(self)
+ self.displayed = False
+ if display_here and self.delay <= 0:
+ display(self.container)
+ self.displayed = True
+ self.disp = self.display
+ self.colour = colour
# Print initial bar state
if not self.disable:
- self.display()
+ self.display(check_delay=False)
- def __iter__(self, *args, **kwargs):
+ def __iter__(self):
try:
- for obj in super(tqdm_notebook, self).__iter__(*args, **kwargs):
+ for obj in super(tqdm_notebook, self).__iter__():
# return super(tqdm...) will not catch exception
yield obj
# NB: except ... [ as ...] breaks IPython async KeyboardInterrupt
except: # NOQA
- self.sp(bar_style='danger')
+ self.disp(bar_style='danger')
raise
# NB: don't `finally: close()`
# since this could be a shared bar which the user will `reset()`
- def update(self, *args, **kwargs):
+ def update(self, n=1):
try:
- super(tqdm_notebook, self).update(*args, **kwargs)
+ return super(tqdm_notebook, self).update(n=n)
# NB: except ... [ as ...] breaks IPython async KeyboardInterrupt
except: # NOQA
# cannot catch KeyboardInterrupt when using manual tqdm
# as the interrupt will most likely happen on another statement
- self.sp(bar_style='danger')
+ self.disp(bar_style='danger')
raise
# NB: don't `finally: close()`
# since this could be a shared bar which the user will `reset()`
- def close(self, *args, **kwargs):
- super(tqdm_notebook, self).close(*args, **kwargs)
+ def close(self):
+ if self.disable:
+ return
+ super(tqdm_notebook, self).close()
# Try to detect if there was an error or KeyboardInterrupt
# in manual mode: if n < total, things probably got wrong
if self.total and self.n < self.total:
- self.sp(bar_style='danger')
+ self.disp(bar_style='danger', check_delay=False)
else:
if self.leave:
- self.sp(bar_style='success')
+ self.disp(bar_style='success', check_delay=False)
else:
- self.sp(close=True)
+ self.disp(close=True, check_delay=False)
- def moveto(self, *args, **kwargs):
- # void -> avoid extraneous `\n` in IPython output cell
- return
+ def clear(self, *_, **__):
+ pass
def reset(self, total=None):
"""
@@ -263,9 +303,14 @@ class tqdm_notebook(std_tqdm):
----------
total : int or float, optional. Total to use for the new bar.
"""
+ if self.disable:
+ return super(tqdm_notebook, self).reset(total=total)
+ _, 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)
diff --git a/libs/tqdm/rich.py b/libs/tqdm/rich.py
new file mode 100644
index 000000000..cf8e71432
--- /dev/null
+++ b/libs/tqdm/rich.py
@@ -0,0 +1,152 @@
+"""
+`rich.progress` decorator for iterators.
+
+Usage:
+>>> from tqdm.rich import trange, tqdm
+>>> for i in trange(10):
+... ...
+"""
+from __future__ import absolute_import
+
+from warnings import warn
+
+from rich.progress import (
+ BarColumn, Progress, ProgressColumn, Text, TimeElapsedColumn, TimeRemainingColumn, filesize)
+
+from .std import TqdmExperimentalWarning
+from .std import tqdm as std_tqdm
+from .utils import _range
+
+__author__ = {"github.com/": ["casperdcl"]}
+__all__ = ['tqdm_rich', 'trrange', 'tqdm', 'trange']
+
+
+class FractionColumn(ProgressColumn):
+ """Renders completed/total, e.g. '0.5/2.3 G'."""
+ def __init__(self, unit_scale=False, unit_divisor=1000):
+ self.unit_scale = unit_scale
+ self.unit_divisor = unit_divisor
+ super().__init__()
+
+ def render(self, task):
+ """Calculate common unit for completed and total."""
+ completed = int(task.completed)
+ total = int(task.total)
+ if self.unit_scale:
+ unit, suffix = filesize.pick_unit_and_suffix(
+ total,
+ ["", "K", "M", "G", "T", "P", "E", "Z", "Y"],
+ self.unit_divisor,
+ )
+ else:
+ unit, suffix = filesize.pick_unit_and_suffix(total, [""], 1)
+ precision = 0 if unit == 1 else 1
+ return Text(
+ f"{completed/unit:,.{precision}f}/{total/unit:,.{precision}f} {suffix}",
+ style="progress.download")
+
+
+class RateColumn(ProgressColumn):
+ """Renders human readable transfer speed."""
+ def __init__(self, unit="", unit_scale=False, unit_divisor=1000):
+ self.unit = unit
+ self.unit_scale = unit_scale
+ self.unit_divisor = unit_divisor
+ super().__init__()
+
+ def render(self, task):
+ """Show data transfer speed."""
+ speed = task.speed
+ if speed is None:
+ return Text(f"? {self.unit}/s", style="progress.data.speed")
+ if self.unit_scale:
+ unit, suffix = filesize.pick_unit_and_suffix(
+ speed,
+ ["", "K", "M", "G", "T", "P", "E", "Z", "Y"],
+ self.unit_divisor,
+ )
+ else:
+ unit, suffix = filesize.pick_unit_and_suffix(speed, [""], 1)
+ precision = 0 if unit == 1 else 1
+ return Text(f"{speed/unit:,.{precision}f} {suffix}{self.unit}/s",
+ style="progress.data.speed")
+
+
+class tqdm_rich(std_tqdm): # pragma: no cover
+ """Experimental rich.progress GUI version of tqdm!"""
+ # TODO: @classmethod: write()?
+ def __init__(self, *args, **kwargs):
+ """
+ This class accepts the following parameters *in addition* to
+ the parameters accepted by `tqdm`.
+
+ Parameters
+ ----------
+ progress : tuple, optional
+ arguments for `rich.progress.Progress()`.
+ """
+ kwargs = kwargs.copy()
+ kwargs['gui'] = True
+ # convert disable = None to False
+ kwargs['disable'] = bool(kwargs.get('disable', False))
+ progress = kwargs.pop('progress', None)
+ super(tqdm_rich, self).__init__(*args, **kwargs)
+
+ if self.disable:
+ return
+
+ warn("rich is experimental/alpha", TqdmExperimentalWarning, stacklevel=2)
+ d = self.format_dict
+ if progress is None:
+ progress = (
+ "[progress.description]{task.description}"
+ "[progress.percentage]{task.percentage:>4.0f}%",
+ BarColumn(bar_width=None),
+ FractionColumn(
+ unit_scale=d['unit_scale'], unit_divisor=d['unit_divisor']),
+ "[", TimeElapsedColumn(), "<", TimeRemainingColumn(),
+ ",", RateColumn(unit=d['unit'], unit_scale=d['unit_scale'],
+ unit_divisor=d['unit_divisor']), "]"
+ )
+ self._prog = Progress(*progress, transient=not self.leave)
+ self._prog.__enter__()
+ self._task_id = self._prog.add_task(self.desc or "", **d)
+
+ def close(self):
+ if self.disable:
+ return
+ super(tqdm_rich, self).close()
+ self._prog.__exit__(None, None, None)
+
+ def clear(self, *_, **__):
+ pass
+
+ def display(self, *_, **__):
+ if not hasattr(self, '_prog'):
+ return
+ self._prog.update(self._task_id, completed=self.n, description=self.desc)
+
+ def reset(self, total=None):
+ """
+ Resets to 0 iterations for repeated use.
+
+ Parameters
+ ----------
+ total : int or float, optional. Total to use for the new bar.
+ """
+ if hasattr(self, '_prog'):
+ self._prog.reset(total=total)
+ super(tqdm_rich, self).reset(total=total)
+
+
+def trrange(*args, **kwargs):
+ """
+ A shortcut for `tqdm.rich.tqdm(xrange(*args), **kwargs)`.
+ On Python3+, `range` is used instead of `xrange`.
+ """
+ return tqdm_rich(_range(*args), **kwargs)
+
+
+# Aliases
+tqdm = tqdm_rich
+trange = trrange
diff --git a/libs/tqdm/std.py b/libs/tqdm/std.py
index 0cdc8e6b7..e81c83680 100644
--- a/libs/tqdm/std.py
+++ b/libs/tqdm/std.py
@@ -1,30 +1,30 @@
"""
Customisable progressbar decorator for iterators.
-Includes a default (x)range iterator printing to stderr.
+Includes a default `range` iterator printing to `stderr`.
Usage:
- >>> from tqdm import trange[, tqdm]
- >>> for i in trange(10): #same as: for i in tqdm(xrange(10))
- ... ...
+>>> from tqdm import trange, tqdm
+>>> for i in trange(10):
+... ...
"""
from __future__ import absolute_import, division
-# compatibility functions and utilities
-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
-from ._monitor import TMonitor
-# native libraries
-from contextlib import contextmanager
+
import sys
+from collections import OrderedDict, defaultdict
+from contextlib import contextmanager
+from datetime import datetime, timedelta
from numbers import Number
from time import time
-# For parallelism safety
-import threading as th
from warnings import warn
+from weakref import WeakSet
+
+from ._monitor import TMonitor
+from .utils import (
+ CallbackIOWrapper, Comparable, DisableOnWriteError, FormatReplace, SimpleTextIOWrapper,
+ _basestring, _is_ascii, _range, _screen_shape_wrapper, _supports_unicode, _term_move_up,
+ _unich, _unicode, disp_len, disp_trim)
-__author__ = {"github.com/": ["noamraph", "obiwanus", "kmike", "hadim",
- "casperdcl", "lrq3000"]}
+__author__ = "https://github.com/tqdm/tqdm#contributions"
__all__ = ['tqdm', 'trange',
'TqdmTypeError', 'TqdmKeyError', 'TqdmWarning',
'TqdmExperimentalWarning', 'TqdmDeprecationWarning',
@@ -46,8 +46,7 @@ class TqdmWarning(Warning):
"""
def __init__(self, msg, fp_write=None, *a, **k):
if fp_write is not None:
- fp_write("\n" + self.__class__.__name__ + ": " +
- str(msg).rstrip() + '\n')
+ fp_write("\n" + self.__class__.__name__ + ": " + str(msg).rstrip() + '\n')
else:
super(TqdmWarning, self).__init__(msg, *a, **k)
@@ -67,6 +66,15 @@ class TqdmMonitorWarning(TqdmWarning, RuntimeWarning):
pass
+def TRLock(*args, **kwargs):
+ """threading RLock"""
+ try:
+ from threading import RLock
+ return RLock(*args, **kwargs)
+ except (ImportError, OSError): # pragma: no cover
+ pass
+
+
class TqdmDefaultWriteLock(object):
"""
Provide a default write lock for thread and multiprocessing safety.
@@ -76,13 +84,22 @@ class TqdmDefaultWriteLock(object):
On Windows, you need to supply the lock from the parent to the children as
an argument to joblib or the parallelism lib you use.
"""
+ # global thread lock so no setup required for multithreading.
+ # NB: Do not create multiprocessing lock as it sets the multiprocessing
+ # context, disallowing `spawn()`/`forkserver()`
+ th_lock = TRLock()
+
def __init__(self):
# Create global parallelism locks to avoid racing issues with parallel
# bars works only if fork available (Linux/MacOSX, but not Windows)
- self.create_mp_lock()
- self.create_th_lock()
cls = type(self)
+ root_lock = cls.th_lock
+ if root_lock is not None:
+ root_lock.acquire()
+ cls.create_mp_lock()
self.locks = [lk for lk in [cls.mp_lock, cls.th_lock] if lk is not None]
+ if root_lock is not None:
+ root_lock.release()
def acquire(self, *a, **k):
for lock in self.locks:
@@ -103,26 +120,14 @@ class TqdmDefaultWriteLock(object):
if not hasattr(cls, 'mp_lock'):
try:
from multiprocessing import RLock
- cls.mp_lock = RLock() # multiprocessing lock
- except ImportError: # pragma: no cover
- cls.mp_lock = None
- except OSError: # pragma: no cover
+ cls.mp_lock = RLock()
+ except (ImportError, OSError): # pragma: no cover
cls.mp_lock = None
@classmethod
def create_th_lock(cls):
- if not hasattr(cls, 'th_lock'):
- try:
- cls.th_lock = th.RLock() # thread lock
- except OSError: # pragma: no cover
- cls.th_lock = None
-
-
-# Create a thread lock before instantiation so that no setup needs to be done
-# before running in a multithreaded environment.
-# Do not create the multiprocessing lock because it sets the multiprocessing
-# context and does not allow the user to use 'spawn' or 'forkserver' methods.
-TqdmDefaultWriteLock.create_th_lock()
+ assert hasattr(cls, 'th_lock')
+ warn("create_th_lock not needed anymore", TqdmDeprecationWarning, stacklevel=2)
class Bar(object):
@@ -141,21 +146,50 @@ class Bar(object):
ASCII = " 123456789#"
UTF = u" " + u''.join(map(_unich, range(0x258F, 0x2587, -1)))
BLANK = " "
-
- def __init__(self, frac, default_len=10, charset=UTF):
- if not (0 <= frac <= 1):
+ COLOUR_RESET = '\x1b[0m'
+ COLOUR_RGB = '\x1b[38;2;%d;%d;%dm'
+ COLOURS = {'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, 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:
_type = format_spec[-1].lower()
try:
- charset = dict(a=self.ASCII, u=self.UTF, b=self.BLANK)[_type]
+ charset = {'a': self.ASCII, 'u': self.UTF, 'b': self.BLANK}[_type]
except KeyError:
charset = self.charset
else:
@@ -171,17 +205,43 @@ class Bar(object):
N_BARS = self.default_len
nsyms = len(charset) - 1
- bar_length, frac_bar_length = divmod(
- int(self.frac * N_BARS * nsyms), nsyms)
+ bar_length, frac_bar_length = divmod(int(self.frac * N_BARS * nsyms), nsyms)
+
+ res = charset[-1] * bar_length
+ if bar_length < N_BARS: # whitespace padding
+ res = res + charset[frac_bar_length] + charset[0] * (N_BARS - bar_length - 1)
+ return self.colour + res + self.COLOUR_RESET if self.colour else res
+
- bar = charset[-1] * bar_length
- frac_bar = charset[frac_bar_length]
+class EMA(object):
+ """
+ Exponential moving average: smoothing to give progressively lower
+ weights to older values.
+
+ Parameters
+ ----------
+ smoothing : float, optional
+ Smoothing factor in range [0, 1], [default: 0.3].
+ Increase to give more weight to recent values.
+ Ranges from 0 (yields old value) to 1 (yields new value).
+ """
+ def __init__(self, smoothing=0.3):
+ self.alpha = smoothing
+ self.last = 0
+ self.calls = 0
- # whitespace padding
- if bar_length < N_BARS:
- return bar + frac_bar + \
- charset[0] * (N_BARS - bar_length - 1)
- return bar
+ def __call__(self, x=None):
+ """
+ Parameters
+ ----------
+ x : float
+ New value to include in EMA.
+ """
+ beta = 1 - self.alpha
+ if x is not None:
+ self.last = self.alpha * x + beta * self.last
+ self.calls += 1
+ return self.last / (1 - beta ** self.calls) if self.calls else self.last
class tqdm(Comparable):
@@ -193,6 +253,7 @@ class tqdm(Comparable):
monitor_interval = 10 # set to 0 to disable the thread
monitor = None
+ _instances = WeakSet()
@staticmethod
def format_sizeof(num, suffix='', divisor=1000):
@@ -266,25 +327,6 @@ class tqdm(Comparable):
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):
"""
Manage the printing and in-place updating of a line of characters.
@@ -293,6 +335,9 @@ class tqdm(Comparable):
"""
fp = file
fp_flush = getattr(fp, 'flush', lambda: None) # pragma: no cover
+ if fp in (sys.stderr, sys.stdout):
+ sys.stderr.flush()
+ sys.stdout.flush()
def fp_write(s):
fp.write(_unicode(s))
@@ -301,16 +346,16 @@ class tqdm(Comparable):
last_len = [0]
def print_status(s):
- len_s = len(s)
+ len_s = disp_len(s)
fp_write('\r' + s + (' ' * max(last_len[0] - len_s, 0)))
last_len[0] = len_s
return print_status
@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, **extra_kwargs):
+ 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, colour=None, **extra_kwargs):
"""
Return a string-based progress bar given some parameters
@@ -355,7 +400,7 @@ class tqdm(Comparable):
percentage, elapsed, elapsed_s, ncols, nrows, desc, unit,
rate, rate_fmt, rate_noinv, rate_noinv_fmt,
rate_inv, rate_inv_fmt, postfix, unit_divisor,
- remaining, remaining_s.
+ remaining, remaining_s, eta.
Note that a trailing ": " is automatically removed after {desc}
if the latter is empty.
postfix : *, optional
@@ -366,6 +411,10 @@ class tqdm(Comparable):
However other types are supported (#382).
unit_divisor : float, optional
[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
-------
@@ -382,7 +431,7 @@ class tqdm(Comparable):
total *= unit_scale
n *= unit_scale
if rate:
- rate *= unit_scale # by default rate = 1 / self.avg_time
+ rate *= unit_scale # by default rate = self.avg_dn / self.avg_dt
unit_scale = False
elapsed_str = tqdm.format_interval(elapsed)
@@ -390,21 +439,19 @@ class tqdm(Comparable):
# if unspecified, attempt to use rate = average speed
# (we allow manual override since predicting time is an arcane art)
if rate is None and elapsed:
- rate = n / elapsed
+ rate = (n - initial) / elapsed
inv_rate = 1 / rate if rate else None
format_sizeof = tqdm.format_sizeof
rate_noinv_fmt = ((format_sizeof(rate) if unit_scale else
- '{0:5.2f}'.format(rate))
- if rate else '?') + unit + '/s'
- rate_inv_fmt = ((format_sizeof(inv_rate) if unit_scale else
- '{0:5.2f}'.format(inv_rate))
- if inv_rate else '?') + 's/' + unit
+ '{0:5.2f}'.format(rate)) if rate else '?') + unit + '/s'
+ rate_inv_fmt = (
+ (format_sizeof(inv_rate) if unit_scale else '{0:5.2f}'.format(inv_rate))
+ if inv_rate else '?') + 's/' + unit
rate_fmt = rate_inv_fmt if inv_rate and inv_rate > 1 else rate_noinv_fmt
if unit_scale:
n_fmt = format_sizeof(n, divisor=unit_divisor)
- total_fmt = format_sizeof(total, divisor=unit_divisor) \
- if total is not None else '?'
+ total_fmt = format_sizeof(total, divisor=unit_divisor) if total is not None else '?'
else:
n_fmt = str(n)
total_fmt = str(total) if total is not None else '?'
@@ -416,6 +463,11 @@ class tqdm(Comparable):
remaining = (total - n) / rate if rate and total else 0
remaining_str = tqdm.format_interval(remaining) if rate else '?'
+ try:
+ eta_dt = (datetime.now() + timedelta(seconds=remaining)
+ if rate and total else datetime.utcfromtimestamp(0))
+ except OverflowError:
+ eta_dt = datetime.max
# format the stats displayed to the left and right sides of the bar
if prefix:
@@ -440,9 +492,10 @@ class tqdm(Comparable):
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,
+ l_bar=l_bar, r_bar=r_bar, eta=eta_dt,
**extra_kwargs)
# total is known: we can predict some stats
@@ -477,11 +530,10 @@ class tqdm(Comparable):
return nobar
# Formatting progress bar space available for bar's display
- full_bar = Bar(
- frac,
- max(1, ncols - disp_len(nobar))
- if ncols else 10,
- charset=Bar.ASCII if ascii is True else ascii or Bar.UTF)
+ full_bar = Bar(frac,
+ max(1, ncols - disp_len(nobar)) if ncols else 10,
+ 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)
@@ -495,31 +547,23 @@ class tqdm(Comparable):
nobar = bar_format.format(bar=full_bar, **format_dict)
if not full_bar.format_called:
return nobar
- full_bar = Bar(
- 0,
- max(1, ncols - disp_len(nobar))
- if ncols else 10,
- charset=Bar.BLANK)
+ full_bar = Bar(0,
+ max(1, ncols - disp_len(nobar)) if ncols else 10,
+ charset=Bar.BLANK, colour=colour)
res = bar_format.format(bar=full_bar, **format_dict)
return disp_trim(res, ncols) if ncols else res
else:
# no total: no progressbar, ETA, just progress stats
- return ((prefix + ": ") if prefix else '') + \
- '{0}{1} [{2}, {3}{4}]'.format(
- n_fmt, unit, elapsed_str, rate_fmt, postfix)
+ return '{0}{1}{2} [{3}, {4}{5}]'.format(
+ (prefix + ": ") if prefix else '', n_fmt, unit, elapsed_str, rate_fmt, postfix)
- def __new__(cls, *args, **kwargs):
- # Create a new instance
+ def __new__(cls, *_, **__):
instance = object.__new__(cls)
- # Construct the lock if it does not exist
- with cls.get_lock():
- # Add to the list of instances
- if not hasattr(cls, '_instances'):
- cls._instances = WeakSet()
+ with cls.get_lock(): # also constructs lock if non-existent
cls._instances.add(instance)
- # Create the monitoring thread
- if cls.monitor_interval and (cls.monitor is None or not
- cls.monitor.report()):
+ # create monitoring thread
+ if cls.monitor_interval and (cls.monitor is None
+ or not cls.monitor.report()):
try:
cls.monitor = TMonitor(cls, cls.monitor_interval)
except Exception as e: # pragma: nocover
@@ -527,14 +571,13 @@ class tqdm(Comparable):
" (monitor_interval = 0) due to:\n" + str(e),
TqdmMonitorWarning, stacklevel=2)
cls.monitor_interval = 0
- # Return the instance
return instance
@classmethod
def _get_free_pos(cls, instance=None):
"""Skips specified instance."""
- positions = set(abs(inst.pos) for inst in cls._instances
- if inst is not instance and hasattr(inst, "pos"))
+ positions = {abs(inst.pos) for inst in cls._instances
+ if inst is not instance and hasattr(inst, "pos")}
return min(set(range(len(positions) + 1)).difference(positions))
@classmethod
@@ -566,15 +609,6 @@ class tqdm(Comparable):
inst = min(instances, key=lambda i: i.pos)
inst.clear(nolock=True)
inst.pos = abs(instance.pos)
- # Kill monitor if no instances are left
- if not cls._instances and cls.monitor:
- try:
- cls.monitor.exit()
- del cls.monitor
- except AttributeError: # pragma: nocover
- pass
- else:
- cls.monitor = None
@classmethod
def write(cls, s, file=None, end="\n", nolock=False):
@@ -628,9 +662,9 @@ class tqdm(Comparable):
return cls._lock
@classmethod
- def pandas(tclass, *targs, **tkwargs):
+ def pandas(cls, **tqdm_kwargs):
"""
- Registers the given `tqdm` class with
+ Registers the current `tqdm` class with
pandas.core.
( frame.DataFrame
| series.Series
@@ -639,11 +673,11 @@ class tqdm(Comparable):
).progress_apply
A new instance will be create every time `progress_apply` is called,
- and each instance will automatically close() upon completion.
+ and each instance will automatically `close()` upon completion.
Parameters
----------
- targs, tkwargs : arguments for the tqdm instance
+ tqdm_kwargs : arguments for the tqdm instance
Examples
--------
@@ -659,35 +693,43 @@ class tqdm(Comparable):
References
----------
- https://stackoverflow.com/questions/18603270/
- progress-indicator-during-pandas-operations-python
+ <https://stackoverflow.com/questions/18603270/\
+ progress-indicator-during-pandas-operations-python>
"""
+ from warnings import catch_warnings, simplefilter
+
from pandas.core.frame import DataFrame
from pandas.core.series import Series
try:
- from pandas import Panel
- except ImportError: # TODO: pandas>0.25.2
+ with catch_warnings():
+ simplefilter("ignore", category=FutureWarning)
+ from pandas import Panel
+ except ImportError: # pandas>=1.2.0
Panel = None
+ Rolling, Expanding = None, None
try: # pandas>=1.0.0
from pandas.core.window.rolling import _Rolling_and_Expanding
except ImportError:
try: # pandas>=0.18.0
from pandas.core.window import _Rolling_and_Expanding
- except ImportError: # pragma: no cover
- _Rolling_and_Expanding = None
+ except ImportError: # pandas>=1.2.0
+ try: # pandas>=1.2.0
+ from pandas.core.window.expanding import Expanding
+ from pandas.core.window.rolling import Rolling
+ _Rolling_and_Expanding = Rolling, Expanding
+ except ImportError: # pragma: no cover
+ _Rolling_and_Expanding = None
try: # pandas>=0.25.0
- from pandas.core.groupby.generic import DataFrameGroupBy, \
- SeriesGroupBy # , NDFrameGroupBy
- except ImportError:
+ from pandas.core.groupby.generic import SeriesGroupBy # , NDFrameGroupBy
+ from pandas.core.groupby.generic import DataFrameGroupBy
+ except ImportError: # pragma: no cover
try: # pandas>=0.23.0
- from pandas.core.groupby.groupby import DataFrameGroupBy, \
- SeriesGroupBy
+ from pandas.core.groupby.groupby import DataFrameGroupBy, SeriesGroupBy
except ImportError:
- from pandas.core.groupby import DataFrameGroupBy, \
- SeriesGroupBy
+ from pandas.core.groupby import DataFrameGroupBy, SeriesGroupBy
try: # pandas>=0.23.0
from pandas.core.groupby.groupby import GroupBy
- except ImportError:
+ except ImportError: # pragma: no cover
from pandas.core.groupby import GroupBy
try: # pandas>=0.23.0
@@ -698,7 +740,8 @@ class tqdm(Comparable):
except ImportError: # pandas>=0.25.0
PanelGroupBy = None
- deprecated_t = [tkwargs.pop('deprecated_t', None)]
+ tqdm_kwargs = tqdm_kwargs.copy()
+ deprecated_t = [tqdm_kwargs.pop('deprecated_t', None)]
def inner_generator(df_function='apply'):
def inner(df, func, *args, **kwargs):
@@ -714,14 +757,14 @@ class tqdm(Comparable):
"""
# Precompute total iterations
- total = tkwargs.pop("total", getattr(df, 'ngroups', None))
+ total = tqdm_kwargs.pop("total", getattr(df, 'ngroups', None))
if total is None: # not grouped
if df_function == 'applymap':
total = df.size
elif isinstance(df, Series):
total = len(df)
- elif _Rolling_and_Expanding is None or \
- not isinstance(df, _Rolling_and_Expanding):
+ elif (_Rolling_and_Expanding is None or
+ not isinstance(df, _Rolling_and_Expanding)):
# DataFrame or Panel
axis = kwargs.get('axis', 0)
if axis == 'index':
@@ -736,7 +779,7 @@ class tqdm(Comparable):
t = deprecated_t[0]
deprecated_t[0] = None
else:
- t = tclass(*targs, total=total, **tkwargs)
+ t = cls(total=total, **tqdm_kwargs)
if len(args) > 0:
# *args intentionally not supported (see #244, #299)
@@ -747,8 +790,12 @@ class tqdm(Comparable):
" Use keyword arguments instead.",
fp_write=getattr(t.fp, 'write', sys.stderr.write))
+ try: # pandas>=1.3.0
+ from pandas.core.common import is_builtin_func
+ except ImportError:
+ is_builtin_func = df._is_builtin_func
try:
- func = df._is_builtin_func(func)
+ func = is_builtin_func(func)
except TypeError:
pass
@@ -790,17 +837,19 @@ class tqdm(Comparable):
GroupBy.progress_aggregate = inner_generator('aggregate')
GroupBy.progress_transform = inner_generator('transform')
- if _Rolling_and_Expanding is not None: # pragma: no cover
+ if Rolling is not None and Expanding is not None:
+ Rolling.progress_apply = inner_generator()
+ Expanding.progress_apply = inner_generator()
+ elif _Rolling_and_Expanding is not None:
_Rolling_and_Expanding.progress_apply = inner_generator()
- def __init__(self, iterable=None, desc=None, total=None, leave=True,
- file=None, ncols=None, mininterval=0.1, 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,
- unit_divisor=1000, write_bytes=None, lock_args=None,
- nrows=None,
- gui=False, **kwargs):
+ def __init__(self, iterable=None, desc=None, total=None, leave=True, file=None,
+ ncols=None, mininterval=0.1, 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, unit_divisor=1000, write_bytes=None,
+ lock_args=None, nrows=None, colour=None, delay=0, gui=False,
+ **kwargs):
"""
Parameters
----------
@@ -878,7 +927,7 @@ class tqdm(Comparable):
percentage, elapsed, elapsed_s, ncols, nrows, desc, unit,
rate, rate_fmt, rate_noinv, rate_noinv_fmt,
rate_inv, rate_inv_fmt, postfix, unit_divisor,
- remaining, remaining_s.
+ remaining, remaining_s, eta.
Note that a trailing ": " is automatically removed after {desc}
if the latter is empty.
initial : int or float, optional
@@ -905,6 +954,10 @@ class tqdm(Comparable):
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').
+ delay : float, optional
+ Don't display until [default: 0] seconds have elapsed.
gui : bool, optional
WARNING: internal parameter - do not use.
Use tqdm.gui.tqdm(...) instead. If set, will attempt to use
@@ -926,6 +979,8 @@ class tqdm(Comparable):
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
@@ -963,9 +1018,9 @@ class tqdm(Comparable):
TqdmKeyError("Unknown argument(s): " + str(kwargs)))
# Preprocess the arguments
- if ((ncols is None or nrows is None) and
- (file in (sys.stderr, sys.stdout))) or \
- dynamic_ncols: # pragma: no cover
+ if (
+ (ncols is None or nrows is None) and (file in (sys.stderr, sys.stdout))
+ ) or dynamic_ncols: # pragma: no cover
if dynamic_ncols:
dynamic_ncols = _screen_shape_wrapper()
if dynamic_ncols:
@@ -994,7 +1049,7 @@ class tqdm(Comparable):
if ascii is None:
ascii = not _supports_unicode(file)
- if bar_format and not ((ascii is True) or _is_ascii(ascii)):
+ if bar_format and ascii is not True and not _is_ascii(ascii):
# Convert bar format into unicode since terminal uses unicode
bar_format = _unicode(bar_format)
@@ -1018,14 +1073,19 @@ class tqdm(Comparable):
self.unit = unit
self.unit_scale = unit_scale
self.unit_divisor = unit_divisor
+ self.initial = initial
self.lock_args = lock_args
+ self.delay = delay
self.gui = gui
self.dynamic_ncols = dynamic_ncols
self.smoothing = smoothing
- self.avg_time = None
- self._time = time
+ self._ema_dn = EMA(smoothing)
+ self._ema_dt = EMA(smoothing)
+ self._ema_miniters = EMA(smoothing)
self.bar_format = bar_format
self.postfix = None
+ self.colour = colour
+ self._time = time
if postfix:
try:
self.set_postfix(refresh=False, **postfix)
@@ -1039,15 +1099,14 @@ class tqdm(Comparable):
# if nested, at initial sp() call we replace '\r' by '\n' to
# not overwrite the outer progress bar
with self._lock:
- if position is None:
- self.pos = self._get_free_pos(self)
- else: # mark fixed positions as negative
- self.pos = -position
+ # mark fixed positions as negative
+ self.pos = self._get_free_pos(self) if position is None else -position
if not gui:
# Initialize the screen printer
self.sp = self.status_printer(self.fp)
- self.refresh(lock_args=self.lock_args)
+ if delay <= 0:
+ self.refresh(lock_args=self.lock_args)
# Init the time counter
self.last_print_t = self._time()
@@ -1065,10 +1124,12 @@ class tqdm(Comparable):
return self.__bool__()
def __len__(self):
- return self.total if self.iterable is None else \
- (self.iterable.shape[0] if hasattr(self.iterable, "shape")
- else len(self.iterable) if hasattr(self.iterable, "__len__")
- else getattr(self, "total", None))
+ return (
+ self.total if self.iterable is None
+ else self.iterable.shape[0] if hasattr(self.iterable, "shape")
+ else len(self.iterable) if hasattr(self.iterable, "__len__")
+ else self.iterable.__length_hint__() if hasattr(self.iterable, "__length_hint__")
+ else getattr(self, "total", None))
def __enter__(self):
return self
@@ -1085,7 +1146,7 @@ class tqdm(Comparable):
def __del__(self):
self.close()
- def __repr__(self):
+ def __str__(self):
return self.format_meter(**self.format_dict)
@property
@@ -1109,76 +1170,28 @@ class tqdm(Comparable):
return
mininterval = self.mininterval
- maxinterval = self.maxinterval
- miniters = self.miniters
- dynamic_miniters = self.dynamic_miniters
last_print_t = self.last_print_t
last_print_n = self.last_print_n
+ min_start_t = self.start_t + self.delay
n = self.n
- smoothing = self.smoothing
- avg_time = self.avg_time
time = self._time
- if not hasattr(self, 'sp'):
- raise TqdmDeprecationWarning(
- "Please use `tqdm.gui.tqdm(...)` instead of"
- " `tqdm(..., gui=True)`\n",
- fp_write=getattr(self.fp, 'write', sys.stderr.write))
-
try:
for obj in iterable:
yield obj
# Update and possibly print the progressbar.
# Note: does not call self.update(1) for speed optimisation.
n += 1
- # check counter first to avoid calls to time()
+
if n - last_print_n >= self.miniters:
- miniters = self.miniters # watch monitoring thread changes
- delta_t = time() - last_print_t
- if delta_t >= mininterval:
- cur_t = time()
- delta_it = n - last_print_n
- # EMA (not just overall average)
- if smoothing and delta_t and delta_it:
- rate = delta_t / delta_it
- avg_time = self.ema(rate, avg_time, smoothing)
- self.avg_time = avg_time
-
- self.n = n
- self.refresh(lock_args=self.lock_args)
-
- # If no `miniters` was specified, adjust automatically
- # to the max iteration rate seen so far between 2 prints
- if dynamic_miniters:
- if maxinterval and delta_t >= maxinterval:
- # Adjust miniters to time interval by rule of 3
- if mininterval:
- # Set miniters to correspond to mininterval
- miniters = delta_it * mininterval / delta_t
- else:
- # Set miniters to correspond to maxinterval
- miniters = delta_it * maxinterval / delta_t
- elif smoothing:
- # EMA-weight miniters to converge
- # towards the timeframe of mininterval
- 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)
-
- # Store old values for next call
- self.n = self.last_print_n = last_print_n = n
- self.last_print_t = last_print_t = cur_t
- self.miniters = miniters
+ cur_t = time()
+ dt = cur_t - last_print_t
+ if dt >= mininterval and cur_t >= min_start_t:
+ self.update(n - last_print_n)
+ last_print_n = self.last_print_n
+ last_print_t = self.last_print_t
finally:
- # Closing the progress bar.
- # Update some internal variables for close().
- self.last_print_n = last_print_n
self.n = n
- self.miniters = miniters
self.close()
def update(self, n=1):
@@ -1201,8 +1214,12 @@ class tqdm(Comparable):
Increment to add to the internal counter of iterations
[default: 1]. If using float, consider specifying `{n:.3f}`
or similar in `bar_format`, or specifying `unit_scale`.
+
+ Returns
+ -------
+ out : bool or None
+ True if a `display()` was triggered.
"""
- # N.B.: see __iter__() for more comments.
if self.disable:
return
@@ -1212,50 +1229,37 @@ class tqdm(Comparable):
# check counter first to reduce calls to time()
if self.n - self.last_print_n >= self.miniters:
- delta_t = self._time() - self.last_print_t
- if delta_t >= self.mininterval:
+ cur_t = self._time()
+ dt = cur_t - self.last_print_t
+ if dt >= self.mininterval and cur_t >= self.start_t + self.delay:
cur_t = self._time()
- delta_it = self.n - self.last_print_n # >= n
- # elapsed = cur_t - self.start_t
- # EMA (not just overall average)
- 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)
-
- if not hasattr(self, "sp"):
- raise TqdmDeprecationWarning(
- "Please use `tqdm.gui.tqdm(...)`"
- " instead of `tqdm(..., gui=True)`\n",
- fp_write=getattr(self.fp, 'write', sys.stderr.write))
-
+ dn = self.n - self.last_print_n # >= n
+ if self.smoothing and dt and dn:
+ # EMA (not just overall average)
+ self._ema_dn(dn)
+ self._ema_dt(dt)
self.refresh(lock_args=self.lock_args)
-
- # If no `miniters` was specified, adjust automatically to the
- # maximum iteration rate seen so far between two prints.
- # e.g.: After running `tqdm.update(5)`, subsequent
- # calls to `tqdm.update()` will only cause an update after
- # at least 5 more iterations.
if self.dynamic_miniters:
- if self.maxinterval and delta_t >= self.maxinterval:
- if self.mininterval:
- self.miniters = delta_it * self.mininterval \
- / delta_t
- else:
- self.miniters = delta_it * self.maxinterval \
- / delta_t
+ # If no `miniters` was specified, adjust automatically to the
+ # maximum iteration rate seen so far between two prints.
+ # e.g.: After running `tqdm.update(5)`, subsequent
+ # calls to `tqdm.update()` will only cause an update after
+ # at least 5 more iterations.
+ if self.maxinterval and dt >= self.maxinterval:
+ self.miniters = dn * (self.mininterval or self.maxinterval) / dt
elif self.smoothing:
- self.miniters = self.smoothing * delta_it * \
- (self.mininterval / delta_t
- if self.mininterval and delta_t
- else 1) + \
- (1 - self.smoothing) * self.miniters
+ # EMA miniters update
+ self.miniters = self._ema_miniters(
+ dn * (self.mininterval / dt if self.mininterval and dt
+ else 1))
else:
- self.miniters = max(self.miniters, delta_it)
+ # max iters between two prints
+ self.miniters = max(self.miniters, dn)
# Store old values for next call
self.last_print_n = self.n
self.last_print_t = cur_t
+ return True
def close(self):
"""Cleanup and (if leave=False) close the progressbar."""
@@ -1269,8 +1273,12 @@ class tqdm(Comparable):
pos = abs(self.pos)
self._decr_instances(self)
+ if self.last_print_t < self.start_t + self.delay:
+ # haven't ever displayed; nothing to clear
+ return
+
# GUI mode
- if not hasattr(self, "sp"):
+ if getattr(self, 'sp', None) is None:
return
# annoyingly, _supports_unicode isn't good enough
@@ -1289,7 +1297,7 @@ class tqdm(Comparable):
with self._lock:
if leave:
# stats for overall rate (no weighted average)
- self.avg_time = None
+ self._ema_dt = lambda: None
self.display(pos=0)
fp_write('\n')
else:
@@ -1342,6 +1350,8 @@ class tqdm(Comparable):
def unpause(self):
"""Restart tqdm timer from last print time."""
+ if self.disable:
+ return
cur_t = self._time()
self.start_t += cur_t - self.last_print_t
self.last_print_t = cur_t
@@ -1356,10 +1366,16 @@ class tqdm(Comparable):
----------
total : int or float, optional. Total to use for the new bar.
"""
- self.last_print_n = self.n = 0
- self.last_print_t = self.start_t = self._time()
+ self.n = 0
if total is not None:
self.total = total
+ if self.disable:
+ return
+ self.last_print_n = 0
+ self.last_print_t = self.start_t = self._time()
+ self._ema_dn = EMA(self.smoothing)
+ self._ema_dt = EMA(self.smoothing)
+ self._ema_miniters = EMA(self.smoothing)
self.refresh()
def set_description(self, desc=None, refresh=True):
@@ -1395,7 +1411,7 @@ class tqdm(Comparable):
kwargs : dict, optional
"""
# Sort in alphabetical order to be more deterministic
- postfix = _OrderedDict([] if ordered_dict is None else ordered_dict)
+ postfix = OrderedDict([] if ordered_dict is None else ordered_dict)
for key in sorted(kwargs.keys()):
postfix[key] = kwargs[key]
# Preprocess stats according to datatype
@@ -1429,19 +1445,20 @@ class tqdm(Comparable):
@property
def format_dict(self):
"""Public API for read-only member access."""
+ if self.disable and not hasattr(self, 'unit'):
+ return defaultdict(lambda: None, {
+ 'n': self.n, 'total': self.total, 'elapsed': 0, 'unit': 'it'})
if self.dynamic_ncols:
self.ncols, self.nrows = self.dynamic_ncols(self.fp)
- ncols, nrows = self.ncols, self.nrows
- return dict(
- n=self.n, total=self.total,
- elapsed=self._time() - self.start_t
- if hasattr(self, 'start_t') else 0,
- ncols=ncols, nrows=nrows,
- prefix=self.desc, ascii=self.ascii, unit=self.unit,
- 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)
+ return {
+ 'n': self.n, 'total': self.total,
+ 'elapsed': self._time() - self.start_t if hasattr(self, 'start_t') else 0,
+ 'ncols': self.ncols, 'nrows': self.nrows, 'prefix': self.desc,
+ 'ascii': self.ascii, 'unit': self.unit, 'unit_scale': self.unit_scale,
+ 'rate': self._ema_dn() / self._ema_dt() if self._ema_dt() else None,
+ 'bar_format': self.bar_format, 'postfix': self.postfix,
+ 'unit_divisor': self.unit_divisor, 'initial': self.initial,
+ 'colour': self.colour}
def display(self, msg=None, pos=None):
"""
@@ -1466,16 +1483,22 @@ class tqdm(Comparable):
if msg or msg is None: # override at `nrows - 1`
msg = " ... (more hidden) ..."
+ if not hasattr(self, "sp"):
+ raise TqdmDeprecationWarning(
+ "Please use `tqdm.gui.tqdm(...)`"
+ " instead of `tqdm(..., gui=True)`\n",
+ fp_write=getattr(self.fp, 'write', sys.stderr.write))
+
if pos:
self.moveto(pos)
- self.sp(self.__repr__() if msg is None else msg)
+ self.sp(self.__str__() if msg is None else msg)
if pos:
self.moveto(-pos)
return True
@classmethod
@contextmanager
- def wrapattr(tclass, stream, method, total=None, bytes=True, **tkwargs):
+ def wrapattr(cls, stream, method, total=None, bytes=True, **tqdm_kwargs):
"""
stream : file-like object.
method : str, "read" or "write". The result of `read()` and
@@ -1487,7 +1510,7 @@ class tqdm(Comparable):
... if not chunk:
... break
"""
- with tclass(total=total, **tkwargs) as t:
+ with cls(total=total, **tqdm_kwargs) as t:
if bytes:
t.unit = "B"
t.unit_scale = True
diff --git a/libs/tqdm/tests/tests_concurrent.py b/libs/tqdm/tests/tests_concurrent.py
deleted file mode 100644
index e64cb789b..000000000
--- a/libs/tqdm/tests/tests_concurrent.py
+++ /dev/null
@@ -1,58 +0,0 @@
-"""
-Tests for `tqdm.contrib.concurrent`.
-"""
-from warnings import catch_warnings
-from tqdm.contrib.concurrent import thread_map, process_map
-from tests_tqdm import with_setup, pretest, posttest, SkipTest, StringIO, \
- closing
-
-
-def incr(x):
- """Dummy function"""
- return x + 1
-
-
-@with_setup(pretest, posttest)
-def test_thread_map():
- """Test contrib.concurrent.thread_map"""
- with closing(StringIO()) as our_file:
- a = range(9)
- b = [i + 1 for i in a]
- try:
- assert thread_map(lambda x: x + 1, a, file=our_file) == b
- except ImportError:
- raise SkipTest
- assert thread_map(incr, a, file=our_file) == b
-
-
-@with_setup(pretest, posttest)
-def test_process_map():
- """Test contrib.concurrent.process_map"""
- with closing(StringIO()) as our_file:
- a = range(9)
- b = [i + 1 for i in a]
- try:
- assert process_map(incr, a, file=our_file) == b
- except ImportError:
- raise SkipTest
-
-
-def test_chunksize_warning():
- """Test contrib.concurrent.process_map chunksize warnings"""
- try:
- from unittest.mock import patch
- except ImportError:
- raise SkipTest
-
- for iterables, should_warn in [
- ([], False),
- (['x'], False),
- ([()], False),
- (['x', ()], False),
- (['x' * 1001], True),
- (['x' * 100, ('x',) * 1001], True),
- ]:
- with patch('tqdm.contrib.concurrent._executor_map'):
- with catch_warnings(record=True) as w:
- process_map(incr, *iterables)
- assert should_warn == bool(w)
diff --git a/libs/tqdm/tests/tests_contrib.py b/libs/tqdm/tests/tests_contrib.py
deleted file mode 100644
index e79fad22e..000000000
--- a/libs/tqdm/tests/tests_contrib.py
+++ /dev/null
@@ -1,61 +0,0 @@
-"""
-Tests for `tqdm.contrib`.
-"""
-import sys
-from tqdm.contrib import tenumerate, tzip, tmap
-from tests_tqdm import with_setup, pretest, posttest, SkipTest, StringIO, \
- closing
-
-
-def incr(x):
- """Dummy function"""
- return x + 1
-
-
-@with_setup(pretest, posttest)
-def test_enumerate():
- """Test contrib.tenumerate"""
- with closing(StringIO()) as our_file:
- a = range(9)
- assert list(tenumerate(a, file=our_file)) == list(enumerate(a))
- assert list(tenumerate(a, 42, file=our_file)) == list(enumerate(a, 42))
-
-
-@with_setup(pretest, posttest)
-def test_enumerate_numpy():
- """Test contrib.tenumerate(numpy.ndarray)"""
- try:
- import numpy as np
- except ImportError:
- raise SkipTest
- with closing(StringIO()) as our_file:
- a = np.random.random((42, 1337))
- assert list(tenumerate(a, file=our_file)) == list(np.ndenumerate(a))
-
-
-@with_setup(pretest, posttest)
-def test_zip():
- """Test contrib.tzip"""
- with closing(StringIO()) as our_file:
- a = range(9)
- b = [i + 1 for i in a]
- if sys.version_info[:1] < (3,):
- assert tzip(a, b, file=our_file) == zip(a, b)
- else:
- gen = tzip(a, b, file=our_file)
- assert gen != list(zip(a, b))
- assert list(gen) == list(zip(a, b))
-
-
-@with_setup(pretest, posttest)
-def test_map():
- """Test contrib.tmap"""
- with closing(StringIO()) as our_file:
- a = range(9)
- b = [i + 1 for i in a]
- if sys.version_info[:1] < (3,):
- assert tmap(lambda x: x + 1, a, file=our_file) == map(incr, a)
- else:
- gen = tmap(lambda x: x + 1, a, file=our_file)
- assert gen != b
- assert list(gen) == b
diff --git a/libs/tqdm/tests/tests_itertools.py b/libs/tqdm/tests/tests_itertools.py
deleted file mode 100644
index c55e07db8..000000000
--- a/libs/tqdm/tests/tests_itertools.py
+++ /dev/null
@@ -1,27 +0,0 @@
-"""
-Tests for `tqdm.contrib.itertools`.
-"""
-from tqdm.contrib.itertools import product
-from tests_tqdm import with_setup, pretest, posttest, StringIO, closing
-import itertools
-
-
-class NoLenIter(object):
- def __init__(self, iterable):
- self._it = iterable
-
- def __iter__(self):
- for i in self._it:
- yield i
-
-
-@with_setup(pretest, posttest)
-def test_product():
- """Test contrib.itertools.product"""
- with closing(StringIO()) as our_file:
- a = range(9)
- assert list(product(a, a[::-1], file=our_file)) == \
- list(itertools.product(a, a[::-1]))
-
- assert list(product(a, NoLenIter(a), file=our_file)) == \
- list(itertools.product(a, NoLenIter(a)))
diff --git a/libs/tqdm/tests/tests_keras.py b/libs/tqdm/tests/tests_keras.py
deleted file mode 100644
index 11684c490..000000000
--- a/libs/tqdm/tests/tests_keras.py
+++ /dev/null
@@ -1,97 +0,0 @@
-from __future__ import division
-from tqdm import tqdm
-from tests_tqdm import with_setup, pretest, posttest, SkipTest, StringIO, \
- closing
-
-
-@with_setup(pretest, posttest)
-def test_keras():
- """Test tqdm.keras.TqdmCallback"""
- try:
- from tqdm.keras import TqdmCallback
- import numpy as np
- try:
- import keras as K
- except ImportError:
- from tensorflow import keras as K
- except ImportError:
- raise SkipTest
-
- # 1D autoencoder
- dtype = np.float32
- model = K.models.Sequential(
- [K.layers.InputLayer((1, 1), dtype=dtype), K.layers.Conv1D(1, 1)]
- )
- model.compile("adam", "mse")
- x = np.random.rand(100, 1, 1).astype(dtype)
- batch_size = 10
- batches = len(x) / batch_size
- epochs = 5
-
- with closing(StringIO()) as our_file:
-
- class Tqdm(tqdm):
- """redirected I/O class"""
-
- def __init__(self, *a, **k):
- k.setdefault("file", our_file)
- super(Tqdm, self).__init__(*a, **k)
-
- # just epoch (no batch) progress
- model.fit(
- x,
- x,
- epochs=epochs,
- batch_size=batch_size,
- verbose=False,
- callbacks=[
- TqdmCallback(
- epochs,
- data_size=len(x),
- batch_size=batch_size,
- verbose=0,
- tqdm_class=Tqdm,
- )
- ],
- )
- res = our_file.getvalue()
- assert "{epochs}/{epochs}".format(epochs=epochs) in res
- assert "{batches}/{batches}".format(batches=batches) not in res
-
- # full (epoch and batch) progress
- our_file.seek(0)
- our_file.truncate()
- model.fit(
- x,
- x,
- epochs=epochs,
- batch_size=batch_size,
- verbose=False,
- callbacks=[
- TqdmCallback(
- epochs,
- data_size=len(x),
- batch_size=batch_size,
- verbose=2,
- tqdm_class=Tqdm,
- )
- ],
- )
- res = our_file.getvalue()
- assert "{epochs}/{epochs}".format(epochs=epochs) in res
- assert "{batches}/{batches}".format(batches=batches) in res
-
- # auto-detect epochs and batches
- our_file.seek(0)
- our_file.truncate()
- model.fit(
- x,
- x,
- epochs=epochs,
- batch_size=batch_size,
- verbose=False,
- callbacks=[TqdmCallback(verbose=2, tqdm_class=Tqdm)],
- )
- res = our_file.getvalue()
- assert "{epochs}/{epochs}".format(epochs=epochs) in res
- assert "{batches}/{batches}".format(batches=batches) in res
diff --git a/libs/tqdm/tests/tests_main.py b/libs/tqdm/tests/tests_main.py
deleted file mode 100644
index 75727071e..000000000
--- a/libs/tqdm/tests/tests_main.py
+++ /dev/null
@@ -1,172 +0,0 @@
-import sys
-import subprocess
-from os import path
-from shutil import rmtree
-from tempfile import mkdtemp
-from tqdm.cli import main, TqdmKeyError, TqdmTypeError
-from tqdm.utils import IS_WIN
-from io import open as io_open
-
-from tests_tqdm import with_setup, pretest, posttest, _range, closing, \
- UnicodeIO, StringIO, SkipTest
-
-
-def _sh(*cmd, **kwargs):
- return subprocess.Popen(cmd, stdout=subprocess.PIPE,
- **kwargs).communicate()[0].decode('utf-8')
-
-
-class Null(object):
- def __call__(self, *_, **__):
- return self
-
- def __getattr__(self, _):
- return self
-
-
-IN_DATA_LIST = map(str, _range(int(123)))
-NULL = Null()
-
-
-# WARNING: this should be the last test as it messes with sys.stdin, argv
-@with_setup(pretest, posttest)
-def test_main():
- """Test command line pipes"""
- ls_out = _sh('ls').replace('\r\n', '\n')
- ls = subprocess.Popen('ls', stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- res = _sh(sys.executable, '-c', 'from tqdm.cli import main; main()',
- stdin=ls.stdout, stderr=subprocess.STDOUT)
- ls.wait()
-
- # actual test:
-
- assert ls_out in res.replace('\r\n', '\n')
-
- # semi-fake test which gets coverage:
- _SYS = sys.stdin, sys.argv
-
- with closing(StringIO()) as sys.stdin:
- sys.argv = ['', '--desc', 'Test CLI --delim',
- '--ascii', 'True', '--delim', r'\0', '--buf_size', '64']
- sys.stdin.write('\0'.join(map(str, _range(int(123)))))
- # sys.stdin.write(b'\xff') # TODO
- sys.stdin.seek(0)
- main()
- sys.stdin = IN_DATA_LIST
-
- sys.argv = ['', '--desc', 'Test CLI pipes',
- '--ascii', 'True', '--unit_scale', 'True']
- import tqdm.__main__ # NOQA
-
- with closing(StringIO()) as sys.stdin:
- IN_DATA = '\0'.join(IN_DATA_LIST)
- sys.stdin.write(IN_DATA)
- sys.stdin.seek(0)
- sys.argv = ['', '--ascii', '--bytes=True', '--unit_scale', 'False']
- with closing(UnicodeIO()) as fp:
- main(fp=fp)
- assert str(len(IN_DATA)) in fp.getvalue()
- sys.stdin = IN_DATA_LIST
-
- # test --log
- with closing(StringIO()) as sys.stdin:
- sys.stdin.write('\0'.join(map(str, _range(int(123)))))
- sys.stdin.seek(0)
- # with closing(UnicodeIO()) as fp:
- main(argv=['--log', 'DEBUG'], fp=NULL)
- # assert "DEBUG:" in sys.stdout.getvalue()
- sys.stdin = IN_DATA_LIST
-
- # clean up
- sys.stdin, sys.argv = _SYS
-
-
-def test_manpath():
- """Test CLI --manpath"""
- if IS_WIN:
- raise SkipTest
- tmp = mkdtemp()
- man = path.join(tmp, "tqdm.1")
- assert not path.exists(man)
- try:
- main(argv=['--manpath', tmp], fp=NULL)
- except SystemExit:
- pass
- else:
- raise SystemExit("Expected system exit")
- assert path.exists(man)
- rmtree(tmp, True)
-
-
-def test_comppath():
- """Test CLI --comppath"""
- if IS_WIN:
- raise SkipTest
- tmp = mkdtemp()
- man = path.join(tmp, "tqdm_completion.sh")
- assert not path.exists(man)
- try:
- main(argv=['--comppath', tmp], fp=NULL)
- except SystemExit:
- pass
- else:
- raise SystemExit("Expected system exit")
- assert path.exists(man)
-
- # check most important options appear
- with io_open(man, mode='r', encoding='utf-8') as fd:
- script = fd.read()
- opts = set([
- '--help', '--desc', '--total', '--leave', '--ncols', '--ascii',
- '--dynamic_ncols', '--position', '--bytes', '--nrows', '--delim',
- '--manpath', '--comppath'
- ])
- assert all(args in script for args in opts)
- rmtree(tmp, True)
-
-
-def test_exceptions():
- """Test CLI Exceptions"""
- _SYS = sys.stdin, sys.argv
- sys.stdin = IN_DATA_LIST
-
- sys.argv = ['', '-ascii', '-unit_scale', '--bad_arg_u_ment', 'foo']
- try:
- main(fp=NULL)
- except TqdmKeyError as e:
- if 'bad_arg_u_ment' not in str(e):
- raise
- else:
- raise TqdmKeyError('bad_arg_u_ment')
-
- sys.argv = ['', '-ascii', '-unit_scale', 'invalid_bool_value']
- try:
- main(fp=NULL)
- except TqdmTypeError as e:
- if 'invalid_bool_value' not in str(e):
- raise
- else:
- raise TqdmTypeError('invalid_bool_value')
-
- sys.argv = ['', '-ascii', '--total', 'invalid_int_value']
- try:
- main(fp=NULL)
- except TqdmTypeError as e:
- if 'invalid_int_value' not in str(e):
- raise
- else:
- raise TqdmTypeError('invalid_int_value')
-
- # test SystemExits
- for i in ('-h', '--help', '-v', '--version'):
- sys.argv = ['', i]
- try:
- main(fp=NULL)
- except SystemExit:
- pass
- else:
- raise ValueError('expected SystemExit')
-
- # clean up
- sys.stdin, sys.argv = _SYS
diff --git a/libs/tqdm/tests/tests_notebook.py b/libs/tqdm/tests/tests_notebook.py
deleted file mode 100644
index 3af992f0c..000000000
--- a/libs/tqdm/tests/tests_notebook.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from tqdm.notebook import tqdm as tqdm_notebook
-from tests_tqdm import with_setup, pretest, posttest
-
-
-@with_setup(pretest, posttest)
-def test_notebook_disabled_description():
- """Test that set_description works for disabled tqdm_notebook"""
- with tqdm_notebook(1, disable=True) as t:
- t.set_description("description")
diff --git a/libs/tqdm/tests/tests_pandas.py b/libs/tqdm/tests/tests_pandas.py
deleted file mode 100644
index 8719a7ca2..000000000
--- a/libs/tqdm/tests/tests_pandas.py
+++ /dev/null
@@ -1,264 +0,0 @@
-from tqdm import tqdm
-from tests_tqdm import with_setup, pretest, posttest, SkipTest, \
- StringIO, closing
-
-
-@with_setup(pretest, posttest)
-def test_pandas_setup():
- """Test tqdm.pandas()"""
- try:
- from numpy.random import randint
- import pandas as pd
- except ImportError:
- raise SkipTest
-
- with closing(StringIO()) as our_file:
- tqdm.pandas(file=our_file, leave=True, ascii=True, total=123)
- series = pd.Series(randint(0, 50, (100,)))
- series.progress_apply(lambda x: x + 10)
- res = our_file.getvalue()
- assert '100/123' in res
-
-
-@with_setup(pretest, posttest)
-def test_pandas_rolling_expanding():
- """Test pandas.(Series|DataFrame).(rolling|expanding)"""
- try:
- from numpy.random import randint
- import pandas as pd
- except ImportError:
- raise SkipTest
-
- with closing(StringIO()) as our_file:
- tqdm.pandas(file=our_file, leave=True, ascii=True)
-
- series = pd.Series(randint(0, 50, (123,)))
- res1 = series.rolling(10).progress_apply(lambda x: 1, raw=True)
- res2 = series.rolling(10).apply(lambda x: 1, raw=True)
- assert res1.equals(res2)
-
- res3 = series.expanding(10).progress_apply(lambda x: 2, raw=True)
- res4 = series.expanding(10).apply(lambda x: 2, raw=True)
- assert res3.equals(res4)
-
- expects = ['114it'] # 123-10+1
- for exres in expects:
- our_file.seek(0)
- if our_file.getvalue().count(exres) < 2:
- our_file.seek(0)
- raise AssertionError(
- "\nExpected:\n{0}\nIn:\n{1}\n".format(
- exres + " at least twice.", our_file.read()))
-
-
-@with_setup(pretest, posttest)
-def test_pandas_series():
- """Test pandas.Series.progress_apply and .progress_map"""
- try:
- from numpy.random import randint
- import pandas as pd
- except ImportError:
- raise SkipTest
-
- with closing(StringIO()) as our_file:
- tqdm.pandas(file=our_file, leave=True, ascii=True)
-
- series = pd.Series(randint(0, 50, (123,)))
- res1 = series.progress_apply(lambda x: x + 10)
- res2 = series.apply(lambda x: x + 10)
- assert res1.equals(res2)
-
- res3 = series.progress_map(lambda x: x + 10)
- res4 = series.map(lambda x: x + 10)
- assert res3.equals(res4)
-
- expects = ['100%', '123/123']
- for exres in expects:
- our_file.seek(0)
- if our_file.getvalue().count(exres) < 2:
- our_file.seek(0)
- raise AssertionError(
- "\nExpected:\n{0}\nIn:\n{1}\n".format(
- exres + " at least twice.", our_file.read()))
-
-
-@with_setup(pretest, posttest)
-def test_pandas_data_frame():
- """Test pandas.DataFrame.progress_apply and .progress_applymap"""
- try:
- from numpy.random import randint
- import pandas as pd
- except ImportError:
- raise SkipTest
-
- with closing(StringIO()) as our_file:
- tqdm.pandas(file=our_file, leave=True, ascii=True)
- df = pd.DataFrame(randint(0, 50, (100, 200)))
-
- def task_func(x):
- return x + 1
-
- # applymap
- res1 = df.progress_applymap(task_func)
- res2 = df.applymap(task_func)
- assert res1.equals(res2)
-
- # apply unhashable
- res1 = []
- df.progress_apply(res1.extend)
- assert len(res1) == df.size
-
- # apply
- for axis in [0, 1, 'index', 'columns']:
- res3 = df.progress_apply(task_func, axis=axis)
- res4 = df.apply(task_func, axis=axis)
- assert res3.equals(res4)
-
- our_file.seek(0)
- if our_file.read().count('100%') < 3:
- our_file.seek(0)
- raise AssertionError("\nExpected:\n{0}\nIn:\n{1}\n".format(
- '100% at least three times', our_file.read()))
-
- # apply_map, apply axis=0, apply axis=1
- expects = ['20000/20000', '200/200', '100/100']
- for exres in expects:
- our_file.seek(0)
- if our_file.getvalue().count(exres) < 1:
- our_file.seek(0)
- raise AssertionError(
- "\nExpected:\n{0}\nIn:\n {1}\n".format(
- exres + " at least once.", our_file.read()))
-
-
-@with_setup(pretest, posttest)
-def test_pandas_groupby_apply():
- """Test pandas.DataFrame.groupby(...).progress_apply"""
- try:
- from numpy.random import randint, rand
- import pandas as pd
- except ImportError:
- raise SkipTest
-
- with closing(StringIO()) as our_file:
- tqdm.pandas(file=our_file, leave=False, ascii=True)
-
- df = pd.DataFrame(randint(0, 50, (500, 3)))
- df.groupby(0).progress_apply(lambda x: None)
-
- dfs = pd.DataFrame(randint(0, 50, (500, 3)), columns=list('abc'))
- dfs.groupby(['a']).progress_apply(lambda x: None)
-
- df2 = df = pd.DataFrame(dict(a=randint(1, 8, 10000), b=rand(10000)))
- res1 = df2.groupby("a").apply(max)
- res2 = df2.groupby("a").progress_apply(max)
- assert res1.equals(res2)
-
- our_file.seek(0)
-
- # don't expect final output since no `leave` and
- # high dynamic `miniters`
- nexres = '100%|##########|'
- if nexres in our_file.read():
- our_file.seek(0)
- raise AssertionError("\nDid not expect:\n{0}\nIn:{1}\n".format(
- nexres, our_file.read()))
-
- with closing(StringIO()) as our_file:
- tqdm.pandas(file=our_file, leave=True, ascii=True)
-
- dfs = pd.DataFrame(randint(0, 50, (500, 3)), columns=list('abc'))
- dfs.loc[0] = [2, 1, 1]
- dfs['d'] = 100
-
- expects = ['500/500', '1/1', '4/4', '2/2']
- dfs.groupby(dfs.index).progress_apply(lambda x: None)
- dfs.groupby('d').progress_apply(lambda x: None)
- dfs.groupby(dfs.columns, axis=1).progress_apply(lambda x: None)
- dfs.groupby([2, 2, 1, 1], axis=1).progress_apply(lambda x: None)
-
- our_file.seek(0)
- if our_file.read().count('100%') < 4:
- our_file.seek(0)
- raise AssertionError("\nExpected:\n{0}\nIn:\n{1}\n".format(
- '100% at least four times', our_file.read()))
-
- for exres in expects:
- our_file.seek(0)
- if our_file.getvalue().count(exres) < 1:
- our_file.seek(0)
- raise AssertionError(
- "\nExpected:\n{0}\nIn:\n {1}\n".format(
- exres + " at least once.", our_file.read()))
-
-
-@with_setup(pretest, posttest)
-def test_pandas_leave():
- """Test pandas with `leave=True`"""
- try:
- from numpy.random import randint
- import pandas as pd
- except ImportError:
- raise SkipTest
-
- with closing(StringIO()) as our_file:
- df = pd.DataFrame(randint(0, 100, (1000, 6)))
- tqdm.pandas(file=our_file, leave=True, ascii=True)
- df.groupby(0).progress_apply(lambda x: None)
-
- our_file.seek(0)
-
- exres = '100%|##########| 100/100'
- if exres not in our_file.read():
- our_file.seek(0)
- raise AssertionError(
- "\nExpected:\n{0}\nIn:{1}\n".format(exres, our_file.read()))
-
-
-@with_setup(pretest, posttest)
-def test_pandas_apply_args_deprecation():
- """Test warning info in
- `pandas.Dataframe(Series).progress_apply(func, *args)`"""
- try:
- from numpy.random import randint
- from tqdm import tqdm_pandas
- import pandas as pd
- except ImportError:
- raise SkipTest
-
- with closing(StringIO()) as our_file:
- tqdm_pandas(tqdm(file=our_file, leave=False, ascii=True, ncols=20))
- df = pd.DataFrame(randint(0, 50, (500, 3)))
- df.progress_apply(lambda x: None, 1) # 1 shall cause a warning
- # Check deprecation message
- res = our_file.getvalue()
- assert all([i in res for i in (
- "TqdmDeprecationWarning", "not supported",
- "keyword arguments instead")])
-
-
-@with_setup(pretest, posttest)
-def test_pandas_deprecation():
- """Test bar object instance as argument deprecation"""
- try:
- from numpy.random import randint
- from tqdm import tqdm_pandas
- import pandas as pd
- except ImportError:
- raise SkipTest
-
- with closing(StringIO()) as our_file:
- tqdm_pandas(tqdm(file=our_file, leave=False, ascii=True, ncols=20))
- df = pd.DataFrame(randint(0, 50, (500, 3)))
- df.groupby(0).progress_apply(lambda x: None)
- # Check deprecation message
- assert "TqdmDeprecationWarning" in our_file.getvalue()
- assert "instead of `tqdm_pandas(tqdm(...))`" in our_file.getvalue()
-
- with closing(StringIO()) as our_file:
- tqdm_pandas(tqdm, file=our_file, leave=False, ascii=True, ncols=20)
- df = pd.DataFrame(randint(0, 50, (500, 3)))
- df.groupby(0).progress_apply(lambda x: None)
- # Check deprecation message
- assert "TqdmDeprecationWarning" in our_file.getvalue()
- assert "instead of `tqdm_pandas(tqdm, ...)`" in our_file.getvalue()
diff --git a/libs/tqdm/tests/tests_perf.py b/libs/tqdm/tests/tests_perf.py
deleted file mode 100644
index 6cb7a6ee5..000000000
--- a/libs/tqdm/tests/tests_perf.py
+++ /dev/null
@@ -1,367 +0,0 @@
-from __future__ import print_function, division
-
-from nose.plugins.skip import SkipTest
-
-from contextlib import contextmanager
-
-import sys
-from time import sleep, time
-
-from tqdm import trange
-from tqdm import tqdm
-
-from tests_tqdm import with_setup, pretest, posttest, StringIO, closing, _range
-
-# Use relative/cpu timer to have reliable timings when there is a sudden load
-try:
- from time import process_time
-except ImportError:
- from time import clock
- process_time = clock
-
-
-def get_relative_time(prevtime=0):
- return process_time() - prevtime
-
-
-def cpu_sleep(t):
- """Sleep the given amount of cpu time"""
- start = process_time()
- while (process_time() - start) < t:
- pass
-
-
-def checkCpuTime(sleeptime=0.2):
- """Check if cpu time works correctly"""
- if checkCpuTime.passed:
- return True
- # First test that sleeping does not consume cputime
- start1 = process_time()
- sleep(sleeptime)
- t1 = process_time() - start1
-
- # secondly check by comparing to cpusleep (where we actually do something)
- start2 = process_time()
- cpu_sleep(sleeptime)
- t2 = process_time() - start2
-
- if abs(t1) < 0.0001 and (t1 < t2 / 10):
- return True
- raise SkipTest
-
-
-checkCpuTime.passed = False
-
-
-@contextmanager
-def relative_timer():
- start = process_time()
-
- def elapser():
- return process_time() - start
-
- yield lambda: elapser()
- spent = process_time() - start
-
- def elapser(): # NOQA
- return spent
-
-
-def retry_on_except(n=3):
- def wrapper(fn):
- def test_inner():
- for i in range(1, n + 1):
- try:
- checkCpuTime()
- fn()
- except SkipTest:
- if i >= n:
- raise
- else:
- return
-
- test_inner.__doc__ = fn.__doc__
- return test_inner
-
- return wrapper
-
-
-class MockIO(StringIO):
- """Wraps StringIO to mock a file with no I/O"""
-
- def write(self, data):
- return
-
-
-def simple_progress(iterable=None, total=None, file=sys.stdout, desc='',
- leave=False, miniters=1, mininterval=0.1, width=60):
- """Simple progress bar reproducing tqdm's major features"""
- n = [0] # use a closure
- start_t = [time()]
- last_n = [0]
- last_t = [0]
- if iterable is not None:
- total = len(iterable)
-
- def format_interval(t):
- mins, s = divmod(int(t), 60)
- h, m = divmod(mins, 60)
- if h:
- return '{0:d}:{1:02d}:{2:02d}'.format(h, m, s)
- else:
- return '{0:02d}:{1:02d}'.format(m, s)
-
- def update_and_print(i=1):
- n[0] += i
- if (n[0] - last_n[0]) >= miniters:
- last_n[0] = n[0]
-
- if (time() - last_t[0]) >= mininterval:
- last_t[0] = time() # last_t[0] == current time
-
- spent = last_t[0] - start_t[0]
- spent_fmt = format_interval(spent)
- rate = n[0] / spent if spent > 0 else 0
- if 0.0 < rate < 1.0:
- rate_fmt = "%.2fs/it" % (1.0 / rate)
- else:
- rate_fmt = "%.2fit/s" % rate
-
- frac = n[0] / total
- percentage = int(frac * 100)
- eta = (total - n[0]) / rate if rate > 0 else 0
- eta_fmt = format_interval(eta)
-
- # bar = "#" * int(frac * width)
- barfill = " " * int((1.0 - frac) * width)
- bar_length, frac_bar_length = divmod(int(frac * width * 10), 10)
- bar = '#' * bar_length
- frac_bar = chr(48 + frac_bar_length) if frac_bar_length \
- else ' '
-
- file.write("\r%s %i%%|%s%s%s| %i/%i [%s<%s, %s]" %
- (desc, percentage, bar, frac_bar, barfill, n[0],
- total, spent_fmt, eta_fmt, rate_fmt))
-
- if n[0] == total and leave:
- file.write("\n")
- file.flush()
-
- def update_and_yield():
- for elt in iterable:
- yield elt
- update_and_print()
-
- update_and_print(0)
- if iterable is not None:
- return update_and_yield()
- else:
- return update_and_print
-
-
-def assert_performance(thresh, name_left, time_left, name_right, time_right):
- """raises if time_left > thresh * time_right"""
- if time_left > thresh * time_right:
- raise ValueError(
- ('{name[0]}: {time[0]:f}, '
- '{name[1]}: {time[1]:f}, '
- 'ratio {ratio:f} > {thresh:f}').format(
- name=(name_left, name_right),
- time=(time_left, time_right),
- ratio=time_left / time_right, thresh=thresh))
-
-
-@with_setup(pretest, posttest)
-@retry_on_except()
-def test_iter_overhead():
- """Test overhead of iteration based tqdm"""
-
- total = int(1e6)
-
- with closing(MockIO()) as our_file:
- a = 0
- with trange(total, file=our_file) as t:
- with relative_timer() as time_tqdm:
- for i in t:
- a += i
- assert a == (total * total - total) / 2.0
-
- a = 0
- with relative_timer() as time_bench:
- for i in _range(total):
- a += i
- our_file.write(a)
-
- assert_performance(6, 'trange', time_tqdm(), 'range', time_bench())
-
-
-@with_setup(pretest, posttest)
-@retry_on_except()
-def test_manual_overhead():
- """Test overhead of manual tqdm"""
-
- total = int(1e6)
-
- with closing(MockIO()) as our_file:
- with tqdm(total=total * 10, file=our_file, leave=True) 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:
- for i in _range(total):
- a += i
- our_file.write(a)
-
- assert_performance(6, 'tqdm', time_tqdm(), 'range', time_bench())
-
-
-def worker(total, blocking=True):
- def incr_bar(x):
- with closing(StringIO()) as our_file:
- for _ in trange(
- total, file=our_file,
- lock_args=None if blocking else (False,),
- miniters=1, mininterval=0, maxinterval=0):
- pass
- return x + 1
- return incr_bar
-
-
-@with_setup(pretest, posttest)
-@retry_on_except()
-def test_lock_args():
- """Test overhead of nonblocking threads"""
- try:
- from concurrent.futures import ThreadPoolExecutor
- from threading import RLock
- except ImportError:
- raise SkipTest
- import sys
-
- total = 8
- subtotal = 1000
-
- tqdm.set_lock(RLock())
- with ThreadPoolExecutor(total) as pool:
- sys.stderr.write('block ... ')
- sys.stderr.flush()
- with relative_timer() as time_tqdm:
- res = list(pool.map(worker(subtotal, True), range(total)))
- assert sum(res) == sum(range(total)) + total
- sys.stderr.write('noblock ... ')
- sys.stderr.flush()
- with relative_timer() as time_noblock:
- res = list(pool.map(worker(subtotal, False), range(total)))
- assert sum(res) == sum(range(total)) + total
-
- assert_performance(0.2, 'noblock', time_noblock(), 'tqdm', time_tqdm())
-
-
-@with_setup(pretest, posttest)
-@retry_on_except()
-def test_iter_overhead_hard():
- """Test overhead of iteration based tqdm (hard)"""
-
- total = int(1e5)
-
- with closing(MockIO()) as our_file:
- a = 0
- with trange(total, file=our_file, leave=True, miniters=1,
- mininterval=0, maxinterval=0) as t:
- with relative_timer() as time_tqdm:
- for i in t:
- a += i
- assert a == (total * total - total) / 2.0
-
- a = 0
- with relative_timer() as time_bench:
- for i in _range(total):
- a += i
- our_file.write(("%i" % a) * 40)
-
- assert_performance(85, 'trange', time_tqdm(), 'range', time_bench())
-
-
-@with_setup(pretest, posttest)
-@retry_on_except()
-def test_manual_overhead_hard():
- """Test overhead of manual tqdm (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)
-
- a = 0
- with relative_timer() as time_bench:
- for i in _range(total):
- a += i
- our_file.write(("%i" % a) * 40)
-
- assert_performance(85, 'tqdm', time_tqdm(), 'range', time_bench())
-
-
-@with_setup(pretest, posttest)
-@retry_on_except()
-def test_iter_overhead_simplebar_hard():
- """Test overhead of iteration based tqdm vs simple progress bar (hard)"""
-
- total = int(1e4)
-
- with closing(MockIO()) as our_file:
- a = 0
- with trange(total, file=our_file, leave=True, miniters=1,
- mininterval=0, maxinterval=0) as t:
- with relative_timer() as time_tqdm:
- for i in t:
- a += i
- assert a == (total * total - total) / 2.0
-
- a = 0
- s = simple_progress(_range(total), file=our_file, leave=True,
- miniters=1, mininterval=0)
- with relative_timer() as time_bench:
- for i in s:
- a += i
-
- assert_performance(
- 5, 'trange', time_tqdm(), 'simple_progress', time_bench())
-
-
-@with_setup(pretest, posttest)
-@retry_on_except()
-def test_manual_overhead_simplebar_hard():
- """Test overhead of manual tqdm vs simple progress bar (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)
-
- simplebar_update = simple_progress(
- total=total * 10, file=our_file, leave=True, miniters=1,
- mininterval=0)
- a = 0
- with relative_timer() as time_bench:
- for i in _range(total):
- a += i
- simplebar_update(10)
-
- assert_performance(
- 5, 'tqdm', time_tqdm(), 'simple_progress', time_bench())
diff --git a/libs/tqdm/tests/tests_synchronisation.py b/libs/tqdm/tests/tests_synchronisation.py
deleted file mode 100644
index 34f682a58..000000000
--- a/libs/tqdm/tests/tests_synchronisation.py
+++ /dev/null
@@ -1,213 +0,0 @@
-from __future__ import division
-from tqdm import tqdm, trange, TMonitor
-from tests_tqdm import with_setup, pretest, posttest, SkipTest, \
- StringIO, closing
-from tests_tqdm import DiscreteTimer, cpu_timify
-from tests_perf import retry_on_except
-
-import sys
-from time import sleep
-from threading import Event
-
-
-class FakeSleep(object):
- """Wait until the discrete timer reached the required time"""
- def __init__(self, dtimer):
- self.dtimer = dtimer
-
- def sleep(self, t):
- end = t + self.dtimer.t
- while self.dtimer.t < end:
- sleep(0.0000001) # sleep a bit to interrupt (instead of pass)
-
-
-class FakeTqdm(object):
- _instances = []
-
-
-def make_create_fake_sleep_event(sleep):
- def wait(self, timeout=None):
- if timeout is not None:
- sleep(timeout)
- return self.is_set()
-
- def create_fake_sleep_event():
- event = Event()
- event.wait = wait
- return event
-
- return create_fake_sleep_event
-
-
-def incr(x):
- return x + 1
-
-
-def incr_bar(x):
- with closing(StringIO()) as our_file:
- for _ in trange(x, lock_args=(False,), file=our_file):
- pass
- return incr(x)
-
-
-@with_setup(pretest, posttest)
-def test_monitor_thread():
- """Test dummy monitoring thread"""
- maxinterval = 10
-
- # Setup a discrete timer
- timer = DiscreteTimer()
- TMonitor._time = timer.time
- # And a fake sleeper
- sleeper = FakeSleep(timer)
- TMonitor._event = make_create_fake_sleep_event(sleeper.sleep)
-
- # Instanciate the monitor
- monitor = TMonitor(FakeTqdm, maxinterval)
- # Test if alive, then killed
- assert monitor.report()
- monitor.exit()
- timer.sleep(maxinterval * 2) # need to go out of the sleep to die
- assert not monitor.report()
- # assert not monitor.is_alive() # not working dunno why, thread not killed
- del monitor
-
-
-@with_setup(pretest, posttest)
-def test_monitoring_and_cleanup():
- """Test for stalled tqdm instance and monitor deletion"""
- # Note: should fix miniters for these tests, else with dynamic_miniters
- # it's too complicated to handle with monitoring update and maxinterval...
- maxinterval = 2
-
- total = 1000
- # Setup a discrete timer
- timer = DiscreteTimer()
- # And a fake sleeper
- sleeper = FakeSleep(timer)
- # Setup TMonitor to use the timer
- TMonitor._time = timer.time
- TMonitor._event = make_create_fake_sleep_event(sleeper.sleep)
- # Set monitor interval
- tqdm.monitor_interval = maxinterval
- with closing(StringIO()) as our_file:
- with tqdm(total=total, file=our_file, miniters=500, mininterval=0.1,
- maxinterval=maxinterval) as t:
- cpu_timify(t, timer)
- # Do a lot of iterations in a small timeframe
- # (smaller than monitor interval)
- timer.sleep(maxinterval / 2) # monitor won't wake up
- t.update(500)
- # check that our fixed miniters is still there
- assert t.miniters == 500
- # Then do 1 it after monitor interval, so that monitor kicks in
- timer.sleep(maxinterval * 2)
- t.update(1)
- # Wait for the monitor to get out of sleep's loop and update tqdm..
- timeend = timer.time()
- while not (t.monitor.woken >= timeend and t.miniters == 1):
- timer.sleep(1) # Force monitor to wake up if it woken too soon
- sleep(0.000001) # sleep to allow interrupt (instead of pass)
- assert t.miniters == 1 # check that monitor corrected miniters
- # Note: at this point, there may be a race condition: monitor saved
- # current woken time but timer.sleep() happen just before monitor
- # sleep. To fix that, either sleep here or increase time in a loop
- # to ensure that monitor wakes up at some point.
-
- # Try again but already at miniters = 1 so nothing will be done
- timer.sleep(maxinterval * 2)
- t.update(2)
- timeend = timer.time()
- while t.monitor.woken < timeend:
- timer.sleep(1) # Force monitor to wake up if it woken too soon
- sleep(0.000001)
- # Wait for the monitor to get out of sleep's loop and update tqdm..
- assert t.miniters == 1 # check that monitor corrected miniters
-
- # Check that class var monitor is deleted if no instance left
- tqdm.monitor_interval = 10
- assert tqdm.monitor is None
-
-
-@with_setup(pretest, posttest)
-def test_monitoring_multi():
- """Test on multiple bars, one not needing miniters adjustment"""
- # Note: should fix miniters for these tests, else with dynamic_miniters
- # it's too complicated to handle with monitoring update and maxinterval...
- maxinterval = 2
-
- total = 1000
- # Setup a discrete timer
- timer = DiscreteTimer()
- # And a fake sleeper
- sleeper = FakeSleep(timer)
- # Setup TMonitor to use the timer
- TMonitor._time = timer.time
- TMonitor._event = make_create_fake_sleep_event(sleeper.sleep)
- # Set monitor interval
- tqdm.monitor_interval = maxinterval
- with closing(StringIO()) as our_file:
- with tqdm(total=total, file=our_file, miniters=500, mininterval=0.1,
- maxinterval=maxinterval) as t1:
- # Set high maxinterval for t2 so monitor does not need to adjust it
- with tqdm(total=total, file=our_file, miniters=500, mininterval=0.1,
- maxinterval=1E5) as t2:
- cpu_timify(t1, timer)
- cpu_timify(t2, timer)
- # Do a lot of iterations in a small timeframe
- timer.sleep(maxinterval / 2)
- t1.update(500)
- t2.update(500)
- assert t1.miniters == 500
- assert t2.miniters == 500
- # Then do 1 it after monitor interval, so that monitor kicks in
- timer.sleep(maxinterval * 2)
- t1.update(1)
- t2.update(1)
- # Wait for the monitor to get out of sleep and update tqdm
- timeend = timer.time()
- while not (t1.monitor.woken >= timeend and t1.miniters == 1):
- timer.sleep(1)
- sleep(0.000001)
- assert t1.miniters == 1 # check that monitor corrected miniters
- assert t2.miniters == 500 # check that t2 was not adjusted
-
- # Check that class var monitor is deleted if no instance left
- tqdm.monitor_interval = 10
- assert tqdm.monitor is None
-
-
-@with_setup(pretest, posttest)
-def test_imap():
- """Test multiprocessing.Pool"""
- try:
- from multiprocessing import Pool
- except ImportError:
- raise SkipTest
-
- pool = Pool()
- res = list(tqdm(pool.imap(incr, range(100)), disable=True))
- assert res[-1] == 100
-
-
-# py2: locks won't propagate to incr_bar so may cause `AttributeError`
-@retry_on_except(n=3 if sys.version_info < (3,) else 1)
-@with_setup(pretest, posttest)
-def test_threadpool():
- """Test concurrent.futures.ThreadPoolExecutor"""
- try:
- from concurrent.futures import ThreadPoolExecutor
- from threading import RLock
- except ImportError:
- raise SkipTest
-
- tqdm.set_lock(RLock())
- with ThreadPoolExecutor(8) as pool:
- try:
- res = list(tqdm(pool.map(incr_bar, range(100)), disable=True))
- except AttributeError:
- if sys.version_info < (3,):
- raise SkipTest
- else:
- raise
- assert sum(res) == sum(range(1, 101))
diff --git a/libs/tqdm/tests/tests_tqdm.py b/libs/tqdm/tests/tests_tqdm.py
deleted file mode 100644
index 5f322e61a..000000000
--- a/libs/tqdm/tests/tests_tqdm.py
+++ /dev/null
@@ -1,1966 +0,0 @@
-# -*- coding: utf-8 -*-
-# Advice: use repr(our_file.read()) to print the full output of tqdm
-# (else '\r' will replace the previous lines and you'll see only the latest.
-
-import sys
-import csv
-import re
-import os
-from nose import with_setup
-from nose.plugins.skip import SkipTest
-from nose.tools import assert_raises
-from nose.tools import eq_
-from contextlib import contextmanager
-from warnings import catch_warnings, simplefilter
-
-from tqdm import tqdm
-from tqdm import trange
-from tqdm import TqdmDeprecationWarning
-from tqdm.std import Bar
-from tqdm.contrib import DummyTqdmFile
-
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-from io import BytesIO
-from io import IOBase # to support unicode strings
-
-
-class DeprecationError(Exception):
- pass
-
-
-# Ensure we can use `with closing(...) as ... :` syntax
-if getattr(StringIO, '__exit__', False) and \
- getattr(StringIO, '__enter__', False):
- def closing(arg):
- return arg
-else:
- from contextlib import closing
-
-try:
- _range = xrange
-except NameError:
- _range = range
-
-try:
- _unicode = unicode
-except NameError:
- _unicode = str
-
-nt_and_no_colorama = False
-if os.name == 'nt':
- try:
- import colorama # NOQA
- except ImportError:
- nt_and_no_colorama = True
-
-# Regex definitions
-# List of control characters
-CTRLCHR = [r'\r', r'\n', r'\x1b\[A'] # Need to escape [ for regex
-# Regular expressions compilation
-RE_rate = re.compile(r'(\d+\.\d+)it/s')
-RE_ctrlchr = re.compile("(%s)" % '|'.join(CTRLCHR)) # Match control chars
-RE_ctrlchr_excl = re.compile('|'.join(CTRLCHR)) # Match and exclude ctrl chars
-RE_pos = re.compile(
- r'([\r\n]+((pos\d+) bar:\s+\d+%|\s{3,6})?[^\r\n]*)')
-
-
-def pos_line_diff(res_list, expected_list, raise_nonempty=True):
- """
- Return differences between two bar output lists.
- To be used with `RE_pos`
- """
- res = [(r, e) for r, e in zip(res_list, expected_list)
- for pos in [len(e) - len(e.lstrip('\n'))] # bar position
- if r != e # simple comparison
- if not r.startswith(e) # start matches
- or not (
- # move up at end (maybe less due to closing bars)
- any(r.endswith(end + i * '\x1b[A') for i in range(pos + 1)
- for end in [
- ']', # bar
- ' ']) # cleared
- or '100%' in r # completed bar
- or r == '\n') # final bar
- or r[(-1 - pos) * len('\x1b[A'):] == '\x1b[A'] # too many moves up
- if raise_nonempty and (res or len(res_list) != len(expected_list)):
- if len(res_list) < len(expected_list):
- res.extend([(None, e) for e in expected_list[len(res_list):]])
- elif len(res_list) > len(expected_list):
- res.extend([(r, None) for r in res_list[len(expected_list):]])
- raise AssertionError(
- "Got => Expected\n" + '\n'.join('%r => %r' % i for i in res))
- return res
-
-
-class DiscreteTimer(object):
- """Virtual discrete time manager, to precisely control time for tests"""
-
- def __init__(self):
- self.t = 0.0
-
- def sleep(self, t):
- """Sleep = increment the time counter (almost no CPU used)"""
- self.t += t
-
- def time(self):
- """Get the current time"""
- return self.t
-
-
-def cpu_timify(t, timer=None):
- """Force tqdm to use the specified timer instead of system-wide time()"""
- if timer is None:
- timer = DiscreteTimer()
- t._time = timer.time
- t._sleep = timer.sleep
- t.start_t = t.last_print_t = t._time()
- return timer
-
-
-def pretest():
- # setcheckinterval is deprecated
- try:
- sys.setswitchinterval(1)
- except AttributeError:
- sys.setcheckinterval(100)
-
- if getattr(tqdm, "_instances", False):
- n = len(tqdm._instances)
- if n:
- tqdm._instances.clear()
- raise EnvironmentError(
- "{0} `tqdm` instances still in existence PRE-test".format(n))
-
-
-def posttest():
- if getattr(tqdm, "_instances", False):
- n = len(tqdm._instances)
- if n:
- tqdm._instances.clear()
- raise EnvironmentError(
- "{0} `tqdm` instances still in existence POST-test".format(n))
-
-
-class UnicodeIO(IOBase):
- """Unicode version of StringIO"""
-
- def __init__(self, *args, **kwargs):
- super(UnicodeIO, self).__init__(*args, **kwargs)
- self.encoding = 'U8' # io.StringIO supports unicode, but no encoding
- self.text = ''
- self.cursor = 0
-
- def __len__(self):
- return len(self.text)
-
- def seek(self, offset):
- self.cursor = offset
-
- def tell(self):
- return self.cursor
-
- def write(self, s):
- self.text = self.text[:self.cursor] + s + \
- self.text[self.cursor + len(s):]
- self.cursor += len(s)
-
- def read(self, n=-1):
- _cur = self.cursor
- self.cursor = len(self) if n < 0 \
- else min(_cur + n, len(self))
- return self.text[_cur:self.cursor]
-
- def getvalue(self):
- return self.text
-
-
-def get_bar(all_bars, i=None):
- """Get a specific update from a whole bar traceback"""
- # Split according to any used control characters
- bars_split = RE_ctrlchr_excl.split(all_bars)
- bars_split = list(filter(None, bars_split)) # filter out empty splits
- return bars_split if i is None else bars_split[i]
-
-
-def progressbar_rate(bar_str):
- return float(RE_rate.search(bar_str).group(1))
-
-
-def squash_ctrlchars(s):
- """Apply control characters in a string just like a terminal display"""
- # Init variables
- curline = 0 # current line in our fake terminal
- lines = [''] # state of our fake terminal
-
- # Split input string by control codes
- s_split = RE_ctrlchr.split(s)
- s_split = filter(None, s_split) # filter out empty splits
-
- # For each control character or message
- for nextctrl in s_split:
- # If it's a control character, apply it
- if nextctrl == '\r':
- # Carriage return
- # Go to the beginning of the line
- # simplified here: we just empty the string
- lines[curline] = ''
- elif nextctrl == '\n':
- # Newline
- # Go to the next line
- if curline < (len(lines) - 1):
- # If already exists, just move cursor
- curline += 1
- else:
- # Else the new line is created
- lines.append('')
- curline += 1
- elif nextctrl == '\x1b[A':
- # Move cursor up
- if curline > 0:
- curline -= 1
- else:
- raise ValueError("Cannot go up, anymore!")
- # Else, it is a message, we print it on current line
- else:
- lines[curline] += nextctrl
-
- return lines
-
-
-def test_format_interval():
- """Test time interval format"""
- format_interval = tqdm.format_interval
-
- assert format_interval(60) == '01:00'
- assert format_interval(6160) == '1:42:40'
- 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:
- unich = unichr
- except NameError:
- unich = chr
-
- format_meter = tqdm.format_meter
-
- assert format_meter(0, 1000, 13) == \
- " 0%| | 0/1000 [00:13<?, ?it/s]"
- # If not implementing any changes to _tqdm.py, set prefix='desc'
- # or else ": : " will be in output, so assertion should change
- assert format_meter(0, 1000, 13, ncols=68, prefix='desc: ') == \
- "desc: 0%| | 0/1000 [00:13<?, ?it/s]"
- assert format_meter(231, 1000, 392) == \
- " 23%|" + unich(0x2588) * 2 + unich(0x258e) + \
- " | 231/1000 [06:32<21:44, 1.70s/it]"
- assert format_meter(10000, 1000, 13) == \
- "10000it [00:13, 769.23it/s]"
- assert format_meter(231, 1000, 392, ncols=56, ascii=True) == \
- " 23%|" + '#' * 3 + '6' + \
- " | 231/1000 [06:32<21:44, 1.70s/it]"
- assert format_meter(100000, 1000, 13, unit_scale=True, unit='iB') == \
- "100kiB [00:13, 7.69kiB/s]"
- assert format_meter(100, 1000, 12, ncols=0, rate=7.33) == \
- " 10% 100/1000 [00:12<02:02, 7.33it/s]"
- eq_(
- # ncols is small, l_bar is too large
- # l_bar gets chopped
- # no bar
- # no r_bar
- format_meter(
- 0, 1000, 13, ncols=10,
- bar_format="************{bar:10}$$$$$$$$$$"),
- "**********" # 10/12 stars since ncols is 10
- )
- eq_(
- # n_cols allows for l_bar and some of bar
- # l_bar displays
- # bar gets chopped
- # no r_bar
- format_meter(
- 0, 1000, 13, ncols=20,
- bar_format="************{bar:10}$$$$$$$$$$"),
- "************ " # all 12 stars and 8/10 bar parts
- )
- eq_(
- # n_cols allows for l_bar, bar, and some of r_bar
- # l_bar displays
- # bar displays
- # r_bar gets chopped
- format_meter(
- 0, 1000, 13, ncols=30,
- bar_format="************{bar:10}$$$$$$$$$$"),
- "************ $$$$$$$$"
- # all 12 stars and 10 bar parts, but only 8/10 dollar signs
- )
- eq_(
- # trim left ANSI; escape is before trim zone
- format_meter(
- 0, 1000, 13, ncols=10,
- bar_format="*****\033[22m****\033[0m***{bar:10}$$$$$$$$$$"),
- "*****\033[22m****\033[0m*\033[0m"
- # we only know it has ANSI codes, so we append an END code anyway
- )
- eq_(
- # trim left ANSI; escape is at trim zone
- format_meter(
- 0, 1000, 13, ncols=10,
- bar_format="*****\033[22m*****\033[0m**{bar:10}$$$$$$$$$$"),
- "*****\033[22m*****\033[0m"
- )
- eq_(
- # trim left ANSI; escape is after trim zone
- format_meter(
- 0, 1000, 13, ncols=10,
- bar_format="*****\033[22m******\033[0m*{bar:10}$$$$$$$$$$"),
- "*****\033[22m*****\033[0m"
- )
- # Check that bar_format correctly adapts {bar} size to the rest
- assert format_meter(20, 100, 12, ncols=13, rate=8.1,
- bar_format=r'{l_bar}{bar}|{n_fmt}/{total_fmt}') == \
- " 20%|" + unich(0x258f) + "|20/100"
- assert format_meter(20, 100, 12, ncols=14, rate=8.1,
- bar_format=r'{l_bar}{bar}|{n_fmt}/{total_fmt}') == \
- " 20%|" + unich(0x258d) + " |20/100"
- # Check wide characters
- if sys.version_info >= (3,):
- assert format_meter(0, 1000, 13, ncols=68, prefix='fullwidth: ') == \
- "fullwidth: 0%| | 0/1000 [00:13<?, ?it/s]"
- assert format_meter(0, 1000, 13, ncols=68, prefix='ニッポン [ニッポン]: ') == \
- "ニッポン [ニッポン]: 0%| | 0/1000 [00:13<?, ?it/s]"
- # Check that bar_format can print only {bar} or just one side
- assert format_meter(20, 100, 12, ncols=2, rate=8.1,
- bar_format=r'{bar}') == \
- unich(0x258d) + " "
- assert format_meter(20, 100, 12, ncols=7, rate=8.1,
- bar_format=r'{l_bar}{bar}') == \
- " 20%|" + unich(0x258d) + " "
- assert format_meter(20, 100, 12, ncols=6, rate=8.1,
- bar_format=r'{bar}|test') == \
- unich(0x258f) + "|test"
-
-
-def test_ansi_escape_codes():
- """Test stripping of ANSI escape codes"""
- ansi = dict(BOLD='\033[1m', RED='\033[91m', END='\033[0m')
- desc_raw = '{BOLD}{RED}Colored{END} description'
- ncols = 123
-
- desc_stripped = desc_raw.format(BOLD='', RED='', END='')
- meter = tqdm.format_meter(0, 100, 0, ncols=ncols, prefix=desc_stripped)
- assert len(meter) == ncols
-
- desc = desc_raw.format(**ansi)
- meter = tqdm.format_meter(0, 100, 0, ncols=ncols, prefix=desc)
- # `format_meter` inserts an extra END for safety
- ansi_len = len(desc) - len(desc_stripped) + len(ansi['END'])
- assert len(meter) == ncols + ansi_len
-
-
-def test_si_format():
- """Test SI unit prefixes"""
- format_meter = tqdm.format_meter
-
- assert '9.00 ' in format_meter(1, 9, 1, unit_scale=True, unit='B')
- assert '99.0 ' in format_meter(1, 99, 1, unit_scale=True)
- assert '999 ' in format_meter(1, 999, 1, unit_scale=True)
- assert '9.99k ' in format_meter(1, 9994, 1, unit_scale=True)
- assert '10.0k ' in format_meter(1, 9999, 1, unit_scale=True)
- assert '99.5k ' in format_meter(1, 99499, 1, unit_scale=True)
- assert '100k ' in format_meter(1, 99999, 1, unit_scale=True)
- assert '1.00M ' in format_meter(1, 999999, 1, unit_scale=True)
- assert '1.00G ' in format_meter(1, 999999999, 1, unit_scale=True)
- assert '1.00T ' in format_meter(1, 999999999999, 1, unit_scale=True)
- assert '1.00P ' in format_meter(1, 999999999999999, 1, unit_scale=True)
- assert '1.00E ' in format_meter(1, 999999999999999999, 1, unit_scale=True)
- assert '1.00Z ' in format_meter(1, 999999999999999999999, 1,
- unit_scale=True)
- assert '1.0Y ' in format_meter(1, 999999999999999999999999, 1,
- unit_scale=True)
- assert '10.0Y ' in format_meter(1, 9999999999999999999999999, 1,
- unit_scale=True)
- assert '100.0Y ' in format_meter(1, 99999999999999999999999999, 1,
- unit_scale=True)
- assert '1000.0Y ' in format_meter(1, 999999999999999999999999999, 1,
- unit_scale=True)
-
-
-def test_bar_formatspec():
- """Test Bar.__format__ spec"""
- assert "{0:5a}".format(Bar(0.3)) == "#5 "
- assert "{0:2}".format(Bar(0.5, charset=" .oO0")) == "0 "
- assert "{0:2a}".format(Bar(0.5, charset=" .oO0")) == "# "
- assert "{0:-6a}".format(Bar(0.5, 10)) == '## '
- assert "{0:2b}".format(Bar(0.5, 10)) == ' '
-
-
-@with_setup(pretest, posttest)
-def test_all_defaults():
- """Test default kwargs"""
- with closing(UnicodeIO()) as our_file:
- with tqdm(range(10), file=our_file) as progressbar:
- assert len(progressbar) == 10
- for _ in progressbar:
- pass
- # restore stdout/stderr output for `nosetest` interface
- # try:
- # sys.stderr.write('\x1b[A')
- # except:
- # pass
- sys.stderr.write('\rTest default kwargs ... ')
-
-
-class WriteTypeChecker(BytesIO):
- """File-like to assert the expected type is written"""
- def __init__(self, expected_type):
- super(WriteTypeChecker, self).__init__()
- self.expected_type = expected_type
-
- def write(self, s):
- assert isinstance(s, self.expected_type)
-
-
-@with_setup(pretest, posttest)
-def test_native_string_io_for_default_file():
- """Native strings written to unspecified files"""
- stderr = sys.stderr
- try:
- sys.stderr = WriteTypeChecker(expected_type=type(''))
- for _ in tqdm(range(3)):
- pass
- sys.stderr.encoding = None # py2 behaviour
- for _ in tqdm(range(3)):
- pass
- finally:
- sys.stderr = stderr
-
-
-@with_setup(pretest, posttest)
-def test_unicode_string_io_for_specified_file():
- """Unicode strings written to specified files"""
- for _ in tqdm(range(3), file=WriteTypeChecker(expected_type=type(u''))):
- pass
-
-
-@with_setup(pretest, posttest)
-def test_write_bytes():
- """Test write_bytes argument with and without `file`"""
- # specified file (and bytes)
- for _ in tqdm(range(3), file=WriteTypeChecker(expected_type=type(b'')),
- write_bytes=True):
- pass
- # unspecified file (and unicode)
- stderr = sys.stderr
- try:
- sys.stderr = WriteTypeChecker(expected_type=type(u''))
- for _ in tqdm(range(3), write_bytes=False):
- pass
- finally:
- sys.stderr = stderr
-
-
-@with_setup(pretest, posttest)
-def test_iterate_over_csv_rows():
- """Test csv iterator"""
- # Create a test csv pseudo file
- with closing(StringIO()) as test_csv_file:
- writer = csv.writer(test_csv_file)
- for _ in _range(3):
- writer.writerow(['test'] * 3)
- test_csv_file.seek(0)
-
- # Test that nothing fails if we iterate over rows
- reader = csv.DictReader(test_csv_file,
- fieldnames=('row1', 'row2', 'row3'))
- with closing(StringIO()) as our_file:
- for _ in tqdm(reader, file=our_file):
- pass
-
-
-@with_setup(pretest, posttest)
-def test_file_output():
- """Test output to arbitrary file-like objects"""
- with closing(StringIO()) as our_file:
- for i in tqdm(_range(3), file=our_file):
- if i == 1:
- our_file.seek(0)
- assert '0/3' in our_file.read()
-
-
-@with_setup(pretest, posttest)
-def test_leave_option():
- """Test `leave=True` always prints info about the last iteration"""
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(3), file=our_file, leave=True):
- pass
- res = our_file.getvalue()
- assert '| 3/3 ' in res
- assert '\n' == res[-1] # not '\r'
-
- with closing(StringIO()) as our_file2:
- for _ in tqdm(_range(3), file=our_file2, leave=False):
- pass
- assert '| 3/3 ' not in our_file2.getvalue()
-
-
-@with_setup(pretest, posttest)
-def test_trange():
- """Test trange"""
- with closing(StringIO()) as our_file:
- for _ in trange(3, file=our_file, leave=True):
- pass
- assert '| 3/3 ' in our_file.getvalue()
-
- with closing(StringIO()) as our_file2:
- for _ in trange(3, file=our_file2, leave=False):
- pass
- assert '| 3/3 ' not in our_file2.getvalue()
-
-
-@with_setup(pretest, posttest)
-def test_min_interval():
- """Test mininterval"""
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(3), file=our_file, mininterval=1e-10):
- pass
- assert " 0%| | 0/3 [00:00<" in our_file.getvalue()
-
-
-@with_setup(pretest, posttest)
-def test_max_interval():
- """Test maxinterval"""
- total = 100
- bigstep = 10
- smallstep = 5
-
- # Test without maxinterval
- timer = DiscreteTimer()
- with closing(StringIO()) as our_file:
- with closing(StringIO()) as our_file2:
- # with maxinterval but higher than loop sleep time
- t = tqdm(total=total, file=our_file, miniters=None, mininterval=0,
- smoothing=1, maxinterval=1e-2)
- cpu_timify(t, timer)
-
- # without maxinterval
- t2 = tqdm(total=total, file=our_file2, miniters=None, mininterval=0,
- smoothing=1, maxinterval=None)
- cpu_timify(t2, timer)
-
- assert t.dynamic_miniters
- assert t2.dynamic_miniters
-
- # Increase 10 iterations at once
- t.update(bigstep)
- t2.update(bigstep)
- # The next iterations should not trigger maxinterval (step 10)
- for _ in _range(4):
- t.update(smallstep)
- t2.update(smallstep)
- timer.sleep(1e-5)
- t.close() # because PyPy doesn't gc immediately
- t2.close() # as above
-
- assert "25%" not in our_file2.getvalue()
- assert "25%" not in our_file.getvalue()
-
- # Test with maxinterval effect
- timer = DiscreteTimer()
- with closing(StringIO()) as our_file:
- with tqdm(total=total, file=our_file, miniters=None, mininterval=0,
- smoothing=1, maxinterval=1e-4) as t:
- cpu_timify(t, timer)
-
- # Increase 10 iterations at once
- t.update(bigstep)
- # The next iterations should trigger maxinterval (step 5)
- for _ in _range(4):
- t.update(smallstep)
- timer.sleep(1e-2)
-
- assert "25%" in our_file.getvalue()
-
- # Test iteration based tqdm with maxinterval effect
- timer = DiscreteTimer()
- with closing(StringIO()) as our_file:
- with tqdm(_range(total), file=our_file, miniters=None,
- mininterval=1e-5, smoothing=1, maxinterval=1e-4) as t2:
- cpu_timify(t2, timer)
-
- for i in t2:
- if i >= (bigstep - 1) and \
- ((i - (bigstep - 1)) % smallstep) == 0:
- timer.sleep(1e-2)
- if i >= 3 * bigstep:
- break
-
- assert "15%" in our_file.getvalue()
-
- # Test different behavior with and without mininterval
- timer = DiscreteTimer()
- total = 1000
- mininterval = 0.1
- maxinterval = 10
- with closing(StringIO()) as our_file:
- with tqdm(total=total, file=our_file, miniters=None, smoothing=1,
- mininterval=mininterval, maxinterval=maxinterval) as tm1:
- with tqdm(total=total, file=our_file, miniters=None, smoothing=1,
- mininterval=0, maxinterval=maxinterval) as tm2:
-
- cpu_timify(tm1, timer)
- cpu_timify(tm2, timer)
-
- # Fast iterations, check if dynamic_miniters triggers
- timer.sleep(mininterval) # to force update for t1
- tm1.update(total / 2)
- tm2.update(total / 2)
- assert int(tm1.miniters) == tm2.miniters == total / 2
-
- # Slow iterations, check different miniters if mininterval
- timer.sleep(maxinterval * 2)
- tm1.update(total / 2)
- tm2.update(total / 2)
- res = [tm1.miniters, tm2.miniters]
- assert res == [(total / 2) * mininterval / (maxinterval * 2),
- (total / 2) * maxinterval / (maxinterval * 2)]
-
- # Same with iterable based tqdm
- timer1 = DiscreteTimer() # need 2 timers for each bar because zip not work
- timer2 = DiscreteTimer()
- total = 100
- mininterval = 0.1
- maxinterval = 10
- with closing(StringIO()) as our_file:
- t1 = tqdm(_range(total), file=our_file, miniters=None, smoothing=1,
- mininterval=mininterval, maxinterval=maxinterval)
- t2 = tqdm(_range(total), file=our_file, miniters=None, smoothing=1,
- mininterval=0, maxinterval=maxinterval)
-
- cpu_timify(t1, timer1)
- cpu_timify(t2, timer2)
-
- for i in t1:
- if i == ((total / 2) - 2):
- timer1.sleep(mininterval)
- if i == (total - 1):
- timer1.sleep(maxinterval * 2)
-
- for i in t2:
- if i == ((total / 2) - 2):
- timer2.sleep(mininterval)
- if i == (total - 1):
- timer2.sleep(maxinterval * 2)
-
- assert t1.miniters == 0.255
- assert t2.miniters == 0.5
-
- t1.close()
- t2.close()
-
-
-@with_setup(pretest, posttest)
-def test_min_iters():
- """Test miniters"""
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(3), file=our_file, leave=True, miniters=4):
- our_file.write('blank\n')
- assert '\nblank\nblank\n' in our_file.getvalue()
-
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(3), file=our_file, leave=True, miniters=1):
- our_file.write('blank\n')
- # assume automatic mininterval = 0 means intermediate output
- assert '| 3/3 ' in our_file.getvalue()
-
-
-@with_setup(pretest, posttest)
-def test_dynamic_min_iters():
- """Test purely dynamic miniters (and manual updates and __del__)"""
- with closing(StringIO()) as our_file:
- total = 10
- t = tqdm(total=total, file=our_file, miniters=None, mininterval=0,
- smoothing=1)
-
- t.update()
- # Increase 3 iterations
- t.update(3)
- # The next two iterations should be skipped because of dynamic_miniters
- t.update()
- t.update()
- # The third iteration should be displayed
- t.update()
-
- out = our_file.getvalue()
- assert t.dynamic_miniters
- t.__del__() # simulate immediate del gc
-
- assert ' 0%| | 0/10 [00:00<' in out
- assert '40%' in out
- assert '50%' not in out
- assert '60%' not in out
- assert '70%' in out
-
- # Check with smoothing=0, miniters should be set to max update seen so far
- with closing(StringIO()) as our_file:
- total = 10
- t = tqdm(total=total, file=our_file, miniters=None, mininterval=0,
- smoothing=0)
-
- t.update()
- t.update(2)
- t.update(5) # this should be stored as miniters
- t.update(1)
-
- out = our_file.getvalue()
- assert all(i in out for i in ("0/10", "1/10", "3/10"))
- assert "2/10" not in out
- assert t.dynamic_miniters and not t.smoothing
- assert t.miniters == 5
- t.close()
-
- # Check iterable based tqdm
- with closing(StringIO()) as our_file:
- t = tqdm(_range(10), file=our_file, miniters=None, mininterval=None,
- smoothing=0.5)
- for _ in t:
- pass
- assert t.dynamic_miniters
-
- # No smoothing
- with closing(StringIO()) as our_file:
- t = tqdm(_range(10), file=our_file, miniters=None, mininterval=None,
- smoothing=0)
- for _ in t:
- pass
- assert t.dynamic_miniters
-
- # No dynamic_miniters (miniters is fixed manually)
- with closing(StringIO()) as our_file:
- t = tqdm(_range(10), file=our_file, miniters=1, mininterval=None)
- for _ in t:
- pass
- assert not t.dynamic_miniters
-
-
-@with_setup(pretest, posttest)
-def test_big_min_interval():
- """Test large mininterval"""
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(2), file=our_file, mininterval=1E10):
- pass
- assert '50%' not in our_file.getvalue()
-
- with closing(StringIO()) as our_file:
- with tqdm(_range(2), file=our_file, mininterval=1E10) as t:
- t.update()
- t.update()
- assert '50%' not in our_file.getvalue()
-
-
-@with_setup(pretest, posttest)
-def test_smoothed_dynamic_min_iters():
- """Test smoothed dynamic miniters"""
- timer = DiscreteTimer()
-
- with closing(StringIO()) as our_file:
- with tqdm(total=100, file=our_file, miniters=None, mininterval=0,
- smoothing=0.5, maxinterval=0) as t:
- cpu_timify(t, timer)
-
- # Increase 10 iterations at once
- t.update(10)
- # The next iterations should be partially skipped
- for _ in _range(2):
- t.update(4)
- for _ in _range(20):
- t.update()
-
- out = our_file.getvalue()
- assert t.dynamic_miniters
- assert ' 0%| | 0/100 [00:00<' in out
- assert '10%' in out
- assert '14%' not in out
- assert '18%' in out
- assert '20%' not in out
- assert '25%' in out
- assert '30%' not in out
- assert '32%' in out
-
-
-@with_setup(pretest, posttest)
-def test_smoothed_dynamic_min_iters_with_min_interval():
- """Test smoothed dynamic miniters with mininterval"""
- timer = DiscreteTimer()
-
- # In this test, `miniters` should gradually decline
- total = 100
-
- with closing(StringIO()) as our_file:
- # Test manual updating tqdm
- with tqdm(total=total, file=our_file, miniters=None, mininterval=1e-3,
- smoothing=1, maxinterval=0) as t:
- cpu_timify(t, timer)
-
- t.update(10)
- timer.sleep(1e-2)
- for _ in _range(4):
- t.update()
- timer.sleep(1e-2)
- out = our_file.getvalue()
- assert t.dynamic_miniters
-
- with closing(StringIO()) as our_file:
- # Test iteration-based tqdm
- with tqdm(_range(total), file=our_file, miniters=None,
- mininterval=0.01, smoothing=1, maxinterval=0) as t2:
- cpu_timify(t2, timer)
-
- for i in t2:
- if i >= 10:
- timer.sleep(0.1)
- if i >= 14:
- break
- out2 = our_file.getvalue()
-
- assert t.dynamic_miniters
- assert ' 0%| | 0/100 [00:00<' in out
- assert '11%' in out and '11%' in out2
- # assert '12%' not in out and '12%' in out2
- assert '13%' in out and '13%' in out2
- assert '14%' in out and '14%' in out2
-
-
-@with_setup(pretest, posttest)
-def test_rlock_creation():
- """Test that importing tqdm does not create multiprocessing objects."""
- import multiprocessing as mp
- if sys.version_info < (3, 3):
- # unittest.mock is a 3.3+ feature
- raise SkipTest
-
- # Use 'spawn' instead of 'fork' so that the process does not inherit any
- # globals that have been constructed by running other tests
- ctx = mp.get_context('spawn')
- with ctx.Pool(1) as pool:
- # The pool will propagate the error if the target method fails
- pool.apply(_rlock_creation_target)
-
-
-def _rlock_creation_target():
- """Check that the RLock has not been constructed."""
- from unittest.mock import patch
- import multiprocessing as mp
-
- # Patch the RLock class/method but use the original implementation
- with patch('multiprocessing.RLock', wraps=mp.RLock) as rlock_mock:
- # Importing the module should not create a lock
- from tqdm import tqdm
- assert rlock_mock.call_count == 0
- # Creating a progress bar should initialize the lock
- with closing(StringIO()) as our_file:
- with tqdm(file=our_file) as _: # NOQA
- pass
- assert rlock_mock.call_count == 1
- # Creating a progress bar again should reuse the lock
- with closing(StringIO()) as our_file:
- with tqdm(file=our_file) as _: # NOQA
- pass
- assert rlock_mock.call_count == 1
-
-
-@with_setup(pretest, posttest)
-def test_disable():
- """Test disable"""
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(3), file=our_file, disable=True):
- pass
- assert our_file.getvalue() == ''
-
- with closing(StringIO()) as our_file:
- progressbar = tqdm(total=3, file=our_file, miniters=1, disable=True)
- progressbar.update(3)
- progressbar.close()
- assert our_file.getvalue() == ''
-
-
-@with_setup(pretest, posttest)
-def test_infinite_total():
- """Test treatment of infinite total"""
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(3), file=our_file, total=float("inf")):
- pass
-
-
-@with_setup(pretest, posttest)
-def test_nototal():
- """Test unknown total length"""
- with closing(StringIO()) as our_file:
- for i in tqdm((i for i in range(10)), file=our_file, unit_scale=10):
- pass
- assert "100it" in our_file.getvalue()
-
- with closing(StringIO()) as our_file:
- for i in tqdm((i for i in range(10)), file=our_file,
- bar_format="{l_bar}{bar}{r_bar}"):
- pass
- assert "10/?" in our_file.getvalue()
-
-
-@with_setup(pretest, posttest)
-def test_unit():
- """Test SI unit prefix"""
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(3), file=our_file, miniters=1, unit="bytes"):
- pass
- assert 'bytes/s' in our_file.getvalue()
-
-
-@with_setup(pretest, posttest)
-def test_ascii():
- """Test ascii/unicode bar"""
- # Test ascii autodetection
- with closing(StringIO()) as our_file:
- with tqdm(total=10, file=our_file, ascii=None) as t:
- assert t.ascii # TODO: this may fail in the future
-
- # Test ascii bar
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(3), total=15, file=our_file, miniters=1,
- mininterval=0, ascii=True):
- pass
- res = our_file.getvalue().strip("\r").split("\r")
- assert '7%|6' in res[1]
- assert '13%|#3' in res[2]
- assert '20%|##' in res[3]
-
- # Test unicode bar
- with closing(UnicodeIO()) as our_file:
- with tqdm(total=15, file=our_file, ascii=False, mininterval=0) as t:
- for _ in _range(3):
- t.update()
- res = our_file.getvalue().strip("\r").split("\r")
- assert u"7%|\u258b" in res[1]
- assert u"13%|\u2588\u258e" in res[2]
- assert u"20%|\u2588\u2588" in res[3]
-
- # Test custom bar
- for ascii in [" .oO0", " #"]:
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(len(ascii) - 1), file=our_file, miniters=1,
- mininterval=0, ascii=ascii, ncols=27):
- pass
- res = our_file.getvalue().strip("\r").split("\r")
- for bar, line in zip(ascii, res):
- assert '|' + bar + '|' in line
-
-
-@with_setup(pretest, posttest)
-def test_update():
- """Test manual creation and updates"""
- res = None
- with closing(StringIO()) as our_file:
- with tqdm(total=2, file=our_file, miniters=1, mininterval=0) \
- as progressbar:
- assert len(progressbar) == 2
- progressbar.update(2)
- assert '| 2/2' in our_file.getvalue()
- progressbar.desc = 'dynamically notify of 4 increments in total'
- progressbar.total = 4
- progressbar.update(-1)
- progressbar.update(2)
- res = our_file.getvalue()
- assert '| 3/4 ' in res
- assert 'dynamically notify of 4 increments in total' in res
-
-
-@with_setup(pretest, posttest)
-def test_close():
- """Test manual creation and closure and n_instances"""
-
- # With `leave` option
- with closing(StringIO()) as our_file:
- progressbar = tqdm(total=3, file=our_file, miniters=10)
- progressbar.update(3)
- assert '| 3/3 ' not in our_file.getvalue() # Should be blank
- assert len(tqdm._instances) == 1
- progressbar.close()
- assert len(tqdm._instances) == 0
- assert '| 3/3 ' in our_file.getvalue()
-
- # Without `leave` option
- with closing(StringIO()) as our_file:
- progressbar = tqdm(total=3, file=our_file, miniters=10, leave=False)
- progressbar.update(3)
- progressbar.close()
- assert '| 3/3 ' not in our_file.getvalue() # Should be blank
-
- # With all updates
- with closing(StringIO()) as our_file:
- assert len(tqdm._instances) == 0
- with tqdm(total=3, file=our_file, miniters=0, mininterval=0,
- leave=True) as progressbar:
- assert len(tqdm._instances) == 1
- progressbar.update(3)
- res = our_file.getvalue()
- assert '| 3/3 ' in res # Should be blank
- assert '\n' not in res
- # close() called
- assert len(tqdm._instances) == 0
-
- exres = res.rsplit(', ', 1)[0]
- res = our_file.getvalue()
- assert res[-1] == '\n'
- if not res.startswith(exres):
- raise AssertionError(
- "\n<<< Expected:\n{0}\n>>> Got:\n{1}\n===".format(
- exres + ', ...it/s]\n', our_file.getvalue()))
-
- # Closing after the output stream has closed
- with closing(StringIO()) as our_file:
- t = tqdm(total=2, file=our_file)
- t.update()
- t.update()
- t.close()
-
-
-@with_setup(pretest, posttest)
-def test_smoothing():
- """Test exponential weighted average smoothing"""
- timer = DiscreteTimer()
-
- # -- Test disabling smoothing
- with closing(StringIO()) as our_file:
- with tqdm(_range(3), file=our_file, smoothing=None, leave=True) as t:
- cpu_timify(t, timer)
-
- for _ in t:
- pass
- assert '| 3/3 ' in our_file.getvalue()
-
- # -- Test smoothing
- # Compile the regex to find the rate
- # 1st case: no smoothing (only use average)
- with closing(StringIO()) as our_file2:
- with closing(StringIO()) as our_file:
- t = tqdm(_range(3), file=our_file2, smoothing=None, leave=True,
- miniters=1, mininterval=0)
- cpu_timify(t, timer)
-
- with tqdm(_range(3), file=our_file, smoothing=None, leave=True,
- miniters=1, mininterval=0) as t2:
- cpu_timify(t2, timer)
-
- for i in t2:
- # Sleep more for first iteration and
- # see how quickly rate is updated
- if i == 0:
- timer.sleep(0.01)
- else:
- # Need to sleep in all iterations
- # to calculate smoothed rate
- # (else delta_t is 0!)
- timer.sleep(0.001)
- t.update()
- n_old = len(tqdm._instances)
- t.close()
- assert len(tqdm._instances) == n_old - 1
- # Get result for iter-based bar
- a = progressbar_rate(get_bar(our_file.getvalue(), 3))
- # Get result for manually updated bar
- a2 = progressbar_rate(get_bar(our_file2.getvalue(), 3))
-
- # 2nd case: use max smoothing (= instant rate)
- with closing(StringIO()) as our_file2:
- with closing(StringIO()) as our_file:
- t = tqdm(_range(3), file=our_file2, smoothing=1, leave=True,
- miniters=1, mininterval=0)
- cpu_timify(t, timer)
-
- with tqdm(_range(3), file=our_file, smoothing=1, leave=True,
- miniters=1, mininterval=0) as t2:
- cpu_timify(t2, timer)
-
- for i in t2:
- if i == 0:
- timer.sleep(0.01)
- else:
- timer.sleep(0.001)
- t.update()
- t.close()
- # Get result for iter-based bar
- b = progressbar_rate(get_bar(our_file.getvalue(), 3))
- # Get result for manually updated bar
- b2 = progressbar_rate(get_bar(our_file2.getvalue(), 3))
-
- # 3rd case: use medium smoothing
- with closing(StringIO()) as our_file2:
- with closing(StringIO()) as our_file:
- t = tqdm(_range(3), file=our_file2, smoothing=0.5, leave=True,
- miniters=1, mininterval=0)
- cpu_timify(t, timer)
-
- t2 = tqdm(_range(3), file=our_file, smoothing=0.5, leave=True,
- miniters=1, mininterval=0)
- cpu_timify(t2, timer)
-
- for i in t2:
- if i == 0:
- timer.sleep(0.01)
- else:
- timer.sleep(0.001)
- t.update()
- t2.close()
- t.close()
- # Get result for iter-based bar
- c = progressbar_rate(get_bar(our_file.getvalue(), 3))
- # Get result for manually updated bar
- c2 = progressbar_rate(get_bar(our_file2.getvalue(), 3))
-
- # Check that medium smoothing's rate is between no and max smoothing rates
- assert a <= c <= b
- assert a2 <= c2 <= b2
-
-
-@with_setup(pretest, posttest)
-def test_deprecated_nested():
- """Test nested progress bars"""
- if nt_and_no_colorama:
- raise SkipTest
- # TODO: test degradation on windows without colorama?
-
- # Artificially test nested loop printing
- # Without leave
- our_file = StringIO()
- try:
- tqdm(total=2, file=our_file, nested=True)
- except TqdmDeprecationWarning:
- if """`nested` is deprecated and automated.
-Use `position` instead for manual control.""" not in our_file.getvalue():
- raise
- else:
- raise DeprecationError("Should not allow nested kwarg")
-
-
-@with_setup(pretest, posttest)
-def test_bar_format():
- """Test custom bar formatting"""
- with closing(StringIO()) as our_file:
- bar_format = r'{l_bar}{bar}|{n_fmt}/{total_fmt}-{n}/{total}{percentage}{rate}{rate_fmt}{elapsed}{remaining}' # NOQA
- for _ in trange(2, file=our_file, leave=True, bar_format=bar_format):
- pass
- out = our_file.getvalue()
- assert "\r 0%| |0/2-0/20.0None?it/s00:00?\r" in out
-
- # Test unicode string auto conversion
- with closing(StringIO()) as our_file:
- bar_format = r'hello world'
- with tqdm(ascii=False, bar_format=bar_format, file=our_file) as t:
- assert isinstance(t.bar_format, _unicode)
-
-
-@with_setup(pretest, posttest)
-def test_custom_format():
- """Test adding additional derived format arguments"""
- class TqdmExtraFormat(tqdm):
- """Provides a `total_time` format parameter"""
- @property
- def format_dict(self):
- d = super(TqdmExtraFormat, self).format_dict
- total_time = d["elapsed"] * (d["total"] or 0) / max(d["n"], 1)
- d.update(total_time=self.format_interval(total_time) + " in total")
- return d
-
- with closing(StringIO()) as our_file:
- for i in TqdmExtraFormat(
- range(10), file=our_file,
- bar_format="{total_time}: {percentage:.0f}%|{bar}{r_bar}"):
- pass
- assert "00:00 in total" in our_file.getvalue()
-
-
-@with_setup(pretest, posttest)
-def test_unpause():
- """Test unpause"""
- timer = DiscreteTimer()
- with closing(StringIO()) as our_file:
- t = trange(10, file=our_file, leave=True, mininterval=0)
- cpu_timify(t, timer)
- timer.sleep(0.01)
- t.update()
- timer.sleep(0.01)
- t.update()
- timer.sleep(0.1) # longer wait time
- t.unpause()
- timer.sleep(0.01)
- t.update()
- timer.sleep(0.01)
- t.update()
- t.close()
- r_before = progressbar_rate(get_bar(our_file.getvalue(), 2))
- r_after = progressbar_rate(get_bar(our_file.getvalue(), 3))
- assert r_before == r_after
-
-
-@with_setup(pretest, posttest)
-def test_reset():
- """Test resetting a bar for re-use"""
- with closing(StringIO()) as our_file:
- with tqdm(total=10, file=our_file,
- miniters=1, mininterval=0, maxinterval=0) as t:
- t.update(9)
- t.reset()
- t.update()
- t.reset(total=12)
- t.update(10)
- assert '| 1/10' in our_file.getvalue()
- assert '| 10/12' in our_file.getvalue()
-
-
-@with_setup(pretest, posttest)
-def test_position():
- """Test positioned progress bars"""
- if nt_and_no_colorama:
- raise SkipTest
-
- # Artificially test nested loop printing
- # Without leave
- our_file = StringIO()
- kwargs = dict(file=our_file, miniters=1, mininterval=0, maxinterval=0)
- t = tqdm(total=2, desc='pos2 bar', leave=False, position=2, **kwargs)
- t.update()
- t.close()
- out = our_file.getvalue()
- res = [m[0] for m in RE_pos.findall(out)]
- exres = ['\n\n\rpos2 bar: 0%',
- '\n\n\rpos2 bar: 50%',
- '\n\n\r ']
-
- pos_line_diff(res, exres)
-
- # Test iteration-based tqdm positioning
- our_file = StringIO()
- kwargs["file"] = our_file
- for _ in trange(2, desc='pos0 bar', position=0, **kwargs):
- for _ in trange(2, desc='pos1 bar', position=1, **kwargs):
- for _ in trange(2, desc='pos2 bar', position=2, **kwargs):
- pass
- out = our_file.getvalue()
- res = [m[0] for m in RE_pos.findall(out)]
- exres = ['\rpos0 bar: 0%',
- '\n\rpos1 bar: 0%',
- '\n\n\rpos2 bar: 0%',
- '\n\n\rpos2 bar: 50%',
- '\n\n\rpos2 bar: 100%',
- '\rpos2 bar: 100%',
- '\n\n\rpos1 bar: 50%',
- '\n\n\rpos2 bar: 0%',
- '\n\n\rpos2 bar: 50%',
- '\n\n\rpos2 bar: 100%',
- '\rpos2 bar: 100%',
- '\n\n\rpos1 bar: 100%',
- '\rpos1 bar: 100%',
- '\n\rpos0 bar: 50%',
- '\n\rpos1 bar: 0%',
- '\n\n\rpos2 bar: 0%',
- '\n\n\rpos2 bar: 50%',
- '\n\n\rpos2 bar: 100%',
- '\rpos2 bar: 100%',
- '\n\n\rpos1 bar: 50%',
- '\n\n\rpos2 bar: 0%',
- '\n\n\rpos2 bar: 50%',
- '\n\n\rpos2 bar: 100%',
- '\rpos2 bar: 100%',
- '\n\n\rpos1 bar: 100%',
- '\rpos1 bar: 100%',
- '\n\rpos0 bar: 100%',
- '\rpos0 bar: 100%',
- '\n']
- pos_line_diff(res, exres)
-
- # Test manual tqdm positioning
- our_file = StringIO()
- kwargs["file"] = our_file
- kwargs["total"] = 2
- t1 = tqdm(desc='pos0 bar', position=0, **kwargs)
- t2 = tqdm(desc='pos1 bar', position=1, **kwargs)
- t3 = tqdm(desc='pos2 bar', position=2, **kwargs)
- for _ in _range(2):
- t1.update()
- t3.update()
- t2.update()
- out = our_file.getvalue()
- res = [m[0] for m in RE_pos.findall(out)]
- exres = ['\rpos0 bar: 0%',
- '\n\rpos1 bar: 0%',
- '\n\n\rpos2 bar: 0%',
- '\rpos0 bar: 50%',
- '\n\n\rpos2 bar: 50%',
- '\n\rpos1 bar: 50%',
- '\rpos0 bar: 100%',
- '\n\n\rpos2 bar: 100%',
- '\n\rpos1 bar: 100%']
- pos_line_diff(res, exres)
- t1.close()
- t2.close()
- t3.close()
-
- # Test auto repositioning of bars when a bar is prematurely closed
- # tqdm._instances.clear() # reset number of instances
- with closing(StringIO()) as our_file:
- t1 = tqdm(total=10, file=our_file, desc='1.pos0 bar', mininterval=0)
- t2 = tqdm(total=10, file=our_file, desc='2.pos1 bar', mininterval=0)
- t3 = tqdm(total=10, file=our_file, desc='3.pos2 bar', mininterval=0)
- res = [m[0] for m in RE_pos.findall(our_file.getvalue())]
- exres = ['\r1.pos0 bar: 0%',
- '\n\r2.pos1 bar: 0%',
- '\n\n\r3.pos2 bar: 0%']
- pos_line_diff(res, exres)
-
- t2.close()
- t4 = tqdm(total=10, file=our_file, desc='4.pos2 bar', mininterval=0)
- t1.update(1)
- t3.update(1)
- t4.update(1)
- res = [m[0] for m in RE_pos.findall(our_file.getvalue())]
- exres = ['\r1.pos0 bar: 0%',
- '\n\r2.pos1 bar: 0%',
- '\n\n\r3.pos2 bar: 0%',
- '\r2.pos1 bar: 0%',
- '\n\n\r4.pos2 bar: 0%',
- '\r1.pos0 bar: 10%',
- '\n\n\r3.pos2 bar: 10%',
- '\n\r4.pos2 bar: 10%']
- pos_line_diff(res, exres)
- t4.close()
- t3.close()
- t1.close()
-
-
-@with_setup(pretest, posttest)
-def test_set_description():
- """Test set description"""
- with closing(StringIO()) as our_file:
- with tqdm(desc='Hello', file=our_file) as t:
- assert t.desc == 'Hello'
- t.set_description_str('World')
- assert t.desc == 'World'
- t.set_description()
- assert t.desc == ''
- t.set_description('Bye')
- assert t.desc == 'Bye: '
- assert "World" in our_file.getvalue()
-
- # without refresh
- with closing(StringIO()) as our_file:
- with tqdm(desc='Hello', file=our_file) as t:
- assert t.desc == 'Hello'
- t.set_description_str('World', False)
- assert t.desc == 'World'
- t.set_description(None, False)
- assert t.desc == ''
- assert "World" not in our_file.getvalue()
-
- # unicode
- with closing(StringIO()) as our_file:
- with tqdm(total=10, file=our_file) as t:
- t.set_description(u"\xe1\xe9\xed\xf3\xfa")
-
-
-@with_setup(pretest, posttest)
-def test_deprecated_gui():
- """Test internal GUI properties"""
- # Check: StatusPrinter iff gui is disabled
- with closing(StringIO()) as our_file:
- t = tqdm(total=2, gui=True, file=our_file, miniters=1, mininterval=0)
- assert not hasattr(t, "sp")
- try:
- t.update(1)
- except TqdmDeprecationWarning as e:
- if ('Please use `tqdm.gui.tqdm(...)` instead of'
- ' `tqdm(..., gui=True)`') \
- not in our_file.getvalue():
- raise e
- else:
- raise DeprecationError('Should not allow manual gui=True without'
- ' overriding __iter__() and update()')
- finally:
- t._instances.clear()
- # t.close()
- # len(tqdm._instances) += 1 # undo the close() decrement
-
- t = tqdm(_range(3), gui=True, file=our_file, miniters=1, mininterval=0)
- try:
- for _ in t:
- pass
- except TqdmDeprecationWarning as e:
- if ('Please use `tqdm.gui.tqdm(...)` instead of'
- ' `tqdm(..., gui=True)`') \
- not in our_file.getvalue():
- raise e
- else:
- raise DeprecationError('Should not allow manual gui=True without'
- ' overriding __iter__() and update()')
- finally:
- t._instances.clear()
- # t.close()
- # len(tqdm._instances) += 1 # undo the close() decrement
-
- with tqdm(total=1, gui=False, file=our_file) as t:
- assert hasattr(t, "sp")
-
-
-@with_setup(pretest, posttest)
-def test_cmp():
- """Test comparison functions"""
- with closing(StringIO()) as our_file:
- t0 = tqdm(total=10, file=our_file)
- t1 = tqdm(total=10, file=our_file)
- t2 = tqdm(total=10, file=our_file)
-
- assert t0 < t1
- assert t2 >= t0
- assert t0 <= t2
-
- t3 = tqdm(total=10, file=our_file)
- t4 = tqdm(total=10, file=our_file)
- t5 = tqdm(total=10, file=our_file)
- t5.close()
- t6 = tqdm(total=10, file=our_file)
-
- assert t3 != t4
- assert t3 > t2
- assert t5 == t6
- t6.close()
- t4.close()
- t3.close()
- t2.close()
- t1.close()
- t0.close()
-
-
-@with_setup(pretest, posttest)
-def test_repr():
- """Test representation"""
- with closing(StringIO()) as our_file:
- with tqdm(total=10, ascii=True, file=our_file) as t:
- assert str(t) == ' 0%| | 0/10 [00:00<?, ?it/s]'
-
-
-@with_setup(pretest, posttest)
-def test_clear():
- """Test clearing bar display"""
- with closing(StringIO()) as our_file:
- t1 = tqdm(total=10, file=our_file, desc='pos0 bar',
- bar_format='{l_bar}')
- t2 = trange(10, file=our_file, desc='pos1 bar', bar_format='{l_bar}')
- before = squash_ctrlchars(our_file.getvalue())
- t2.clear()
- t1.clear()
- after = squash_ctrlchars(our_file.getvalue())
- t1.close()
- t2.close()
- assert before == ['pos0 bar: 0%|', 'pos1 bar: 0%|']
- assert after == ['', '']
-
-
-@with_setup(pretest, posttest)
-def test_clear_disabled():
- """Test clearing bar display"""
- with closing(StringIO()) as our_file:
- with tqdm(total=10, file=our_file, desc='pos0 bar', disable=True,
- bar_format='{l_bar}') as t:
- t.clear()
- assert our_file.getvalue() == ''
-
-
-@with_setup(pretest, posttest)
-def test_refresh():
- """Test refresh bar display"""
- with closing(StringIO()) as our_file:
- t1 = tqdm(total=10, file=our_file, desc='pos0 bar',
- bar_format='{l_bar}', mininterval=999, miniters=999)
- t2 = tqdm(total=10, file=our_file, desc='pos1 bar',
- bar_format='{l_bar}', mininterval=999, miniters=999)
- t1.update()
- t2.update()
- before = squash_ctrlchars(our_file.getvalue())
- t1.refresh()
- t2.refresh()
- after = squash_ctrlchars(our_file.getvalue())
- t1.close()
- t2.close()
-
- # Check that refreshing indeed forced the display to use realtime state
- assert before == [u'pos0 bar: 0%|', u'pos1 bar: 0%|']
- assert after == [u'pos0 bar: 10%|', u'pos1 bar: 10%|']
-
-
-@with_setup(pretest, posttest)
-def test_disabled_refresh():
- """Test refresh bar display"""
- with closing(StringIO()) as our_file:
- with tqdm(total=10, file=our_file, desc='pos0 bar', disable=True,
- bar_format='{l_bar}', mininterval=999, miniters=999) as t:
- t.update()
- t.refresh()
-
- assert our_file.getvalue() == ''
-
-
-@with_setup(pretest, posttest)
-def test_write():
- """Test write messages"""
- s = "Hello world"
- with closing(StringIO()) as our_file:
- # Change format to keep only left part w/o bar and it/s rate
- t1 = tqdm(total=10, file=our_file, desc='pos0 bar',
- bar_format='{l_bar}', mininterval=0, miniters=1)
- t2 = trange(10, file=our_file, desc='pos1 bar', bar_format='{l_bar}',
- mininterval=0, miniters=1)
- t3 = tqdm(total=10, file=our_file, desc='pos2 bar',
- bar_format='{l_bar}', mininterval=0, miniters=1)
- t1.update()
- t2.update()
- t3.update()
- before = our_file.getvalue()
-
- # Write msg and see if bars are correctly redrawn below the msg
- t1.write(s, file=our_file) # call as an instance method
- tqdm.write(s, file=our_file) # call as a class method
- after = our_file.getvalue()
-
- t1.close()
- t2.close()
- t3.close()
-
- before_squashed = squash_ctrlchars(before)
- after_squashed = squash_ctrlchars(after)
-
- assert after_squashed == [s, s] + before_squashed
-
- # Check that no bar clearing if different file
- with closing(StringIO()) as our_file_bar:
- with closing(StringIO()) as our_file_write:
- t1 = tqdm(total=10, file=our_file_bar, desc='pos0 bar',
- bar_format='{l_bar}', mininterval=0, miniters=1)
-
- t1.update()
- before_bar = our_file_bar.getvalue()
-
- tqdm.write(s, file=our_file_write)
-
- after_bar = our_file_bar.getvalue()
- t1.close()
-
- assert before_bar == after_bar
-
- # Test stdout/stderr anti-mixup strategy
- # Backup stdout/stderr
- stde = sys.stderr
- stdo = sys.stdout
- # Mock stdout/stderr
- with closing(StringIO()) as our_stderr:
- with closing(StringIO()) as our_stdout:
- sys.stderr = our_stderr
- sys.stdout = our_stdout
- t1 = tqdm(total=10, file=sys.stderr, desc='pos0 bar',
- bar_format='{l_bar}', mininterval=0, miniters=1)
-
- t1.update()
- before_err = sys.stderr.getvalue()
- before_out = sys.stdout.getvalue()
-
- tqdm.write(s, file=sys.stdout)
- after_err = sys.stderr.getvalue()
- after_out = sys.stdout.getvalue()
-
- t1.close()
-
- assert before_err == '\rpos0 bar: 0%|\rpos0 bar: 10%|'
- assert before_out == ''
- after_err_res = [m[0] for m in RE_pos.findall(after_err)]
- exres = ['\rpos0 bar: 0%|',
- '\rpos0 bar: 10%|',
- '\r ',
- '\r\rpos0 bar: 10%|']
- pos_line_diff(after_err_res, exres)
- assert after_out == s + '\n'
- # Restore stdout and stderr
- sys.stderr = stde
- sys.stdout = stdo
-
-
-@with_setup(pretest, posttest)
-def test_len():
- """Test advance len (numpy array shape)"""
- try:
- import numpy as np
- except ImportError:
- raise SkipTest
- with closing(StringIO()) as f:
- with tqdm(np.zeros((3, 4)), file=f) as t:
- assert len(t) == 3
-
-
-@with_setup(pretest, posttest)
-def test_autodisable_disable():
- """Test autodisable will disable on non-TTY"""
- with closing(StringIO()) as our_file:
- with tqdm(total=10, disable=None, file=our_file) as t:
- t.update(3)
- assert our_file.getvalue() == ''
-
-
-@with_setup(pretest, posttest)
-def test_autodisable_enable():
- """Test autodisable will not disable on TTY"""
- with closing(StringIO()) as our_file:
- setattr(our_file, "isatty", lambda: True)
- with tqdm(total=10, disable=None, file=our_file) as t:
- t.update()
- assert our_file.getvalue() != ''
-
-
-@with_setup(pretest, posttest)
-def test_deprecation_exception():
- def test_TqdmDeprecationWarning():
- with closing(StringIO()) as our_file:
- raise (TqdmDeprecationWarning('Test!', fp_write=getattr(
- our_file, 'write', sys.stderr.write)))
-
- def test_TqdmDeprecationWarning_nofpwrite():
- raise (TqdmDeprecationWarning('Test!', fp_write=None))
-
- assert_raises(TqdmDeprecationWarning, test_TqdmDeprecationWarning)
- assert_raises(Exception, test_TqdmDeprecationWarning_nofpwrite)
-
-
-@with_setup(pretest, posttest)
-def test_postfix():
- """Test postfix"""
- postfix = {'float': 0.321034, 'gen': 543, 'str': 'h', 'lst': [2]}
- postfix_order = (('w', 'w'), ('a', 0)) # no need for OrderedDict
- expected = ['float=0.321', 'gen=543', 'lst=[2]', 'str=h']
- expected_order = ['w=w', 'a=0', 'float=0.321', 'gen=543', 'lst=[2]',
- 'str=h']
-
- # Test postfix set at init
- with closing(StringIO()) as our_file:
- with tqdm(total=10, file=our_file, desc='pos0 bar',
- bar_format='{r_bar}', postfix=postfix) as t1:
- t1.refresh()
- out = our_file.getvalue()
-
- # Test postfix set after init
- with closing(StringIO()) as our_file:
- with trange(10, file=our_file, desc='pos1 bar', bar_format='{r_bar}',
- postfix=None) as t2:
- t2.set_postfix(**postfix)
- t2.refresh()
- out2 = our_file.getvalue()
-
- # Order of items in dict may change, so need a loop to check per item
- for res in expected:
- assert res in out
- assert res in out2
-
- # Test postfix (with ordered dict and no refresh) set after init
- with closing(StringIO()) as our_file:
- with trange(10, file=our_file, desc='pos2 bar', bar_format='{r_bar}',
- postfix=None) as t3:
- t3.set_postfix(postfix_order, False, **postfix)
- t3.refresh() # explicit external refresh
- out3 = our_file.getvalue()
-
- out3 = out3[1:-1].split(', ')[3:]
- assert out3 == expected_order
-
- # Test postfix (with ordered dict and refresh) set after init
- with closing(StringIO()) as our_file:
- with trange(10, file=our_file, desc='pos2 bar',
- bar_format='{r_bar}', postfix=None) as t4:
- t4.set_postfix(postfix_order, True, **postfix)
- t4.refresh() # double refresh
- out4 = our_file.getvalue()
-
- assert out4.count('\r') > out3.count('\r')
- assert out4.count(", ".join(expected_order)) == 2
-
- # Test setting postfix string directly
- with closing(StringIO()) as our_file:
- with trange(10, file=our_file, desc='pos2 bar', bar_format='{r_bar}',
- postfix=None) as t5:
- t5.set_postfix_str("Hello", False)
- t5.set_postfix_str("World")
- out5 = our_file.getvalue()
-
- assert "Hello" not in out5
- out5 = out5[1:-1].split(', ')[3:]
- assert out5 == ["World"]
-
-
-def test_postfix_direct():
- """Test directly assigning non-str objects to postfix"""
- with closing(StringIO()) as our_file:
- with tqdm(total=10, file=our_file, miniters=1, mininterval=0,
- bar_format="{postfix[0][name]} {postfix[1]:>5.2f}",
- postfix=[dict(name="foo"), 42]) as t:
- for i in range(10):
- if i % 2:
- t.postfix[0]["name"] = "abcdefghij"[i]
- else:
- t.postfix[1] = i
- t.update()
- res = our_file.getvalue()
- assert "f 6.00" in res
- assert "h 6.00" in res
- assert "h 8.00" in res
- assert "j 8.00" in res
-
-
-@contextmanager
-def std_out_err_redirect_tqdm(tqdm_file=sys.stderr):
- orig_out_err = sys.stdout, sys.stderr
- try:
- sys.stdout = sys.stderr = DummyTqdmFile(tqdm_file)
- yield orig_out_err[0]
- # Relay exceptions
- except Exception as exc:
- raise exc
- # Always restore sys.stdout/err if necessary
- finally:
- sys.stdout, sys.stderr = orig_out_err
-
-
-@with_setup(pretest, posttest)
-def test_file_redirection():
- """Test redirection of output"""
- with closing(StringIO()) as our_file:
- # Redirect stdout to tqdm.write()
- with std_out_err_redirect_tqdm(tqdm_file=our_file):
- for _ in trange(3):
- print("Such fun")
- res = our_file.getvalue()
- assert res.count("Such fun\n") == 3
- assert "0/3" in res
- assert "3/3" in res
-
-
-@with_setup(pretest, posttest)
-def test_external_write():
- """Test external write mode"""
- with closing(StringIO()) as our_file:
- # Redirect stdout to tqdm.write()
- for _ in trange(3, file=our_file):
- del tqdm._lock # classmethod should be able to recreate lock
- with tqdm.external_write_mode(file=our_file):
- our_file.write("Such fun\n")
- res = our_file.getvalue()
- assert res.count("Such fun\n") == 3
- assert "0/3" in res
- assert "3/3" in res
-
-
-@with_setup(pretest, posttest)
-def test_unit_scale():
- """Test numeric `unit_scale`"""
- with closing(StringIO()) as our_file:
- for _ in tqdm(_range(9), unit_scale=9, file=our_file,
- miniters=1, mininterval=0):
- pass
- out = our_file.getvalue()
- assert '81/81' in out
-
-
-@with_setup(pretest, posttest)
-def test_threading():
- """Test multiprocess/thread-realted features"""
- from multiprocessing import RLock
- try:
- mp_lock = RLock()
- except OSError:
- pass
- else:
- tqdm.set_lock(mp_lock)
- # TODO: test interleaved output #445
-
-
-@with_setup(pretest, posttest)
-def test_bool():
- """Test boolean cast"""
- def internal(our_file, disable):
- kwargs = dict(file=our_file, disable=disable)
- with trange(10, **kwargs) as t:
- assert t
- with trange(0, **kwargs) as t:
- assert not t
- with tqdm(total=10, **kwargs) as t:
- assert bool(t)
- with tqdm(total=0, **kwargs) as t:
- assert not bool(t)
- with tqdm([], **kwargs) as t:
- assert not t
- with tqdm([0], **kwargs) as t:
- assert t
- with tqdm((x for x in []), **kwargs) as t:
- assert t
- with tqdm((x for x in [1, 2, 3]), **kwargs) as t:
- assert t
- with tqdm(**kwargs) as t:
- try:
- print(bool(t))
- except TypeError:
- pass
- else:
- raise TypeError("Expected bool(tqdm()) to fail")
-
- # test with and without disable
- with closing(StringIO()) as our_file:
- internal(our_file, False)
- internal(our_file, True)
-
-
-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)
-
-
-@with_setup(pretest, posttest)
-def test_wrapattr():
- """Test wrapping file-like objects"""
- data = "a twenty-char string"
-
- with closing(StringIO()) as our_file:
- with closing(StringIO()) as writer:
- with tqdm.wrapattr(
- writer, "write", file=our_file, bytes=True) as wrap:
- wrap.write(data)
- res = writer.getvalue()
- assert data == res
- res = our_file.getvalue()
- assert ('%.1fB [' % len(data)) in res
-
- with closing(StringIO()) as our_file:
- with closing(StringIO()) as writer:
- with tqdm.wrapattr(
- writer, "write", file=our_file, bytes=False) as wrap:
- wrap.write(data)
- res = our_file.getvalue()
- assert ('%dit [' % len(data)) in res
-
-
-@with_setup(pretest, posttest)
-def test_float_progress():
- """Test float totals"""
- 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")
- for i in t:
- if i < 9:
- assert not w
- assert w
- assert "clamping frac" in str(w[-1].message)
-
-
-@with_setup(pretest, posttest)
-def test_screen_shape():
- """Test screen shape"""
- # ncols
- with closing(StringIO()) as our_file:
- with trange(10, file=our_file, ncols=50) as t:
- list(t)
-
- res = our_file.getvalue()
- assert all(len(i) == 50 for i in get_bar(res))
-
- # no second/third bar, leave=False
- with closing(StringIO()) as our_file:
- kwargs = dict(file=our_file, ncols=50, nrows=2, miniters=0,
- mininterval=0, leave=False)
- with trange(10, desc="one", **kwargs) as t1:
- with trange(10, desc="two", **kwargs) as t2:
- with trange(10, desc="three", **kwargs) as t3:
- list(t3)
- list(t2)
- list(t1)
-
- res = our_file.getvalue()
- assert "one" in res
- assert "two" not in res
- assert "three" not in res
- assert "\n\n" not in res
- assert "more hidden" in res
- # double-check ncols
- assert all(len(i) == 50 for i in get_bar(res)
- if i.strip() and "more hidden" not in i)
-
- # all bars, leave=True
- with closing(StringIO()) as our_file:
- kwargs = dict(file=our_file, ncols=50, nrows=2, miniters=0,
- mininterval=0)
- with trange(10, desc="one", **kwargs) as t1:
- with trange(10, desc="two", **kwargs) as t2:
- assert "two" not in our_file.getvalue()
- with trange(10, desc="three", **kwargs) as t3:
- assert "three" not in our_file.getvalue()
- list(t3)
- list(t2)
- list(t1)
-
- res = our_file.getvalue()
- assert "one" in res
- assert "two" in res
- assert "three" in res
- assert "\n\n" not in res
- assert "more hidden" in res
- # double-check ncols
- assert all(len(i) == 50 for i in get_bar(res)
- if i.strip() and "more hidden" not in i)
-
- # second bar becomes first, leave=False
- with closing(StringIO()) as our_file:
- kwargs = dict(file=our_file, ncols=50, nrows=2, miniters=0,
- mininterval=0, leave=False)
- t1 = tqdm(total=10, desc="one", **kwargs)
- with tqdm(total=10, desc="two", **kwargs) as t2:
- t1.update()
- t2.update()
- t1.close()
- res = our_file.getvalue()
- assert "one" in res
- assert "two" not in res
- assert "more hidden" in res
- t2.update()
-
- res = our_file.getvalue()
- assert "two" in res
diff --git a/libs/tqdm/tests/tests_version.py b/libs/tqdm/tests/tests_version.py
deleted file mode 100644
index 226b99802..000000000
--- a/libs/tqdm/tests/tests_version.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import re
-
-
-def test_version():
- """Test version string"""
- from tqdm import __version__
- version_parts = re.split('[.-]', __version__)
- assert 3 <= len(version_parts) # must have at least Major.minor.patch
- try:
- map(int, version_parts[:3])
- except ValueError:
- raise TypeError('Version Major.minor.patch must be 3 integers')
diff --git a/libs/tqdm/tk.py b/libs/tqdm/tk.py
new file mode 100644
index 000000000..92adb51db
--- /dev/null
+++ b/libs/tqdm/tk.py
@@ -0,0 +1,207 @@
+"""
+Tkinter GUI progressbar decorator for iterators.
+
+Usage:
+>>> from tqdm.tk import trange, tqdm
+>>> for i in trange(10):
+... ...
+"""
+from __future__ import absolute_import, division
+
+import re
+import sys
+from warnings import warn
+
+try:
+ import tkinter
+ import tkinter.ttk as ttk
+except ImportError:
+ import Tkinter as tkinter
+ import ttk as ttk
+
+from .std import TqdmExperimentalWarning, TqdmWarning
+from .std import tqdm as std_tqdm
+from .utils import _range
+
+__author__ = {"github.com/": ["richardsheridan", "casperdcl"]}
+__all__ = ['tqdm_tk', 'ttkrange', 'tqdm', 'trange']
+
+
+class tqdm_tk(std_tqdm): # pragma: no cover
+ """
+ Experimental Tkinter GUI version of tqdm!
+
+ Note: Window interactivity suffers if `tqdm_tk` is not running within
+ a Tkinter mainloop and values are generated infrequently. In this case,
+ consider calling `tqdm_tk.refresh()` frequently in the Tk thread.
+ """
+
+ # TODO: @classmethod: write()?
+
+ def __init__(self, *args, **kwargs):
+ """
+ This class accepts the following parameters *in addition* to
+ the parameters accepted by `tqdm`.
+
+ Parameters
+ ----------
+ grab : bool, optional
+ Grab the input across all windows of the process.
+ tk_parent : `tkinter.Wm`, optional
+ Parent Tk window.
+ cancel_callback : Callable, optional
+ Create a cancel button and set `cancel_callback` to be called
+ when the cancel or window close button is clicked.
+ """
+ kwargs = kwargs.copy()
+ kwargs['gui'] = True
+ # convert disable = None to False
+ kwargs['disable'] = bool(kwargs.get('disable', False))
+ self._warn_leave = 'leave' in kwargs
+ grab = kwargs.pop('grab', False)
+ tk_parent = kwargs.pop('tk_parent', None)
+ self._cancel_callback = kwargs.pop('cancel_callback', None)
+ super(tqdm_tk, self).__init__(*args, **kwargs)
+
+ if self.disable:
+ return
+
+ if tk_parent is None: # Discover parent widget
+ try:
+ tk_parent = tkinter._default_root
+ except AttributeError:
+ raise AttributeError(
+ "`tk_parent` required when using `tkinter.NoDefaultRoot()`")
+ if tk_parent is None: # use new default root window as display
+ self._tk_window = tkinter.Tk()
+ else: # some other windows already exist
+ self._tk_window = tkinter.Toplevel()
+ else:
+ self._tk_window = tkinter.Toplevel(tk_parent)
+
+ warn("GUI is experimental/alpha", TqdmExperimentalWarning, stacklevel=2)
+ self._tk_dispatching = self._tk_dispatching_helper()
+
+ self._tk_window.protocol("WM_DELETE_WINDOW", self.cancel)
+ self._tk_window.wm_title(self.desc)
+ self._tk_window.wm_attributes("-topmost", 1)
+ self._tk_window.after(0, lambda: self._tk_window.wm_attributes("-topmost", 0))
+ self._tk_n_var = tkinter.DoubleVar(self._tk_window, value=0)
+ self._tk_text_var = tkinter.StringVar(self._tk_window)
+ pbar_frame = ttk.Frame(self._tk_window, padding=5)
+ pbar_frame.pack()
+ _tk_label = ttk.Label(pbar_frame, textvariable=self._tk_text_var,
+ wraplength=600, anchor="center", justify="center")
+ _tk_label.pack()
+ self._tk_pbar = ttk.Progressbar(
+ pbar_frame, variable=self._tk_n_var, length=450)
+ if self.total is not None:
+ self._tk_pbar.configure(maximum=self.total)
+ else:
+ self._tk_pbar.configure(mode="indeterminate")
+ self._tk_pbar.pack()
+ if self._cancel_callback is not None:
+ _tk_button = ttk.Button(pbar_frame, text="Cancel", command=self.cancel)
+ _tk_button.pack()
+ if grab:
+ self._tk_window.grab_set()
+
+ def close(self):
+ if self.disable:
+ return
+
+ self.disable = True
+
+ with self.get_lock():
+ self._instances.remove(self)
+
+ def _close():
+ self._tk_window.after('idle', self._tk_window.destroy)
+ if not self._tk_dispatching:
+ self._tk_window.update()
+
+ self._tk_window.protocol("WM_DELETE_WINDOW", _close)
+
+ # if leave is set but we are self-dispatching, the left window is
+ # totally unresponsive unless the user manually dispatches
+ if not self.leave:
+ _close()
+ elif not self._tk_dispatching:
+ if self._warn_leave:
+ warn("leave flag ignored if not in tkinter mainloop",
+ TqdmWarning, stacklevel=2)
+ _close()
+
+ def clear(self, *_, **__):
+ pass
+
+ def display(self, *_, **__):
+ self._tk_n_var.set(self.n)
+ d = self.format_dict
+ # remove {bar}
+ d['bar_format'] = (d['bar_format'] or "{l_bar}<bar/>{r_bar}").replace(
+ "{bar}", "<bar/>")
+ msg = self.format_meter(**d)
+ if '<bar/>' in msg:
+ msg = "".join(re.split(r'\|?<bar/>\|?', msg, 1))
+ self._tk_text_var.set(msg)
+ if not self._tk_dispatching:
+ self._tk_window.update()
+
+ def set_description(self, desc=None, refresh=True):
+ self.set_description_str(desc, refresh)
+
+ def set_description_str(self, desc=None, refresh=True):
+ self.desc = desc
+ if not self.disable:
+ self._tk_window.wm_title(desc)
+ if refresh and not self._tk_dispatching:
+ self._tk_window.update()
+
+ def cancel(self):
+ """
+ `cancel_callback()` followed by `close()`
+ when close/cancel buttons clicked.
+ """
+ if self._cancel_callback is not None:
+ self._cancel_callback()
+ self.close()
+
+ def reset(self, total=None):
+ """
+ Resets to 0 iterations for repeated use.
+
+ Parameters
+ ----------
+ total : int or float, optional. Total to use for the new bar.
+ """
+ if hasattr(self, '_tk_pbar'):
+ if total is None:
+ self._tk_pbar.configure(maximum=100, mode="indeterminate")
+ else:
+ self._tk_pbar.configure(maximum=total, mode="determinate")
+ super(tqdm_tk, self).reset(total=total)
+
+ @staticmethod
+ def _tk_dispatching_helper():
+ """determine if Tkinter mainloop is dispatching events"""
+ codes = {tkinter.mainloop.__code__, tkinter.Misc.mainloop.__code__}
+ for frame in sys._current_frames().values():
+ while frame:
+ if frame.f_code in codes:
+ return True
+ frame = frame.f_back
+ return False
+
+
+def ttkrange(*args, **kwargs):
+ """
+ A shortcut for `tqdm.tk.tqdm(xrange(*args), **kwargs)`.
+ On Python3+, `range` is used instead of `xrange`.
+ """
+ return tqdm_tk(_range(*args), **kwargs)
+
+
+# Aliases
+tqdm = tqdm_tk
+trange = ttkrange
diff --git a/libs/tqdm/tqdm.1 b/libs/tqdm/tqdm.1
index f0c692452..0533198ca 100644
--- a/libs/tqdm/tqdm.1
+++ b/libs/tqdm/tqdm.1
@@ -1,6 +1,6 @@
-.\" Automatically generated by Pandoc 1.19.2.1
+.\" Automatically generated by Pandoc 1.19.2
.\"
-.TH "TQDM" "1" "2015\-2020" "tqdm User Manuals" ""
+.TH "TQDM" "1" "2015\-2021" "tqdm User Manuals" ""
.hy
.SH NAME
.PP
@@ -36,12 +36,12 @@ counting:\ 100%|█████████|\ 432/432\ [00:00<00:00,\ 794361.83f
.SH OPTIONS
.TP
.B \-h, \-\-help
-Print this help and exit
+Print this help and exit.
.RS
.RE
.TP
.B \-v, \-\-version
-Print version and exit
+Print version and exit.
.RS
.RE
.TP
@@ -63,7 +63,7 @@ specify an initial arbitrary large positive number, e.g.
.RS
.RE
.TP
-.B \-\-leave=\f[I]leave\f[]
+.B \-\-leave
bool, optional.
If [default: True], keeps all traces of the progressbar upon termination
of iteration.
@@ -117,7 +117,7 @@ The fallback is to use ASCII characters " 123456789#".
.RS
.RE
.TP
-.B \-\-disable=\f[I]disable\f[]
+.B \-\-disable
bool, optional.
Whether to disable the entire progressbar wrapper [default: False].
If set to None, disable on non\-TTY.
@@ -131,7 +131,7 @@ it].
.RS
.RE
.TP
-.B \-\-unit_scale=\f[I]unit_scale\f[]
+.B \-\-unit\-scale=\f[I]unit_scale\f[]
bool or int or float, optional.
If 1 or True, the number of iterations will be reduced/scaled
automatically and a metric prefix following the International System of
@@ -140,7 +140,7 @@ If any other non\-zero number, will scale \f[C]total\f[] and \f[C]n\f[].
.RS
.RE
.TP
-.B \-\-dynamic_ncols=\f[I]dynamic_ncols\f[]
+.B \-\-dynamic\-ncols
bool, optional.
If set, constantly alters \f[C]ncols\f[] and \f[C]nrows\f[] to the
environment (allowing for window resizes) [default: False].
@@ -156,7 +156,7 @@ Ranges from 0 (average speed) to 1 (current/instantaneous speed)
.RS
.RE
.TP
-.B \-\-bar_format=\f[I]bar_format\f[]
+.B \-\-bar\-format=\f[I]bar_format\f[]
str, optional.
Specify a custom bar string formatting.
May impact performance.
@@ -166,7 +166,7 @@ May impact performance.
vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, percentage,
elapsed, elapsed_s, ncols, nrows, desc, unit, rate, rate_fmt,
rate_noinv, rate_noinv_fmt, rate_inv, rate_inv_fmt, postfix,
-unit_divisor, remaining, remaining_s.
+unit_divisor, remaining, remaining_s, eta.
Note that a trailing ": " is automatically removed after {desc} if the
latter is empty.
.RS
@@ -196,13 +196,13 @@ Calls \f[C]set_postfix(**postfix)\f[] if possible (dict).
.RS
.RE
.TP
-.B \-\-unit_divisor=\f[I]unit_divisor\f[]
+.B \-\-unit\-divisor=\f[I]unit_divisor\f[]
float, optional.
[default: 1000], ignored unless \f[C]unit_scale\f[] is True.
.RS
.RE
.TP
-.B \-\-write_bytes=\f[I]write_bytes\f[]
+.B \-\-write\-bytes
bool, optional.
If (default: None) and \f[C]file\f[] is unspecified, bytes will be
written in Python 2.
@@ -211,7 +211,7 @@ In all other cases will default to unicode.
.RS
.RE
.TP
-.B \-\-lock_args=\f[I]lock_args\f[]
+.B \-\-lock\-args=\f[I]lock_args\f[]
tuple, optional.
Passed to \f[C]refresh\f[] for intermediate output (initialisation,
iterating, and updating).
@@ -227,6 +227,19 @@ The fallback is 20.
.RS
.RE
.TP
+.B \-\-colour=\f[I]colour\f[]
+str, optional.
+Bar colour (e.g.
+\[aq]green\[aq], \[aq]#00ff00\[aq]).
+.RS
+.RE
+.TP
+.B \-\-delay=\f[I]delay\f[]
+float, optional.
+Don\[aq]t display until [default: 0] seconds have elapsed.
+.RS
+.RE
+.TP
.B \-\-delim=\f[I]delim\f[]
chr, optional.
Delimiting character [default: \[aq]\\n\[aq]].
@@ -236,14 +249,14 @@ N.B.: on Windows systems, Python converts \[aq]\\n\[aq] to
.RS
.RE
.TP
-.B \-\-buf_size=\f[I]buf_size\f[]
+.B \-\-buf\-size=\f[I]buf_size\f[]
int, optional.
String buffer size in bytes [default: 256] used when \f[C]delim\f[] is
specified.
.RS
.RE
.TP
-.B \-\-bytes=\f[I]bytes\f[]
+.B \-\-bytes
bool, optional.
If true, will count bytes, ignore \f[C]delim\f[], and default
\f[C]unit_scale\f[] to True, \f[C]unit_divisor\f[] to 1024, and
@@ -251,6 +264,37 @@ If true, will count bytes, ignore \f[C]delim\f[], and default
.RS
.RE
.TP
+.B \-\-tee
+bool, optional.
+If true, passes \f[C]stdin\f[] to both \f[C]stderr\f[] and
+\f[C]stdout\f[].
+.RS
+.RE
+.TP
+.B \-\-update
+bool, optional.
+If true, will treat input as newly elapsed iterations, i.e.
+numbers to pass to \f[C]update()\f[].
+Note that this is slow (~2e5 it/s) since every input must be decoded as
+a number.
+.RS
+.RE
+.TP
+.B \-\-update\-to
+bool, optional.
+If true, will treat input as total elapsed iterations, i.e.
+numbers to assign to \f[C]self.n\f[].
+Note that this is slow (~2e5 it/s) since every input must be decoded as
+a number.
+.RS
+.RE
+.TP
+.B \-\-null
+bool, optional.
+If true, will discard input (no stdout).
+.RS
+.RE
+.TP
.B \-\-manpath=\f[I]manpath\f[]
str, optional.
Directory in which to install tqdm man pages.
diff --git a/libs/tqdm/utils.py b/libs/tqdm/utils.py
index b64de297f..0632b8dd0 100644
--- a/libs/tqdm/utils.py
+++ b/libs/tqdm/utils.py
@@ -1,131 +1,51 @@
-from functools import wraps
+"""
+General helpers required for `tqdm.std`.
+"""
import os
-from platform import system as _curos
import re
-import subprocess
+import sys
+from functools import wraps
from warnings import warn
+from weakref import proxy
-CUR_OS = _curos()
-IS_WIN = CUR_OS in ['Windows', 'cli']
-IS_NIX = (not IS_WIN) and any(
- CUR_OS.startswith(i) for i in
- ['CYGWIN', 'MSYS', 'Linux', 'Darwin', 'SunOS',
- 'FreeBSD', 'NetBSD', 'OpenBSD'])
-RE_ANSI = re.compile(r"\x1b\[[;\d]*[A-Za-z]")
+# py2/3 compat
+try:
+ _range = xrange
+except NameError:
+ _range = range
+try:
+ _unich = unichr
+except NameError:
+ _unich = chr
-# Py2/3 compat. Empty conditional to avoid coverage
-if True: # pragma: no cover
- try:
- _range = xrange
- except NameError:
- _range = range
+try:
+ _unicode = unicode
+except NameError:
+ _unicode = str
- try:
- _unich = unichr
- except NameError:
- _unich = chr
+try:
+ _basestring = basestring
+except NameError:
+ _basestring = str
- try:
- _unicode = unicode
- except NameError:
- _unicode = str
+CUR_OS = sys.platform
+IS_WIN = any(CUR_OS.startswith(i) for i in ['win32', 'cygwin'])
+IS_NIX = any(CUR_OS.startswith(i) for i in ['aix', 'linux', 'darwin'])
+RE_ANSI = re.compile(r"\x1b\[[;\d]*[A-Za-z]")
- try:
- if IS_WIN:
- import colorama
- else:
- raise ImportError
- except ImportError:
- colorama = None
+try:
+ if IS_WIN:
+ import colorama
else:
- try:
- colorama.init(strip=False)
- except TypeError:
- colorama.init()
-
- try:
- from weakref import WeakSet
- except ImportError:
- WeakSet = set
-
+ raise ImportError
+except ImportError:
+ colorama = None
+else:
try:
- _basestring = basestring
- except NameError:
- _basestring = str
-
- try: # py>=2.7,>=3.1
- from collections import OrderedDict as _OrderedDict
- except ImportError:
- try: # older Python versions with backported ordereddict lib
- from ordereddict import OrderedDict as _OrderedDict
- except ImportError: # older Python versions without ordereddict lib
- # Py2.6,3.0 compat, from PEP 372
- from collections import MutableMapping
-
- class _OrderedDict(dict, MutableMapping):
- # Methods with direct access to underlying attributes
- def __init__(self, *args, **kwds):
- if len(args) > 1:
- raise TypeError('expected at 1 argument, got %d',
- len(args))
- if not hasattr(self, '_keys'):
- self._keys = []
- self.update(*args, **kwds)
-
- def clear(self):
- del self._keys[:]
- dict.clear(self)
-
- def __setitem__(self, key, value):
- if key not in self:
- self._keys.append(key)
- dict.__setitem__(self, key, value)
-
- def __delitem__(self, key):
- dict.__delitem__(self, key)
- self._keys.remove(key)
-
- def __iter__(self):
- return iter(self._keys)
-
- def __reversed__(self):
- return reversed(self._keys)
-
- def popitem(self):
- if not self:
- raise KeyError
- key = self._keys.pop()
- value = dict.pop(self, key)
- return key, value
-
- def __reduce__(self):
- items = [[k, self[k]] for k in self]
- inst_dict = vars(self).copy()
- inst_dict.pop('_keys', None)
- return self.__class__, (items,), inst_dict
-
- # Methods with indirect access via the above methods
- setdefault = MutableMapping.setdefault
- update = MutableMapping.update
- pop = MutableMapping.pop
- keys = MutableMapping.keys
- values = MutableMapping.values
- items = MutableMapping.items
-
- def __repr__(self):
- pairs = ', '.join(map('%r: %r'.__mod__, self.items()))
- return '%s({%s})' % (self.__class__.__name__, pairs)
-
- def copy(self):
- return self.__class__(self)
-
- @classmethod
- def fromkeys(cls, iterable, value=None):
- d = cls()
- for key in iterable:
- d[key] = value
- return d
+ colorama.init(strip=False)
+ except TypeError:
+ colorama.init()
class FormatReplace(object):
@@ -133,7 +53,7 @@ class FormatReplace(object):
>>> a = FormatReplace('something')
>>> "{:5d}".format(a)
'something'
- """
+ """ # NOQA: P102
def __init__(self, replace=''):
self.replace = replace
self.format_called = 0
@@ -209,6 +129,49 @@ class SimpleTextIOWrapper(ObjectWrapper):
return self._wrapped == getattr(other, '_wrapped', other)
+class DisableOnWriteError(ObjectWrapper):
+ """
+ Disable the given `tqdm_instance` upon `write()` or `flush()` errors.
+ """
+ @staticmethod
+ def disable_on_exception(tqdm_instance, func):
+ """
+ Quietly set `tqdm_instance.miniters=inf` if `func` raises `errno=5`.
+ """
+ tqdm_instance = proxy(tqdm_instance)
+
+ def inner(*args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except OSError as e:
+ if e.errno != 5:
+ raise
+ try:
+ tqdm_instance.miniters = float('inf')
+ except ReferenceError:
+ pass
+ except ValueError as e:
+ if 'closed' not in str(e):
+ raise
+ try:
+ tqdm_instance.miniters = float('inf')
+ except ReferenceError:
+ pass
+ return inner
+
+ def __init__(self, wrapped, tqdm_instance):
+ super(DisableOnWriteError, self).__init__(wrapped)
+ if hasattr(wrapped, 'write'):
+ self.wrapper_setattr(
+ 'write', self.disable_on_exception(tqdm_instance, wrapped.write))
+ if hasattr(wrapped, 'flush'):
+ self.wrapper_setattr(
+ 'flush', self.disable_on_exception(tqdm_instance, wrapped.flush))
+
+ def __eq__(self, other):
+ return self._wrapped == getattr(other, '_wrapped', other)
+
+
class CallbackIOWrapper(ObjectWrapper):
def __init__(self, callback, stream, method="read"):
"""
@@ -238,12 +201,12 @@ class CallbackIOWrapper(ObjectWrapper):
def _is_utf(encoding):
try:
u'\u2588\u2589'.encode(encoding)
- except UnicodeEncodeError: # pragma: no cover
+ except UnicodeEncodeError:
return False
- except Exception: # pragma: no cover
+ except Exception:
try:
return encoding.lower().startswith('utf-') or ('U8' == encoding)
- except:
+ except Exception:
return False
else:
return True
@@ -282,8 +245,8 @@ def _screen_shape_wrapper(): # pragma: no cover
def _screen_shape_windows(fp): # pragma: no cover
try:
- from ctypes import windll, create_string_buffer
import struct
+ from ctypes import create_string_buffer, windll
from sys import stdin, stdout
io_handle = -12 # assume stderr
@@ -299,7 +262,7 @@ def _screen_shape_windows(fp): # pragma: no cover
(_bufx, _bufy, _curx, _cury, _wattr, left, top, right, bottom,
_maxx, _maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
return right - left, bottom - top # +1
- except:
+ except Exception: # nosec
pass
return None, None
@@ -308,9 +271,10 @@ def _screen_shape_tput(*_): # pragma: no cover
"""cygwin xterm (windows)"""
try:
import shlex
- return [int(subprocess.check_call(shlex.split('tput ' + i))) - 1
+ from subprocess import check_call # nosec
+ return [int(check_call(shlex.split('tput ' + i))) - 1
for i in ('cols', 'lines')]
- except:
+ except Exception: # nosec
pass
return None, None
@@ -318,19 +282,19 @@ def _screen_shape_tput(*_): # pragma: no cover
def _screen_shape_linux(fp): # pragma: no cover
try:
- from termios import TIOCGWINSZ
- from fcntl import ioctl
from array import array
+ from fcntl import ioctl
+ from termios import TIOCGWINSZ
except ImportError:
- return None
+ return None, None
else:
try:
rows, cols = array('h', ioctl(fp, TIOCGWINSZ, '\0' * 8))[:2]
return cols, rows
- except:
+ except Exception:
try:
return [int(os.environ[i]) - 1 for i in ("COLUMNS", "LINES")]
- except KeyError:
+ except (KeyError, ValueError):
return None, None
@@ -363,8 +327,7 @@ except ImportError:
_text_width = len
else:
def _text_width(s):
- return sum(
- 2 if east_asian_width(ch) in 'FW' else 1 for ch in _unicode(s))
+ return sum(2 if east_asian_width(ch) in 'FW' else 1 for ch in _unicode(s))
def disp_len(data):
diff --git a/libs/tqdm/version.py b/libs/tqdm/version.py
new file mode 100644
index 000000000..11cbaea79
--- /dev/null
+++ b/libs/tqdm/version.py
@@ -0,0 +1,9 @@
+"""`tqdm` version detector. Precedence: installed dist, git, 'UNKNOWN'."""
+try:
+ from ._dist_ver import __version__
+except ImportError:
+ try:
+ from setuptools_scm import get_version
+ __version__ = get_version(root='..', relative_to=__file__)
+ except (ImportError, LookupError):
+ __version__ = "UNKNOWN"