summaryrefslogtreecommitdiffstats
path: root/third_party/python/tqdm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/python/tqdm
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/python/tqdm')
-rw-r--r--third_party/python/tqdm/tqdm-4.62.3.dist-info/LICENCE49
-rw-r--r--third_party/python/tqdm/tqdm-4.62.3.dist-info/METADATA1585
-rw-r--r--third_party/python/tqdm/tqdm-4.62.3.dist-info/RECORD39
-rw-r--r--third_party/python/tqdm/tqdm-4.62.3.dist-info/WHEEL6
-rw-r--r--third_party/python/tqdm/tqdm-4.62.3.dist-info/entry_points.txt3
-rw-r--r--third_party/python/tqdm/tqdm-4.62.3.dist-info/top_level.txt1
-rw-r--r--third_party/python/tqdm/tqdm/__init__.py41
-rw-r--r--third_party/python/tqdm/tqdm/__main__.py3
-rw-r--r--third_party/python/tqdm/tqdm/_dist_ver.py1
-rw-r--r--third_party/python/tqdm/tqdm/_main.py9
-rw-r--r--third_party/python/tqdm/tqdm/_monitor.py95
-rw-r--r--third_party/python/tqdm/tqdm/_tqdm.py9
-rw-r--r--third_party/python/tqdm/tqdm/_tqdm_gui.py9
-rw-r--r--third_party/python/tqdm/tqdm/_tqdm_notebook.py9
-rw-r--r--third_party/python/tqdm/tqdm/_tqdm_pandas.py24
-rw-r--r--third_party/python/tqdm/tqdm/_utils.py12
-rw-r--r--third_party/python/tqdm/tqdm/asyncio.py93
-rw-r--r--third_party/python/tqdm/tqdm/auto.py44
-rw-r--r--third_party/python/tqdm/tqdm/autonotebook.py28
-rw-r--r--third_party/python/tqdm/tqdm/cli.py308
-rwxr-xr-xthird_party/python/tqdm/tqdm/completion.sh19
-rw-r--r--third_party/python/tqdm/tqdm/contrib/__init__.py98
-rw-r--r--third_party/python/tqdm/tqdm/contrib/bells.py24
-rw-r--r--third_party/python/tqdm/tqdm/contrib/concurrent.py130
-rw-r--r--third_party/python/tqdm/tqdm/contrib/discord.py121
-rw-r--r--third_party/python/tqdm/tqdm/contrib/itertools.py36
-rw-r--r--third_party/python/tqdm/tqdm/contrib/logging.py128
-rw-r--r--third_party/python/tqdm/tqdm/contrib/telegram.py159
-rw-r--r--third_party/python/tqdm/tqdm/contrib/utils_worker.py40
-rw-r--r--third_party/python/tqdm/tqdm/dask.py46
-rw-r--r--third_party/python/tqdm/tqdm/gui.py191
-rw-r--r--third_party/python/tqdm/tqdm/keras.py124
-rw-r--r--third_party/python/tqdm/tqdm/notebook.py327
-rw-r--r--third_party/python/tqdm/tqdm/rich.py152
-rw-r--r--third_party/python/tqdm/tqdm/std.py1526
-rw-r--r--third_party/python/tqdm/tqdm/tk.py207
-rw-r--r--third_party/python/tqdm/tqdm/tqdm.1316
-rw-r--r--third_party/python/tqdm/tqdm/utils.py354
-rw-r--r--third_party/python/tqdm/tqdm/version.py9
39 files changed, 6375 insertions, 0 deletions
diff --git a/third_party/python/tqdm/tqdm-4.62.3.dist-info/LICENCE b/third_party/python/tqdm/tqdm-4.62.3.dist-info/LICENCE
new file mode 100644
index 0000000000..5b3cab7fb5
--- /dev/null
+++ b/third_party/python/tqdm/tqdm-4.62.3.dist-info/LICENCE
@@ -0,0 +1,49 @@
+`tqdm` is a product of collaborative work.
+Unless otherwise stated, all authors (see commit logs) retain copyright
+for their respective work, and release the work under the MIT licence
+(text below).
+
+Exceptions or notable authors are listed below
+in reverse chronological order:
+
+* files: *
+ MPLv2.0 2015-2021 (c) Casper da Costa-Luis
+ [casperdcl](https://github.com/casperdcl).
+* files: tqdm/_tqdm.py
+ MIT 2016 (c) [PR #96] on behalf of Google Inc.
+* files: tqdm/_tqdm.py setup.py README.rst MANIFEST.in .gitignore
+ MIT 2013 (c) Noam Yorav-Raphael, original author.
+
+[PR #96]: https://github.com/tqdm/tqdm/pull/96
+
+
+Mozilla Public Licence (MPL) v. 2.0 - Exhibit A
+-----------------------------------------------
+
+This Source Code Form is subject to the terms of the
+Mozilla Public License, v. 2.0.
+If a copy of the MPL was not distributed with this project,
+You can obtain one at https://mozilla.org/MPL/2.0/.
+
+
+MIT License (MIT)
+-----------------
+
+Copyright (c) 2013 noamraph
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/third_party/python/tqdm/tqdm-4.62.3.dist-info/METADATA b/third_party/python/tqdm/tqdm-4.62.3.dist-info/METADATA
new file mode 100644
index 0000000000..48461ec16e
--- /dev/null
+++ b/third_party/python/tqdm/tqdm-4.62.3.dist-info/METADATA
@@ -0,0 +1,1585 @@
+Metadata-Version: 2.1
+Name: tqdm
+Version: 4.62.3
+Summary: Fast, Extensible Progress Meter
+Home-page: https://tqdm.github.io
+Maintainer: tqdm developers
+Maintainer-email: python.tqdm@gmail.com
+License: MPLv2.0, MIT Licences
+Project-URL: Changelog, https://tqdm.github.io/releases
+Project-URL: Source, https://github.com/tqdm/tqdm
+Project-URL: Wiki, https://github.com/tqdm/tqdm/wiki
+Keywords: progressbar,progressmeter,progress,bar,meter,rate,eta,console,terminal,time
+Platform: any
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Environment :: MacOS X
+Classifier: Environment :: Other Environment
+Classifier: Environment :: Win32 (MS Windows)
+Classifier: Environment :: X11 Applications
+Classifier: Framework :: IPython
+Classifier: Framework :: Jupyter
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Education
+Classifier: Intended Audience :: End Users/Desktop
+Classifier: Intended Audience :: Other Audience
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: MIT License
+Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
+Classifier: Operating System :: MacOS
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft
+Classifier: Operating System :: Microsoft :: MS-DOS
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: POSIX :: BSD
+Classifier: Operating System :: POSIX :: BSD :: FreeBSD
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Operating System :: POSIX :: SunOS/Solaris
+Classifier: Operating System :: Unix
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: Implementation
+Classifier: Programming Language :: Python :: Implementation :: IronPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Programming Language :: Unix Shell
+Classifier: Topic :: Desktop Environment
+Classifier: Topic :: Education :: Computer Aided Instruction (CAI)
+Classifier: Topic :: Education :: Testing
+Classifier: Topic :: Office/Business
+Classifier: Topic :: Other/Nonlisted Topic
+Classifier: Topic :: Software Development :: Build Tools
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Software Development :: Pre-processors
+Classifier: Topic :: Software Development :: User Interfaces
+Classifier: Topic :: System :: Installation/Setup
+Classifier: Topic :: System :: Logging
+Classifier: Topic :: System :: Monitoring
+Classifier: Topic :: System :: Shells
+Classifier: Topic :: Terminals
+Classifier: Topic :: Utilities
+Provides: tqdm
+Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7
+Description-Content-Type: text/x-rst
+License-File: LICENCE
+Requires-Dist: colorama ; platform_system == "Windows"
+Provides-Extra: dev
+Requires-Dist: py-make (>=0.1.0) ; extra == 'dev'
+Requires-Dist: twine ; extra == 'dev'
+Requires-Dist: wheel ; extra == 'dev'
+Provides-Extra: notebook
+Requires-Dist: ipywidgets (>=6) ; extra == 'notebook'
+Provides-Extra: telegram
+Requires-Dist: requests ; extra == 'telegram'
+
+|Logo|
+
+tqdm
+====
+
+|Py-Versions| |Versions| |Conda-Forge-Status| |Docker| |Snapcraft|
+
+|Build-Status| |Coverage-Status| |Branch-Coverage-Status| |Codacy-Grade| |Libraries-Rank| |PyPI-Downloads|
+
+|LICENCE| |OpenHub-Status| |binder-demo| |awesome-python|
+
+``tqdm`` derives from the Arabic word *taqaddum* (تقدّم) which can mean "progress,"
+and is an abbreviation for "I love you so much" in Spanish (*te quiero demasiado*).
+
+Instantly make your loops show a smart progress meter - just wrap any
+iterable with ``tqdm(iterable)``, and you're done!
+
+.. code:: python
+
+ from tqdm import tqdm
+ for i in tqdm(range(10000)):
+ ...
+
+``76%|████████████████████████        | 7568/10000 [00:33<00:10, 229.00it/s]``
+
+``trange(N)`` can be also used as a convenient shortcut for
+``tqdm(range(N))``.
+
+|Screenshot|
+ |Video| |Slides| |Merch|
+
+It can also be executed as a module with pipes:
+
+.. code:: sh
+
+ $ seq 9999999 | tqdm --bytes | wc -l
+ 75.2MB [00:00, 217MB/s]
+ 9999999
+
+ $ tar -zcf - docs/ | tqdm --bytes --total `du -sb docs/ | cut -f1` \
+ > backup.tgz
+ 32%|██████████▍ | 8.89G/27.9G [00:42<01:31, 223MB/s]
+
+Overhead is low -- about 60ns per iteration (80ns with ``tqdm.gui``), and is
+unit tested against performance regression.
+By comparison, the well-established
+`ProgressBar <https://github.com/niltonvolpato/python-progressbar>`__ has
+an 800ns/iter overhead.
+
+In addition to its low overhead, ``tqdm`` uses smart algorithms to predict
+the remaining time and to skip unnecessary iteration displays, which allows
+for a negligible overhead in most cases.
+
+``tqdm`` works on any platform
+(Linux, Windows, Mac, FreeBSD, NetBSD, Solaris/SunOS),
+in any console or in a GUI, and is also friendly with IPython/Jupyter notebooks.
+
+``tqdm`` does not require any dependencies (not even ``curses``!), just
+Python and an environment supporting ``carriage return \r`` and
+``line feed \n`` control characters.
+
+------------------------------------------
+
+.. contents:: Table of contents
+ :backlinks: top
+ :local:
+
+
+Installation
+------------
+
+Latest PyPI stable release
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+|Versions| |PyPI-Downloads| |Libraries-Dependents|
+
+.. code:: sh
+
+ pip install tqdm
+
+Latest development release on GitHub
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+|GitHub-Status| |GitHub-Stars| |GitHub-Commits| |GitHub-Forks| |GitHub-Updated|
+
+Pull and install pre-release ``devel`` branch:
+
+.. code:: sh
+
+ pip install "git+https://github.com/tqdm/tqdm.git@devel#egg=tqdm"
+
+Latest Conda release
+~~~~~~~~~~~~~~~~~~~~
+
+|Conda-Forge-Status|
+
+.. code:: sh
+
+ conda install -c conda-forge tqdm
+
+Latest Snapcraft release
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+|Snapcraft|
+
+There are 3 channels to choose from:
+
+.. code:: sh
+
+ snap install tqdm # implies --stable, i.e. latest tagged release
+ snap install tqdm --candidate # master branch
+ snap install tqdm --edge # devel branch
+
+Note that ``snap`` binaries are purely for CLI use (not ``import``-able), and
+automatically set up ``bash`` tab-completion.
+
+Latest Docker release
+~~~~~~~~~~~~~~~~~~~~~
+
+|Docker|
+
+.. code:: sh
+
+ docker pull tqdm/tqdm
+ docker run -i --rm tqdm/tqdm --help
+
+Other
+~~~~~
+
+There are other (unofficial) places where ``tqdm`` may be downloaded, particularly for CLI use:
+
+|Repology|
+
+.. |Repology| image:: https://repology.org/badge/tiny-repos/python:tqdm.svg
+ :target: https://repology.org/project/python:tqdm/versions
+
+Changelog
+---------
+
+The list of all changes is available either on GitHub's Releases:
+|GitHub-Status|, on the
+`wiki <https://github.com/tqdm/tqdm/wiki/Releases>`__, or on the
+`website <https://tqdm.github.io/releases>`__.
+
+
+Usage
+-----
+
+``tqdm`` is very versatile and can be used in a number of ways.
+The three main ones are given below.
+
+Iterable-based
+~~~~~~~~~~~~~~
+
+Wrap ``tqdm()`` around any iterable:
+
+.. code:: python
+
+ from tqdm import tqdm
+ from time import sleep
+
+ text = ""
+ for char in tqdm(["a", "b", "c", "d"]):
+ sleep(0.25)
+ text = text + char
+
+``trange(i)`` is a special optimised instance of ``tqdm(range(i))``:
+
+.. code:: python
+
+ from tqdm import trange
+
+ for i in trange(100):
+ sleep(0.01)
+
+Instantiation outside of the loop allows for manual control over ``tqdm()``:
+
+.. code:: python
+
+ pbar = tqdm(["a", "b", "c", "d"])
+ for char in pbar:
+ sleep(0.25)
+ pbar.set_description("Processing %s" % char)
+
+Manual
+~~~~~~
+
+Manual control of ``tqdm()`` updates using a ``with`` statement:
+
+.. code:: python
+
+ with tqdm(total=100) as pbar:
+ for i in range(10):
+ sleep(0.1)
+ pbar.update(10)
+
+If the optional variable ``total`` (or an iterable with ``len()``) is
+provided, predictive stats are displayed.
+
+``with`` is also optional (you can just assign ``tqdm()`` to a variable,
+but in this case don't forget to ``del`` or ``close()`` at the end:
+
+.. code:: python
+
+ pbar = tqdm(total=100)
+ for i in range(10):
+ sleep(0.1)
+ pbar.update(10)
+ pbar.close()
+
+Module
+~~~~~~
+
+Perhaps the most wonderful use of ``tqdm`` is in a script or on the command
+line. Simply inserting ``tqdm`` (or ``python -m tqdm``) between pipes will pass
+through all ``stdin`` to ``stdout`` while printing progress to ``stderr``.
+
+The example below demonstrate counting the number of lines in all Python files
+in the current directory, with timing information included.
+
+.. code:: sh
+
+ $ time find . -name '*.py' -type f -exec cat \{} \; | wc -l
+ 857365
+
+ real 0m3.458s
+ user 0m0.274s
+ sys 0m3.325s
+
+ $ time find . -name '*.py' -type f -exec cat \{} \; | tqdm | wc -l
+ 857366it [00:03, 246471.31it/s]
+ 857365
+
+ real 0m3.585s
+ user 0m0.862s
+ sys 0m3.358s
+
+Note that the usual arguments for ``tqdm`` can also be specified.
+
+.. code:: sh
+
+ $ find . -name '*.py' -type f -exec cat \{} \; |
+ tqdm --unit loc --unit_scale --total 857366 >> /dev/null
+ 100%|█████████████████████████████████| 857K/857K [00:04<00:00, 246Kloc/s]
+
+Backing up a large directory?
+
+.. code:: sh
+
+ $ tar -zcf - docs/ | tqdm --bytes --total `du -sb docs/ | cut -f1` \
+ > backup.tgz
+ 44%|██████████████▊ | 153M/352M [00:14<00:18, 11.0MB/s]
+
+This can be beautified further:
+
+.. code:: sh
+
+ $ BYTES="$(du -sb docs/ | cut -f1)"
+ $ tar -cf - docs/ \
+ | tqdm --bytes --total "$BYTES" --desc Processing | gzip \
+ | tqdm --bytes --total "$BYTES" --desc Compressed --position 1 \
+ > ~/backup.tgz
+ Processing: 100%|██████████████████████| 352M/352M [00:14<00:00, 30.2MB/s]
+ Compressed: 42%|█████████▎ | 148M/352M [00:14<00:19, 10.9MB/s]
+
+Or done on a file level using 7-zip:
+
+.. code:: sh
+
+ $ 7z a -bd -r backup.7z docs/ | grep Compressing \
+ | tqdm --total $(find docs/ -type f | wc -l) --unit files \
+ | grep -v Compressing
+ 100%|██████████████████████████▉| 15327/15327 [01:00<00:00, 712.96files/s]
+
+Pre-existing CLI programs already outputting basic progress information will
+benefit from ``tqdm``'s ``--update`` and ``--update_to`` flags:
+
+.. code:: sh
+
+ $ seq 3 0.1 5 | tqdm --total 5 --update_to --null
+ 100%|████████████████████████████████████| 5.0/5 [00:00<00:00, 9673.21it/s]
+ $ seq 10 | tqdm --update --null # 1 + 2 + ... + 10 = 55 iterations
+ 55it [00:00, 90006.52it/s]
+
+FAQ and Known Issues
+--------------------
+
+|GitHub-Issues|
+
+The most common issues relate to excessive output on multiple lines, instead
+of a neat one-line progress bar.
+
+- Consoles in general: require support for carriage return (``CR``, ``\r``).
+- Nested progress bars:
+
+ * Consoles in general: require support for moving cursors up to the
+ previous line. For example,
+ `IDLE <https://github.com/tqdm/tqdm/issues/191#issuecomment-230168030>`__,
+ `ConEmu <https://github.com/tqdm/tqdm/issues/254>`__ and
+ `PyCharm <https://github.com/tqdm/tqdm/issues/203>`__ (also
+ `here <https://github.com/tqdm/tqdm/issues/208>`__,
+ `here <https://github.com/tqdm/tqdm/issues/307>`__, and
+ `here <https://github.com/tqdm/tqdm/issues/454#issuecomment-335416815>`__)
+ lack full support.
+ * Windows: additionally may require the Python module ``colorama``
+ to ensure nested bars stay within their respective lines.
+
+- Unicode:
+
+ * Environments which report that they support unicode will have solid smooth
+ progressbars. The fallback is an ``ascii``-only bar.
+ * Windows consoles often only partially support unicode and thus
+ `often require explicit ascii=True <https://github.com/tqdm/tqdm/issues/454#issuecomment-335416815>`__
+ (also `here <https://github.com/tqdm/tqdm/issues/499>`__). This is due to
+ either normal-width unicode characters being incorrectly displayed as
+ "wide", or some unicode characters not rendering.
+
+- Wrapping generators:
+
+ * Generator wrapper functions tend to hide the length of iterables.
+ ``tqdm`` does not.
+ * Replace ``tqdm(enumerate(...))`` with ``enumerate(tqdm(...))`` or
+ ``tqdm(enumerate(x), total=len(x), ...)``.
+ The same applies to ``numpy.ndenumerate``.
+ * Replace ``tqdm(zip(a, b))`` with ``zip(tqdm(a), b)`` or even
+ ``zip(tqdm(a), tqdm(b))``.
+ * The same applies to ``itertools``.
+ * Some useful convenience functions can be found under ``tqdm.contrib``.
+
+- `Hanging pipes in python2 <https://github.com/tqdm/tqdm/issues/359>`__:
+ when using ``tqdm`` on the CLI, you may need to use Python 3.5+ for correct
+ buffering.
+- `No intermediate output in docker-compose <https://github.com/tqdm/tqdm/issues/771>`__:
+ use ``docker-compose run`` instead of ``docker-compose up`` and ``tty: true``.
+
+If you come across any other difficulties, browse and file |GitHub-Issues|.
+
+Documentation
+-------------
+
+|Py-Versions| |README-Hits| (Since 19 May 2016)
+
+.. code:: python
+
+ class tqdm():
+ """
+ Decorate an iterable object, returning an iterator which acts exactly
+ like the original iterable, but prints a dynamically updating
+ progressbar every time a value is requested.
+ """
+
+ 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):
+
+Parameters
+~~~~~~~~~~
+
+* iterable : iterable, optional
+ Iterable to decorate with a progressbar.
+ Leave blank to manually manage the updates.
+* desc : str, optional
+ Prefix for the progressbar.
+* total : int or float, optional
+ The number of expected iterations. If unspecified,
+ len(iterable) is used if possible. If float("inf") or as a last
+ resort, only basic progress statistics are displayed
+ (no ETA, no progressbar).
+ If ``gui`` is True and this parameter needs subsequent updating,
+ specify an initial arbitrary large positive number,
+ e.g. 9e9.
+* leave : bool, optional
+ If [default: True], keeps all traces of the progressbar
+ upon termination of iteration.
+ If ``None``, will leave only if ``position`` is ``0``.
+* file : ``io.TextIOWrapper`` or ``io.StringIO``, optional
+ Specifies where to output the progress messages
+ (default: sys.stderr). Uses ``file.write(str)`` and ``file.flush()``
+ methods. For encoding, see ``write_bytes``.
+* ncols : int, optional
+ The width of the entire output message. If specified,
+ dynamically resizes the progressbar to stay within this bound.
+ If unspecified, attempts to use environment width. The
+ fallback is a meter width of 10 and no limit for the counter and
+ statistics. If 0, will not print any meter (only stats).
+* mininterval : float, optional
+ Minimum progress display update interval [default: 0.1] seconds.
+* maxinterval : float, optional
+ Maximum progress display update interval [default: 10] seconds.
+ Automatically adjusts ``miniters`` to correspond to ``mininterval``
+ after long display update lag. Only works if ``dynamic_miniters``
+ or monitor thread is enabled.
+* miniters : int or float, optional
+ Minimum progress display update interval, in iterations.
+ If 0 and ``dynamic_miniters``, will automatically adjust to equal
+ ``mininterval`` (more CPU efficient, good for tight loops).
+ If > 0, will skip display of specified number of iterations.
+ Tweak this and ``mininterval`` to get very efficient loops.
+ If your progress is erratic with both fast and slow iterations
+ (network, skipping items, etc) you should set miniters=1.
+* ascii : bool or str, optional
+ If unspecified or False, use unicode (smooth blocks) to fill
+ the meter. The fallback is to use ASCII characters " 123456789#".
+* disable : bool, optional
+ Whether to disable the entire progressbar wrapper
+ [default: False]. If set to None, disable on non-TTY.
+* unit : str, optional
+ String that will be used to define the unit of each iteration
+ [default: it].
+* unit_scale : 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 Units standard will be added
+ (kilo, mega, etc.) [default: False]. If any other non-zero
+ number, will scale ``total`` and ``n``.
+* dynamic_ncols : bool, optional
+ If set, constantly alters ``ncols`` and ``nrows`` to the
+ environment (allowing for window resizes) [default: False].
+* smoothing : float, optional
+ Exponential moving average smoothing factor for speed estimates
+ (ignored in GUI mode). Ranges from 0 (average speed) to 1
+ (current/instantaneous speed) [default: 0.3].
+* bar_format : str, optional
+ Specify a custom bar string formatting. May impact performance.
+ [default: '{l_bar}{bar}{r_bar}'], where
+ l_bar='{desc}: {percentage:3.0f}%|' and
+ r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, '
+ '{rate_fmt}{postfix}]'
+ Possible 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, eta.
+ Note that a trailing ": " is automatically removed after {desc}
+ if the latter is empty.
+* initial : int or float, optional
+ The initial counter value. Useful when restarting a progress
+ bar [default: 0]. If using float, consider specifying ``{n:.3f}``
+ or similar in ``bar_format``, or specifying ``unit_scale``.
+* position : int, optional
+ Specify the line offset to print this bar (starting from 0)
+ Automatic if unspecified.
+ Useful to manage multiple bars at once (eg, from threads).
+* postfix : dict or ``*``, optional
+ Specify additional stats to display at the end of the bar.
+ Calls ``set_postfix(**postfix)`` if possible (dict).
+* unit_divisor : float, optional
+ [default: 1000], ignored unless ``unit_scale`` is True.
+* write_bytes : bool, optional
+ If (default: None) and ``file`` is unspecified,
+ bytes will be written in Python 2. If ``True`` will also write
+ bytes. In all other cases will default to unicode.
+* lock_args : tuple, optional
+ Passed to ``refresh`` for intermediate output
+ (initialisation, iterating, and updating).
+* nrows : int, optional
+ 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.
+
+Extra CLI Options
+~~~~~~~~~~~~~~~~~
+
+* delim : chr, optional
+ Delimiting character [default: '\n']. Use '\0' for null.
+ N.B.: on Windows systems, Python converts '\n' to '\r\n'.
+* buf_size : int, optional
+ String buffer size in bytes [default: 256]
+ used when ``delim`` is specified.
+* 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
+ Directory in which to place tqdm completion.
+* log : str, optional
+ CRITICAL|FATAL|ERROR|WARN(ING)|[default: 'INFO']|DEBUG|NOTSET.
+
+Returns
+~~~~~~~
+
+* out : decorated iterator.
+
+.. code:: python
+
+ class tqdm():
+ def update(self, n=1):
+ """
+ Manually update the progress bar, useful for streams
+ such as reading files.
+ E.g.:
+ >>> t = tqdm(total=filesize) # Initialise
+ >>> for current_buffer in stream:
+ ... ...
+ ... t.update(len(current_buffer))
+ >>> t.close()
+ The last line is highly recommended, but possibly not necessary if
+ ``t.update()`` will be called in such a way that ``filesize`` will be
+ exactly reached and printed.
+
+ Parameters
+ ----------
+ n : int or float, optional
+ 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.
+ """
+
+ def close(self):
+ """Cleanup and (if leave=False) close the progressbar."""
+
+ def clear(self, nomove=False):
+ """Clear current bar display."""
+
+ def refresh(self):
+ """
+ Force refresh the display of this bar.
+
+ Parameters
+ ----------
+ nolock : bool, optional
+ If ``True``, does not lock.
+ If [default: ``False``]: calls ``acquire()`` on internal lock.
+ lock_args : tuple, optional
+ Passed to internal lock's ``acquire()``.
+ If specified, will only ``display()`` if ``acquire()`` returns ``True``.
+ """
+
+ def unpause(self):
+ """Restart tqdm timer from last print time."""
+
+ def reset(self, total=None):
+ """
+ Resets to 0 iterations for repeated use.
+
+ Consider combining with ``leave=True``.
+
+ Parameters
+ ----------
+ total : int or float, optional. Total to use for the new bar.
+ """
+
+ def set_description(self, desc=None, refresh=True):
+ """
+ Set/modify description of the progress bar.
+
+ Parameters
+ ----------
+ desc : str, optional
+ refresh : bool, optional
+ Forces refresh [default: True].
+ """
+
+ def set_postfix(self, ordered_dict=None, refresh=True, **tqdm_kwargs):
+ """
+ Set/modify postfix (additional stats)
+ with automatic formatting based on datatype.
+
+ Parameters
+ ----------
+ ordered_dict : dict or OrderedDict, optional
+ refresh : bool, optional
+ Forces refresh [default: True].
+ kwargs : dict, optional
+ """
+
+ @classmethod
+ def write(cls, s, file=sys.stdout, end="\n"):
+ """Print a message via tqdm (without overlap with bars)."""
+
+ @property
+ def format_dict(self):
+ """Public API for read-only member access."""
+
+ def display(self, msg=None, pos=None):
+ """
+ Use ``self.sp`` to display ``msg`` in the specified ``pos``.
+
+ Consider overloading this function when inheriting to use e.g.:
+ ``self.some_frontend(**self.format_dict)`` instead of ``self.sp``.
+
+ Parameters
+ ----------
+ msg : str, optional. What to display (default: ``repr(self)``).
+ pos : int, optional. Position to ``moveto``
+ (default: ``abs(self.pos)``).
+ """
+
+ @classmethod
+ @contextmanager
+ 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
+ the first argument of ``write()`` should have a ``len()``.
+
+ >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj:
+ ... while True:
+ ... chunk = fobj.read(chunk_size)
+ ... if not chunk:
+ ... break
+ """
+
+ @classmethod
+ def pandas(cls, *targs, **tqdm_kwargs):
+ """Registers the current `tqdm` class with `pandas`."""
+
+ def trange(*args, **tqdm_kwargs):
+ """
+ A shortcut for `tqdm(xrange(*args), **tqdm_kwargs)`.
+ On Python3+, `range` is used instead of `xrange`.
+ """
+
+Convenience Functions
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+ def tqdm.contrib.tenumerate(iterable, start=0, total=None,
+ tqdm_class=tqdm.auto.tqdm, **tqdm_kwargs):
+ """Equivalent of `numpy.ndenumerate` or builtin `enumerate`."""
+
+ def tqdm.contrib.tzip(iter1, *iter2plus, **tqdm_kwargs):
+ """Equivalent of builtin `zip`."""
+
+ def tqdm.contrib.tmap(function, *sequences, **tqdm_kwargs):
+ """Equivalent of builtin `map`."""
+
+Submodules
+~~~~~~~~~~
+
+.. code:: python
+
+ class tqdm.notebook.tqdm(tqdm.tqdm):
+ """IPython/Jupyter Notebook widget."""
+
+ class tqdm.auto.tqdm(tqdm.tqdm):
+ """Automatically chooses beween `tqdm.notebook` and `tqdm.tqdm`."""
+
+ class tqdm.asyncio.tqdm(tqdm.tqdm):
+ """Asynchronous version."""
+ @classmethod
+ def as_completed(cls, fs, *, loop=None, timeout=None, total=None,
+ **tqdm_kwargs):
+ """Wrapper for `asyncio.as_completed`."""
+
+ class tqdm.gui.tqdm(tqdm.tqdm):
+ """Matplotlib GUI version."""
+
+ class tqdm.tk.tqdm(tqdm.tqdm):
+ """Tkinter GUI version."""
+
+ class tqdm.rich.tqdm(tqdm.tqdm):
+ """`rich.progress` version."""
+
+ class tqdm.keras.TqdmCallback(keras.callbacks.Callback):
+ """Keras callback for epoch and batch progress."""
+
+ class tqdm.dask.TqdmCallback(dask.callbacks.Callback):
+ """Dask callback for task progress."""
+
+
+``contrib``
++++++++++++
+
+The ``tqdm.contrib`` package also contains experimental modules:
+
+- ``tqdm.contrib.itertools``: Thin wrappers around ``itertools``
+- ``tqdm.contrib.concurrent``: Thin wrappers around ``concurrent.futures``
+- ``tqdm.contrib.discord``: Posts to `Discord <https://discord.com>`__ bots
+- ``tqdm.contrib.telegram``: Posts to `Telegram <https://telegram.org>`__ bots
+- ``tqdm.contrib.bells``: Automagically enables all optional features
+
+ * ``auto``, ``pandas``, ``discord``, ``telegram``
+
+Examples and Advanced Usage
+---------------------------
+
+- See the `examples <https://github.com/tqdm/tqdm/tree/master/examples>`__
+ folder;
+- import the module and run ``help()``;
+- consult the `wiki <https://github.com/tqdm/tqdm/wiki>`__;
+
+ * this has an
+ `excellent article <https://github.com/tqdm/tqdm/wiki/How-to-make-a-great-Progress-Bar>`__
+ on how to make a **great** progressbar;
+
+- check out the `slides from PyData London <https://tqdm.github.io/PyData2019/slides.html>`__, or
+- run the |binder-demo|.
+
+Description and additional stats
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Custom information can be displayed and updated dynamically on ``tqdm`` bars
+with the ``desc`` and ``postfix`` arguments:
+
+.. code:: python
+
+ from tqdm import tqdm, trange
+ from random import random, randint
+ from time import sleep
+
+ with trange(10) as t:
+ for i in t:
+ # Description will be displayed on the left
+ t.set_description('GEN %i' % i)
+ # Postfix will be displayed on the right,
+ # formatted automatically based on argument's datatype
+ t.set_postfix(loss=random(), gen=randint(1,999), str='h',
+ lst=[1, 2])
+ sleep(0.1)
+
+ with tqdm(total=10, bar_format="{postfix[0]} {postfix[1][value]:>8.2g}",
+ postfix=["Batch", dict(value=0)]) as t:
+ for i in range(10):
+ sleep(0.1)
+ t.postfix[1]["value"] = i / 2
+ t.update()
+
+Points to remember when using ``{postfix[...]}`` in the ``bar_format`` string:
+
+- ``postfix`` also needs to be passed as an initial argument in a compatible
+ format, and
+- ``postfix`` will be auto-converted to a string if it is a ``dict``-like
+ object. To prevent this behaviour, insert an extra item into the dictionary
+ where the key is not a string.
+
+Additional ``bar_format`` parameters may also be defined by overriding
+``format_dict``, and the bar itself may be modified using ``ascii``:
+
+.. code:: python
+
+ from tqdm import tqdm
+ 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
+
+ for i in TqdmExtraFormat(
+ range(9), ascii=" .oO0",
+ bar_format="{total_time}: {percentage:.0f}%|{bar}{r_bar}"):
+ if i == 4:
+ break
+
+.. code::
+
+ 00:00 in total: 44%|0000. | 4/9 [00:00<00:00, 962.93it/s]
+
+Note that ``{bar}`` also supports a format specifier ``[width][type]``.
+
+- ``width``
+
+ * unspecified (default): automatic to fill ``ncols``
+ * ``int >= 0``: fixed width overriding ``ncols`` logic
+ * ``int < 0``: subtract from the automatic default
+
+- ``type``
+
+ * ``a``: ascii (``ascii=True`` override)
+ * ``u``: unicode (``ascii=False`` override)
+ * ``b``: blank (``ascii=" "`` override)
+
+This means a fixed bar with right-justified text may be created by using:
+``bar_format="{l_bar}{bar:10}|{bar:-10b}right-justified"``
+
+Nested progress bars
+~~~~~~~~~~~~~~~~~~~~
+
+``tqdm`` supports nested progress bars. Here's an example:
+
+.. code:: python
+
+ from tqdm.auto import trange
+ from time import sleep
+
+ for i in trange(4, desc='1st loop'):
+ for j in trange(5, desc='2nd loop'):
+ for k in trange(50, desc='3rd loop', leave=False):
+ sleep(0.01)
+
+For manual control over positioning (e.g. for multi-processing use),
+you may specify ``position=n`` where ``n=0`` for the outermost bar,
+``n=1`` for the next, and so on.
+However, it's best to check if ``tqdm`` can work without manual ``position``
+first.
+
+.. code:: python
+
+ from time import sleep
+ from tqdm import trange, tqdm
+ from multiprocessing import Pool, RLock, freeze_support
+
+ L = list(range(9))
+
+ def progresser(n):
+ interval = 0.001 / (n + 2)
+ total = 5000
+ text = "#{}, est. {:<04.2}s".format(n, interval * total)
+ for _ in trange(total, desc=text, position=n):
+ sleep(interval)
+
+ if __name__ == '__main__':
+ freeze_support() # for Windows support
+ tqdm.set_lock(RLock()) # for managing output contention
+ p = Pool(initializer=tqdm.set_lock, initargs=(tqdm.get_lock(),))
+ p.map(progresser, L)
+
+Note that in Python 3, ``tqdm.write`` is thread-safe:
+
+.. code:: python
+
+ from time import sleep
+ from tqdm import tqdm, trange
+ from concurrent.futures import ThreadPoolExecutor
+
+ L = list(range(9))
+
+ def progresser(n):
+ interval = 0.001 / (n + 2)
+ total = 5000
+ text = "#{}, est. {:<04.2}s".format(n, interval * total)
+ for _ in trange(total, desc=text):
+ sleep(interval)
+ if n == 6:
+ tqdm.write("n == 6 completed.")
+ tqdm.write("`tqdm.write()` is thread-safe in py3!")
+
+ if __name__ == '__main__':
+ with ThreadPoolExecutor() as p:
+ p.map(progresser, L)
+
+Hooks and callbacks
+~~~~~~~~~~~~~~~~~~~
+
+``tqdm`` can easily support callbacks/hooks and manual updates.
+Here's an example with ``urllib``:
+
+**``urllib.urlretrieve`` documentation**
+
+ | [...]
+ | If present, the hook function will be called once
+ | on establishment of the network connection and once after each block read
+ | thereafter. The hook will be passed three arguments; a count of blocks
+ | transferred so far, a block size in bytes, and the total size of the file.
+ | [...]
+
+.. code:: python
+
+ import urllib, os
+ from tqdm import tqdm
+ urllib = getattr(urllib, 'request', urllib)
+
+ class TqdmUpTo(tqdm):
+ """Provides `update_to(n)` which uses `tqdm.update(delta_n)`."""
+ def update_to(self, b=1, bsize=1, tsize=None):
+ """
+ b : int, optional
+ Number of blocks transferred so far [default: 1].
+ bsize : int, optional
+ Size of each block (in tqdm units) [default: 1].
+ tsize : int, optional
+ Total size (in tqdm units). If [default: None] remains unchanged.
+ """
+ if tsize is not None:
+ self.total = tsize
+ return self.update(b * bsize - self.n) # also sets self.n = b * bsize
+
+ eg_link = "https://caspersci.uk.to/matryoshka.zip"
+ with TqdmUpTo(unit='B', unit_scale=True, unit_divisor=1024, miniters=1,
+ desc=eg_link.split('/')[-1]) as t: # all optional kwargs
+ urllib.urlretrieve(eg_link, filename=os.devnull,
+ reporthook=t.update_to, data=None)
+ t.total = t.n
+
+Inspired by `twine#242 <https://github.com/pypa/twine/pull/242>`__.
+Functional alternative in
+`examples/tqdm_wget.py <https://github.com/tqdm/tqdm/blob/master/examples/tqdm_wget.py>`__.
+
+It is recommend to use ``miniters=1`` whenever there is potentially
+large differences in iteration speed (e.g. downloading a file over
+a patchy connection).
+
+**Wrapping read/write methods**
+
+To measure throughput through a file-like object's ``read`` or ``write``
+methods, use ``CallbackIOWrapper``:
+
+.. code:: python
+
+ from tqdm.auto import tqdm
+ from tqdm.utils import CallbackIOWrapper
+
+ with tqdm(total=file_obj.size,
+ unit='B', unit_scale=True, unit_divisor=1024) as t:
+ fobj = CallbackIOWrapper(t.update, file_obj, "read")
+ while True:
+ chunk = fobj.read(chunk_size)
+ if not chunk:
+ break
+ t.reset()
+ # ... continue to use `t` for something else
+
+Alternatively, use the even simpler ``wrapattr`` convenience function,
+which would condense both the ``urllib`` and ``CallbackIOWrapper`` examples
+down to:
+
+.. code:: python
+
+ import urllib, os
+ from tqdm import tqdm
+
+ eg_link = "https://caspersci.uk.to/matryoshka.zip"
+ response = getattr(urllib, 'request', urllib).urlopen(eg_link)
+ with tqdm.wrapattr(open(os.devnull, "wb"), "write",
+ miniters=1, desc=eg_link.split('/')[-1],
+ total=getattr(response, 'length', None)) as fout:
+ for chunk in response:
+ fout.write(chunk)
+
+The ``requests`` equivalent is nearly identical:
+
+.. code:: python
+
+ import requests, os
+ from tqdm import tqdm
+
+ eg_link = "https://caspersci.uk.to/matryoshka.zip"
+ response = requests.get(eg_link, stream=True)
+ with tqdm.wrapattr(open(os.devnull, "wb"), "write",
+ miniters=1, desc=eg_link.split('/')[-1],
+ total=int(response.headers.get('content-length', 0))) as fout:
+ for chunk in response.iter_content(chunk_size=4096):
+ fout.write(chunk)
+
+**Custom callback**
+
+``tqdm`` is known for intelligently skipping unnecessary displays. To make a
+custom callback take advantage of this, simply use the return value of
+``update()``. This is set to ``True`` if a ``display()`` was triggered.
+
+.. code:: python
+
+ from tqdm.auto import tqdm as std_tqdm
+
+ def external_callback(*args, **kwargs):
+ ...
+
+ class TqdmExt(std_tqdm):
+ def update(self, n=1):
+ displayed = super(TqdmExt, self).update(n):
+ if displayed:
+ external_callback(**self.format_dict)
+ return displayed
+
+``asyncio``
+~~~~~~~~~~~
+
+Note that ``break`` isn't currently caught by asynchronous iterators.
+This means that ``tqdm`` cannot clean up after itself in this case:
+
+.. code:: python
+
+ from tqdm.asyncio import tqdm
+
+ async for i in tqdm(range(9)):
+ if i == 2:
+ break
+
+Instead, either call ``pbar.close()`` manually or use the context manager syntax:
+
+.. code:: python
+
+ from tqdm.asyncio import tqdm
+
+ with tqdm(range(9)) as pbar:
+ async for i in pbar:
+ if i == 2:
+ break
+
+Pandas Integration
+~~~~~~~~~~~~~~~~~~
+
+Due to popular demand we've added support for ``pandas`` -- here's an example
+for ``DataFrame.progress_apply`` and ``DataFrameGroupBy.progress_apply``:
+
+.. code:: python
+
+ import pandas as pd
+ import numpy as np
+ from tqdm import tqdm
+
+ df = pd.DataFrame(np.random.randint(0, 100, (100000, 6)))
+
+ # Register `pandas.progress_apply` and `pandas.Series.map_apply` with `tqdm`
+ # (can use `tqdm.gui.tqdm`, `tqdm.notebook.tqdm`, optional kwargs, etc.)
+ tqdm.pandas(desc="my bar!")
+
+ # Now you can use `progress_apply` instead of `apply`
+ # and `progress_map` instead of `map`
+ df.progress_apply(lambda x: x**2)
+ # can also groupby:
+ # df.groupby(0).progress_apply(lambda x: x**2)
+
+In case you're interested in how this works (and how to modify it for your
+own callbacks), see the
+`examples <https://github.com/tqdm/tqdm/tree/master/examples>`__
+folder or import the module and run ``help()``.
+
+Keras Integration
+~~~~~~~~~~~~~~~~~
+
+A ``keras`` callback is also available:
+
+.. code:: python
+
+ from tqdm.keras import TqdmCallback
+
+ ...
+
+ model.fit(..., verbose=0, callbacks=[TqdmCallback()])
+
+Dask Integration
+~~~~~~~~~~~~~~~~
+
+A ``dask`` callback is also available:
+
+.. code:: python
+
+ from tqdm.dask import TqdmCallback
+
+ with TqdmCallback(desc="compute"):
+ ...
+ arr.compute()
+
+ # or use callback globally
+ cb = TqdmCallback(desc="global")
+ cb.register()
+ arr.compute()
+
+IPython/Jupyter Integration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+IPython/Jupyter is supported via the ``tqdm.notebook`` submodule:
+
+.. code:: python
+
+ from tqdm.notebook import trange, tqdm
+ from time import sleep
+
+ for i in trange(3, desc='1st loop'):
+ for j in tqdm(range(100), desc='2nd loop'):
+ sleep(0.01)
+
+In addition to ``tqdm`` features, the submodule provides a native Jupyter
+widget (compatible with IPython v1-v4 and Jupyter), fully working nested bars
+and colour hints (blue: normal, green: completed, red: error/interrupt,
+light blue: no ETA); as demonstrated below.
+
+|Screenshot-Jupyter1|
+|Screenshot-Jupyter2|
+|Screenshot-Jupyter3|
+
+The ``notebook`` version supports percentage or pixels for overall width
+(e.g.: ``ncols='100%'`` or ``ncols='480px'``).
+
+It is also possible to let ``tqdm`` automatically choose between
+console or notebook versions by using the ``autonotebook`` submodule:
+
+.. code:: python
+
+ from tqdm.autonotebook import tqdm
+ tqdm.pandas()
+
+Note that this will issue a ``TqdmExperimentalWarning`` if run in a notebook
+since it is not meant to be possible to distinguish between ``jupyter notebook``
+and ``jupyter console``. Use ``auto`` instead of ``autonotebook`` to suppress
+this warning.
+
+Note that notebooks will display the bar in the cell where it was created.
+This may be a different cell from the one where it is used.
+If this is not desired, either
+
+- delay the creation of the bar to the cell where it must be displayed, or
+- create the bar with ``display=False``, and in a later cell call
+ ``display(bar.container)``:
+
+.. code:: python
+
+ from tqdm.notebook import tqdm
+ pbar = tqdm(..., display=False)
+
+.. code:: python
+
+ # different cell
+ display(pbar.container)
+
+The ``keras`` callback has a ``display()`` method which can be used likewise:
+
+.. code:: python
+
+ from tqdm.keras import TqdmCallback
+ cbk = TqdmCallback(display=False)
+
+.. code:: python
+
+ # different cell
+ cbk.display()
+ model.fit(..., verbose=0, callbacks=[cbk])
+
+Another possibility is to have a single bar (near the top of the notebook)
+which is constantly re-used (using ``reset()`` rather than ``close()``).
+For this reason, the notebook version (unlike the CLI version) does not
+automatically call ``close()`` upon ``Exception``.
+
+.. code:: python
+
+ from tqdm.notebook import tqdm
+ pbar = tqdm()
+
+.. code:: python
+
+ # different cell
+ iterable = range(100)
+ pbar.reset(total=len(iterable)) # initialise with new `total`
+ for i in iterable:
+ pbar.update()
+ pbar.refresh() # force print final status but don't `close()`
+
+Custom Integration
+~~~~~~~~~~~~~~~~~~
+
+To change the default arguments (such as making ``dynamic_ncols=True``),
+simply use built-in Python magic:
+
+.. code:: python
+
+ from functools import partial
+ from tqdm import tqdm as std_tqdm
+ tqdm = partial(std_tqdm, dynamic_ncols=True)
+
+For further customisation,
+``tqdm`` may be inherited from to create custom callbacks (as with the
+``TqdmUpTo`` example `above <#hooks-and-callbacks>`__) or for custom frontends
+(e.g. GUIs such as notebook or plotting packages). In the latter case:
+
+1. ``def __init__()`` to call ``super().__init__(..., gui=True)`` to disable
+ terminal ``status_printer`` creation.
+2. Redefine: ``close()``, ``clear()``, ``display()``.
+
+Consider overloading ``display()`` to use e.g.
+``self.frontend(**self.format_dict)`` instead of ``self.sp(repr(self))``.
+
+Some submodule examples of inheritance:
+
+- `tqdm/notebook.py <https://github.com/tqdm/tqdm/blob/master/tqdm/notebook.py>`__
+- `tqdm/gui.py <https://github.com/tqdm/tqdm/blob/master/tqdm/gui.py>`__
+- `tqdm/tk.py <https://github.com/tqdm/tqdm/blob/master/tqdm/tk.py>`__
+- `tqdm/contrib/telegram.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/telegram.py>`__
+- `tqdm/contrib/discord.py <https://github.com/tqdm/tqdm/blob/master/tqdm/contrib/discord.py>`__
+
+Dynamic Monitor/Meter
+~~~~~~~~~~~~~~~~~~~~~
+
+You can use a ``tqdm`` as a meter which is not monotonically increasing.
+This could be because ``n`` decreases (e.g. a CPU usage monitor) or ``total``
+changes.
+
+One example would be recursively searching for files. The ``total`` is the
+number of objects found so far, while ``n`` is the number of those objects which
+are files (rather than folders):
+
+.. code:: python
+
+ from tqdm import tqdm
+ import os.path
+
+ def find_files_recursively(path, show_progress=True):
+ files = []
+ # total=1 assumes `path` is a file
+ t = tqdm(total=1, unit="file", disable=not show_progress)
+ if not os.path.exists(path):
+ raise IOError("Cannot find:" + path)
+
+ def append_found_file(f):
+ files.append(f)
+ t.update()
+
+ def list_found_dir(path):
+ """returns os.listdir(path) assuming os.path.isdir(path)"""
+ listing = os.listdir(path)
+ # subtract 1 since a "file" we found was actually this directory
+ t.total += len(listing) - 1
+ # fancy way to give info without forcing a refresh
+ t.set_postfix(dir=path[-10:], refresh=False)
+ t.update(0) # may trigger a refresh
+ return listing
+
+ def recursively_search(path):
+ if os.path.isdir(path):
+ for f in list_found_dir(path):
+ recursively_search(os.path.join(path, f))
+ else:
+ append_found_file(path)
+
+ recursively_search(path)
+ t.set_postfix(dir=path)
+ t.close()
+ return files
+
+Using ``update(0)`` is a handy way to let ``tqdm`` decide when to trigger a
+display refresh to avoid console spamming.
+
+Writing messages
+~~~~~~~~~~~~~~~~
+
+This is a work in progress (see
+`#737 <https://github.com/tqdm/tqdm/issues/737>`__).
+
+Since ``tqdm`` uses a simple printing mechanism to display progress bars,
+you should not write any message in the terminal using ``print()`` while
+a progressbar is open.
+
+To write messages in the terminal without any collision with ``tqdm`` bar
+display, a ``.write()`` method is provided:
+
+.. code:: python
+
+ from tqdm.auto import tqdm, trange
+ from time import sleep
+
+ bar = trange(10)
+ for i in bar:
+ # Print using tqdm class method .write()
+ sleep(0.1)
+ if not (i % 3):
+ tqdm.write("Done task %i" % i)
+ # Can also use bar.write()
+
+By default, this will print to standard output ``sys.stdout``. but you can
+specify any file-like object using the ``file`` argument. For example, this
+can be used to redirect the messages writing to a log file or class.
+
+Redirecting writing
+~~~~~~~~~~~~~~~~~~~
+
+If using a library that can print messages to the console, editing the library
+by replacing ``print()`` with ``tqdm.write()`` may not be desirable.
+In that case, redirecting ``sys.stdout`` to ``tqdm.write()`` is an option.
+
+To redirect ``sys.stdout``, create a file-like class that will write
+any input string to ``tqdm.write()``, and supply the arguments
+``file=sys.stdout, dynamic_ncols=True``.
+
+A reusable canonical example is given below:
+
+.. code:: python
+
+ from time import sleep
+ import contextlib
+ import sys
+ from tqdm import tqdm
+ from tqdm.contrib import DummyTqdmFile
+
+
+ @contextlib.contextmanager
+ def std_out_err_redirect_tqdm():
+ orig_out_err = sys.stdout, sys.stderr
+ try:
+ sys.stdout, sys.stderr = map(DummyTqdmFile, orig_out_err)
+ 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
+
+ def some_fun(i):
+ print("Fee, fi, fo,".split()[i])
+
+ # Redirect stdout to tqdm.write() (don't forget the `as save_stdout`)
+ with std_out_err_redirect_tqdm() as orig_stdout:
+ # tqdm needs the original stdout
+ # and dynamic_ncols=True to autodetect console width
+ for i in tqdm(range(3), file=orig_stdout, dynamic_ncols=True):
+ sleep(.5)
+ some_fun(i)
+
+ # After the `with`, printing is restored
+ print("Done!")
+
+Redirecting ``logging``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Similar to ``sys.stdout``/``sys.stderr`` as detailed above, console ``logging``
+may also be redirected to ``tqdm.write()``.
+
+Warning: if also redirecting ``sys.stdout``/``sys.stderr``, make sure to
+redirect ``logging`` first if needed.
+
+Helper methods are available in ``tqdm.contrib.logging``. For example:
+
+.. code:: 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
+
+Monitoring thread, intervals and miniters
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``tqdm`` implements a few tricks to increase efficiency and reduce overhead.
+
+- Avoid unnecessary frequent bar refreshing: ``mininterval`` defines how long
+ to wait between each refresh. ``tqdm`` always gets updated in the background,
+ but it will display only every ``mininterval``.
+- Reduce number of calls to check system clock/time.
+- ``mininterval`` is more intuitive to configure than ``miniters``.
+ A clever adjustment system ``dynamic_miniters`` will automatically adjust
+ ``miniters`` to the amount of iterations that fit into time ``mininterval``.
+ Essentially, ``tqdm`` will check if it's time to print without actually
+ checking time. This behaviour can be still be bypassed by manually setting
+ ``miniters``.
+
+However, consider a case with a combination of fast and slow iterations.
+After a few fast iterations, ``dynamic_miniters`` will set ``miniters`` to a
+large number. When iteration rate subsequently slows, ``miniters`` will
+remain large and thus reduce display update frequency. To address this:
+
+- ``maxinterval`` defines the maximum time between display refreshes.
+ A concurrent monitoring thread checks for overdue updates and forces one
+ where necessary.
+
+The monitoring thread should not have a noticeable overhead, and guarantees
+updates at least every 10 seconds by default.
+This value can be directly changed by setting the ``monitor_interval`` of
+any ``tqdm`` instance (i.e. ``t = tqdm.tqdm(...); t.monitor_interval = 2``).
+The monitor thread may be disabled application-wide by setting
+``tqdm.tqdm.monitor_interval = 0`` before instantiation of any ``tqdm`` bar.
+
+
+Merch
+-----
+
+You can buy `tqdm branded merch <https://tqdm.github.io/merch>`__ now!
+
+Contributions
+-------------
+
+|GitHub-Commits| |GitHub-Issues| |GitHub-PRs| |OpenHub-Status| |GitHub-Contributions| |CII Best Practices|
+
+All source code is hosted on `GitHub <https://github.com/tqdm/tqdm>`__.
+Contributions are welcome.
+
+See the
+`CONTRIBUTING <https://github.com/tqdm/tqdm/blob/master/CONTRIBUTING.md>`__
+file for more information.
+
+Developers who have made significant contributions, ranked by *SLoC*
+(surviving lines of code,
+`git fame <https://github.com/casperdcl/git-fame>`__ ``-wMC --excl '\.(png|gif|jpg)$'``),
+are:
+
+==================== ======================================================== ==== ================================
+Name ID SLoC Notes
+==================== ======================================================== ==== ================================
+Casper da Costa-Luis `casperdcl <https://github.com/casperdcl>`__ ~78% primary maintainer |Gift-Casper|
+Stephen Larroque `lrq3000 <https://github.com/lrq3000>`__ ~10% team member
+Martin Zugnoni `martinzugnoni <https://github.com/martinzugnoni>`__ ~4%
+Daniel Ecer `de-code <https://github.com/de-code>`__ ~2%
+Richard Sheridan `richardsheridan <https://github.com/richardsheridan>`__ ~1%
+Guangshuo Chen `chengs <https://github.com/chengs>`__ ~1%
+Kyle Altendorf `altendky <https://github.com/altendky>`__ <1%
+Matthew Stevens `mjstevens777 <https://github.com/mjstevens777>`__ <1%
+Hadrien Mary `hadim <https://github.com/hadim>`__ <1% team member
+Noam Yorav-Raphael `noamraph <https://github.com/noamraph>`__ <1% original author
+Mikhail Korobov `kmike <https://github.com/kmike>`__ <1% team member
+==================== ======================================================== ==== ================================
+
+Ports to Other Languages
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+A list is available on
+`this wiki page <https://github.com/tqdm/tqdm/wiki/tqdm-ports>`__.
+
+
+LICENCE
+-------
+
+Open Source (OSI approved): |LICENCE|
+
+Citation information: |DOI|
+
+|README-Hits| (Since 19 May 2016)
+
+.. |Logo| image:: https://img.tqdm.ml/logo.gif
+.. |Screenshot| image:: https://img.tqdm.ml/tqdm.gif
+.. |Video| image:: https://img.tqdm.ml/video.jpg
+ :target: https://tqdm.github.io/video
+.. |Slides| image:: https://img.tqdm.ml/slides.jpg
+ :target: https://tqdm.github.io/PyData2019/slides.html
+.. |Merch| image:: https://img.tqdm.ml/merch.jpg
+ :target: https://tqdm.github.io/merch
+.. |Build-Status| image:: https://img.shields.io/github/workflow/status/tqdm/tqdm/Test/master?logo=GitHub
+ :target: https://github.com/tqdm/tqdm/actions?query=workflow%3ATest
+.. |Coverage-Status| image:: https://img.shields.io/coveralls/github/tqdm/tqdm/master?logo=coveralls
+ :target: https://coveralls.io/github/tqdm/tqdm
+.. |Branch-Coverage-Status| image:: https://codecov.io/gh/tqdm/tqdm/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/tqdm/tqdm
+.. |Codacy-Grade| image:: https://app.codacy.com/project/badge/Grade/3f965571598f44549c7818f29cdcf177
+ :target: https://www.codacy.com/gh/tqdm/tqdm/dashboard
+.. |CII Best Practices| image:: https://bestpractices.coreinfrastructure.org/projects/3264/badge
+ :target: https://bestpractices.coreinfrastructure.org/projects/3264
+.. |GitHub-Status| image:: https://img.shields.io/github/tag/tqdm/tqdm.svg?maxAge=86400&logo=github&logoColor=white
+ :target: https://github.com/tqdm/tqdm/releases
+.. |GitHub-Forks| image:: https://img.shields.io/github/forks/tqdm/tqdm.svg?logo=github&logoColor=white
+ :target: https://github.com/tqdm/tqdm/network
+.. |GitHub-Stars| image:: https://img.shields.io/github/stars/tqdm/tqdm.svg?logo=github&logoColor=white
+ :target: https://github.com/tqdm/tqdm/stargazers
+.. |GitHub-Commits| image:: https://img.shields.io/github/commit-activity/y/tqdm/tqdm.svg?logo=git&logoColor=white
+ :target: https://github.com/tqdm/tqdm/graphs/commit-activity
+.. |GitHub-Issues| image:: https://img.shields.io/github/issues-closed/tqdm/tqdm.svg?logo=github&logoColor=white
+ :target: https://github.com/tqdm/tqdm/issues?q=
+.. |GitHub-PRs| image:: https://img.shields.io/github/issues-pr-closed/tqdm/tqdm.svg?logo=github&logoColor=white
+ :target: https://github.com/tqdm/tqdm/pulls
+.. |GitHub-Contributions| image:: https://img.shields.io/github/contributors/tqdm/tqdm.svg?logo=github&logoColor=white
+ :target: https://github.com/tqdm/tqdm/graphs/contributors
+.. |GitHub-Updated| image:: https://img.shields.io/github/last-commit/tqdm/tqdm/master.svg?logo=github&logoColor=white&label=pushed
+ :target: https://github.com/tqdm/tqdm/pulse
+.. |Gift-Casper| image:: https://img.shields.io/badge/dynamic/json.svg?color=ff69b4&label=gifts%20received&prefix=%C2%A3&query=%24..sum&url=https%3A%2F%2Fcaspersci.uk.to%2Fgifts.json
+ :target: https://cdcl.ml/sponsor
+.. |Versions| image:: https://img.shields.io/pypi/v/tqdm.svg
+ :target: https://tqdm.github.io/releases
+.. |PyPI-Downloads| image:: https://img.shields.io/pypi/dm/tqdm.svg?label=pypi%20downloads&logo=PyPI&logoColor=white
+ :target: https://pepy.tech/project/tqdm
+.. |Py-Versions| image:: https://img.shields.io/pypi/pyversions/tqdm.svg?logo=python&logoColor=white
+ :target: https://pypi.org/project/tqdm
+.. |Conda-Forge-Status| image:: https://img.shields.io/conda/v/conda-forge/tqdm.svg?label=conda-forge&logo=conda-forge
+ :target: https://anaconda.org/conda-forge/tqdm
+.. |Snapcraft| image:: https://img.shields.io/badge/snap-install-82BEA0.svg?logo=snapcraft
+ :target: https://snapcraft.io/tqdm
+.. |Docker| image:: https://img.shields.io/badge/docker-pull-blue.svg?logo=docker&logoColor=white
+ :target: https://hub.docker.com/r/tqdm/tqdm
+.. |Libraries-Rank| image:: https://img.shields.io/librariesio/sourcerank/pypi/tqdm.svg?logo=koding&logoColor=white
+ :target: https://libraries.io/pypi/tqdm
+.. |Libraries-Dependents| image:: https://img.shields.io/librariesio/dependent-repos/pypi/tqdm.svg?logo=koding&logoColor=white
+ :target: https://github.com/tqdm/tqdm/network/dependents
+.. |OpenHub-Status| image:: https://www.openhub.net/p/tqdm/widgets/project_thin_badge?format=gif
+ :target: https://www.openhub.net/p/tqdm?ref=Thin+badge
+.. |awesome-python| image:: https://awesome.re/mentioned-badge.svg
+ :target: https://github.com/vinta/awesome-python
+.. |LICENCE| image:: https://img.shields.io/pypi/l/tqdm.svg
+ :target: https://raw.githubusercontent.com/tqdm/tqdm/master/LICENCE
+.. |DOI| image:: https://img.shields.io/badge/DOI-10.5281/zenodo.595120-blue.svg
+ :target: https://doi.org/10.5281/zenodo.595120
+.. |binder-demo| image:: https://mybinder.org/badge_logo.svg
+ :target: https://mybinder.org/v2/gh/tqdm/tqdm/master?filepath=DEMO.ipynb
+.. |Screenshot-Jupyter1| image:: https://img.tqdm.ml/jupyter-1.gif
+.. |Screenshot-Jupyter2| image:: https://img.tqdm.ml/jupyter-2.gif
+.. |Screenshot-Jupyter3| image:: https://img.tqdm.ml/jupyter-3.gif
+.. |README-Hits| image:: https://caspersci.uk.to/cgi-bin/hits.cgi?q=tqdm&style=social&r=https://github.com/tqdm/tqdm&l=https://img.tqdm.ml/favicon.png&f=https://img.tqdm.ml/logo.gif
+ :target: https://caspersci.uk.to/cgi-bin/hits.cgi?q=tqdm&a=plot&r=https://github.com/tqdm/tqdm&l=https://img.tqdm.ml/favicon.png&f=https://img.tqdm.ml/logo.gif&style=social
+
+
diff --git a/third_party/python/tqdm/tqdm-4.62.3.dist-info/RECORD b/third_party/python/tqdm/tqdm-4.62.3.dist-info/RECORD
new file mode 100644
index 0000000000..8b98eca2b6
--- /dev/null
+++ b/third_party/python/tqdm/tqdm-4.62.3.dist-info/RECORD
@@ -0,0 +1,39 @@
+tqdm/__init__.py,sha256=LiezHIqATK3FOij_365eMcu11UPmijmDFKogl72fHp4,1639
+tqdm/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
+tqdm/_dist_ver.py,sha256=mXM_6fFcFakqg8WfBGHFnOAJldFvVy1ECtxe-NkcRxA,23
+tqdm/_main.py,sha256=9ySvgmi_2Sw4CAo5UDW0Q2dxfTryboEWGHohfCJz0sA,283
+tqdm/_monitor.py,sha256=Uku-DPWgzJ7dO5CK08xKJK-E_F6qQ-JB3ksuXczSYR0,3699
+tqdm/_tqdm.py,sha256=LfLCuJ6bpsVo9xilmtBXyEm1vGnUCFrliW85j3J-nD4,283
+tqdm/_tqdm_gui.py,sha256=03Hc8KayxJveieI5-0-2NGiDpLvw9jZekofJUV7CCwk,287
+tqdm/_tqdm_notebook.py,sha256=BuHiLuxu6uEfZFaPJW3RPpPaxaVctEQA3kdSJSDL1hw,307
+tqdm/_tqdm_pandas.py,sha256=c9jptUgigN6axRDhRd4Rif98Tmxeopc1nFNFhIpbFUE,888
+tqdm/_utils.py,sha256=YIwj0ZJQonXgYa2HaA3U_paP4xOXJqj0ZWMPeZSf6Pw,596
+tqdm/asyncio.py,sha256=7CWT2150uMvyXSMDkl9PvG9G_HrfOVY32rWbeP2bw1Y,2789
+tqdm/auto.py,sha256=P__dIfklVGqcRdzV4q68SOBVhLHe9QWnrCk3IJIA-fM,1106
+tqdm/autonotebook.py,sha256=5LdOJz8_HnA55hJRUdq_69Zv1qjKI4AlJEC7RiQmzoQ,857
+tqdm/cli.py,sha256=x_c8nmc4Huc-lKEsAXj78ZiyqSJ9hJ71j7vltY67icw,10509
+tqdm/completion.sh,sha256=j79KbSmpIj_E11jfTfBXrGnUTzKXVpQ1vGVQvsyDRl4,946
+tqdm/dask.py,sha256=BqPQ2O_Bd59hnXlC7B5rS7y9C2wI4cPkIHDdeCWGtzc,1377
+tqdm/gui.py,sha256=kQP-ezwAUSvJ44f50Up2fEG4Hq-p4snrEyKwSNwcgkI,5943
+tqdm/keras.py,sha256=auQQJvAZMHgr0Y3kY6pKQVD-6EAJMPg91ZOJ2WSTN-A,4409
+tqdm/notebook.py,sha256=Y6d5z8p2T3hV3w_O-iWpbNdRPik1jYPI2KD_HY0V8Es,11231
+tqdm/rich.py,sha256=Hs8iu1pXZHUGj2DJVMiEUO897zmiodf3KwZQlO0Z_G4,4964
+tqdm/std.py,sha256=yvqDOoKVOkX47d8Wpk26Xv502ytw2EtNC_xCmWNA1ZM,57760
+tqdm/tk.py,sha256=a3lbj1GsP7jyDpQQgm5ohsFm9Y9-adeklYIhPH69P88,6948
+tqdm/tqdm.1,sha256=1YMLZFiY0wGAUYgjmrfr9vQTlyMql6LT31oUWvOyQdU,7997
+tqdm/utils.py,sha256=KvE0DM28X__NHYKgGl5jUrk6CM5BV60G4Nf55ITPeJI,9803
+tqdm/version.py,sha256=-1yWjfu3P0eghVsysHH07fbzdiADNRdzRtYPqOaqR2A,333
+tqdm/contrib/__init__.py,sha256=gpiBeuWB1OaaoGFwiS-G_Nodv8fLPZ_xVxbENL0EYL4,2604
+tqdm/contrib/bells.py,sha256=_CURLQOkZHjn429e6HGB5U3ESTPBjxr15flG1346eF8,735
+tqdm/contrib/concurrent.py,sha256=YmHJG_jUYUsg2NR1eAhsrl6X-_BfzlANtW32IhNmRTA,4644
+tqdm/contrib/discord.py,sha256=H5Wq6xbvH0H8c_53jpSWZtyElK_RprVSPqkXZjDRVW0,3989
+tqdm/contrib/itertools.py,sha256=BLsGWBjSjI5grz3UBBf-qcmlmJqN29AGMNNH-Bjk8HA,798
+tqdm/contrib/logging.py,sha256=F4pEE2mRecNKoZNm7jIWr2nMeelvogvZ8aopo_irK44,3844
+tqdm/contrib/telegram.py,sha256=5S6IIZMjDg7rcdxJaGGcvTRC37DnHf0r36ahje_JyyQ,5228
+tqdm/contrib/utils_worker.py,sha256=3Mj9TvDa3qRGoZvrmU5cQTnmQLPd8oP7AURuJjVVFXo,1247
+tqdm-4.62.3.dist-info/LICENCE,sha256=oPwXhajyogCjEk1wPUlVBgG3dBzP_IYXE8LdqgelN90,2006
+tqdm-4.62.3.dist-info/METADATA,sha256=j5GU21D1jHKgPWY0OOH9Fmcvx0ADzIJ_c_MXzn5hGnE,56972
+tqdm-4.62.3.dist-info/WHEEL,sha256=WzZ8cwjh8l0jtULNjYq1Hpr-WCqCRgPr--TX4P5I1Wo,110
+tqdm-4.62.3.dist-info/entry_points.txt,sha256=wDAae6wt2WNgXb_Zk5TNu9YmqoafUG2pV7K1CXf3k_U,40
+tqdm-4.62.3.dist-info/top_level.txt,sha256=NLiUJNfmc9At15s7JURiwvqMEjUi9G5PMGRrmMYzNSM,5
+tqdm-4.62.3.dist-info/RECORD,,
diff --git a/third_party/python/tqdm/tqdm-4.62.3.dist-info/WHEEL b/third_party/python/tqdm/tqdm-4.62.3.dist-info/WHEEL
new file mode 100644
index 0000000000..b733a60d37
--- /dev/null
+++ b/third_party/python/tqdm/tqdm-4.62.3.dist-info/WHEEL
@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.37.0)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+
diff --git a/third_party/python/tqdm/tqdm-4.62.3.dist-info/entry_points.txt b/third_party/python/tqdm/tqdm-4.62.3.dist-info/entry_points.txt
new file mode 100644
index 0000000000..9b3087d455
--- /dev/null
+++ b/third_party/python/tqdm/tqdm-4.62.3.dist-info/entry_points.txt
@@ -0,0 +1,3 @@
+[console_scripts]
+tqdm = tqdm.cli:main
+
diff --git a/third_party/python/tqdm/tqdm-4.62.3.dist-info/top_level.txt b/third_party/python/tqdm/tqdm-4.62.3.dist-info/top_level.txt
new file mode 100644
index 0000000000..78620c472c
--- /dev/null
+++ b/third_party/python/tqdm/tqdm-4.62.3.dist-info/top_level.txt
@@ -0,0 +1 @@
+tqdm
diff --git a/third_party/python/tqdm/tqdm/__init__.py b/third_party/python/tqdm/tqdm/__init__.py
new file mode 100644
index 0000000000..a021d16e9a
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/__init__.py
@@ -0,0 +1,41 @@
+from ._monitor import TMonitor, TqdmSynchronisationWarning
+from ._tqdm_pandas import tqdm_pandas
+from .cli import main # TODO: remove in v5.0.0
+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',
+ 'TqdmTypeError', 'TqdmKeyError',
+ 'TqdmWarning', 'TqdmDeprecationWarning',
+ 'TqdmExperimentalWarning',
+ 'TqdmMonitorWarning', 'TqdmSynchronisationWarning',
+ '__version__']
+
+
+def tqdm_notebook(*args, **kwargs): # pragma: no cover
+ """See tqdm.notebook.tqdm for full documentation"""
+ 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)
+ return _tqdm_notebook(*args, **kwargs)
+
+
+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 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/third_party/python/tqdm/tqdm/__main__.py b/third_party/python/tqdm/tqdm/__main__.py
new file mode 100644
index 0000000000..4e28416e10
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/__main__.py
@@ -0,0 +1,3 @@
+from .cli import main
+
+main()
diff --git a/third_party/python/tqdm/tqdm/_dist_ver.py b/third_party/python/tqdm/tqdm/_dist_ver.py
new file mode 100644
index 0000000000..0e32760553
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/_dist_ver.py
@@ -0,0 +1 @@
+__version__ = '4.62.3'
diff --git a/third_party/python/tqdm/tqdm/_main.py b/third_party/python/tqdm/tqdm/_main.py
new file mode 100644
index 0000000000..04fdeeff17
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/_main.py
@@ -0,0 +1,9 @@
+from warnings import warn
+
+from .cli import * # NOQA
+from .cli import __all__ # NOQA
+from .std import TqdmDeprecationWarning
+
+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/third_party/python/tqdm/tqdm/_monitor.py b/third_party/python/tqdm/tqdm/_monitor.py
new file mode 100644
index 0000000000..f71aa56817
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/_monitor.py
@@ -0,0 +1,95 @@
+import atexit
+from threading import Event, Thread, current_thread
+from time import time
+from warnings import warn
+
+__all__ = ["TMonitor", "TqdmSynchronisationWarning"]
+
+
+class TqdmSynchronisationWarning(RuntimeWarning):
+ """tqdm multi-thread/-process errors which may cause incorrect nesting
+ but otherwise no adverse effects"""
+ pass
+
+
+class TMonitor(Thread):
+ """
+ Monitoring thread for tqdm bars.
+ Monitors if tqdm bars are taking too much time to display
+ and readjusts miniters automatically if necessary.
+
+ Parameters
+ ----------
+ tqdm_cls : class
+ tqdm class to use (can be core tqdm or a submodule).
+ sleep_interval : float
+ Time to sleep between monitoring checks.
+ """
+ _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.woken = 0 # last time woken up, to sync with monitor
+ self.tqdm_cls = tqdm_cls
+ self.sleep_interval = sleep_interval
+ self._time = self._test.get("time", time)
+ self.was_killed = self._test.get("Event", Event)()
+ atexit.register(self.exit)
+ self.start()
+
+ def exit(self):
+ self.was_killed.set()
+ if self is not current_thread():
+ self.join()
+ return self.report()
+
+ def get_instances(self):
+ # returns a copy of started `tqdm_cls` instances
+ return [i for i in self.tqdm_cls._instances.copy()
+ # Avoid race by checking that the instance started
+ if hasattr(i, 'start_t')]
+
+ def run(self):
+ cur_t = self._time()
+ while True:
+ # After processing and before sleeping, notify that we woke
+ # Need to be done just before sleeping
+ self.woken = cur_t
+ # Sleep some time...
+ self.was_killed.wait(self.sleep_interval)
+ # Quit if killed
+ if self.was_killed.is_set():
+ return
+ # Then monitor!
+ # Acquire lock (to access _instances)
+ with self.tqdm_cls.get_lock():
+ cur_t = self._time()
+ # Check tqdm instances are waiting too long to print
+ instances = self.get_instances()
+ for instance in instances:
+ # Check event in loop to reduce blocking time on exit
+ if self.was_killed.is_set():
+ 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
+ ):
+ # 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/third_party/python/tqdm/tqdm/_tqdm.py b/third_party/python/tqdm/tqdm/_tqdm.py
new file mode 100644
index 0000000000..7fc4962774
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/_tqdm.py
@@ -0,0 +1,9 @@
+from warnings import warn
+
+from .std import * # NOQA
+from .std import __all__ # NOQA
+from .std import TqdmDeprecationWarning
+
+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/third_party/python/tqdm/tqdm/_tqdm_gui.py b/third_party/python/tqdm/tqdm/_tqdm_gui.py
new file mode 100644
index 0000000000..f32aa894f5
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/_tqdm_gui.py
@@ -0,0 +1,9 @@
+from warnings import warn
+
+from .gui import * # NOQA
+from .gui import __all__ # NOQA
+from .std import TqdmDeprecationWarning
+
+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/third_party/python/tqdm/tqdm/_tqdm_notebook.py b/third_party/python/tqdm/tqdm/_tqdm_notebook.py
new file mode 100644
index 0000000000..f225fbf5b5
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/_tqdm_notebook.py
@@ -0,0 +1,9 @@
+from warnings import warn
+
+from .notebook import * # NOQA
+from .notebook import __all__ # NOQA
+from .std import TqdmDeprecationWarning
+
+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/third_party/python/tqdm/tqdm/_tqdm_pandas.py b/third_party/python/tqdm/tqdm/_tqdm_pandas.py
new file mode 100644
index 0000000000..c4fe6efdc6
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/_tqdm_pandas.py
@@ -0,0 +1,24 @@
+import sys
+
+__author__ = "github.com/casperdcl"
+__all__ = ['tqdm_pandas']
+
+
+def tqdm_pandas(tclass, **tqdm_kwargs):
+ """
+ Registers the given `tqdm` instance with
+ `pandas.core.groupby.DataFrameGroupBy.progress_apply`.
+ """
+ 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(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))
+ type(tclass).pandas(deprecated_t=tclass)
diff --git a/third_party/python/tqdm/tqdm/_utils.py b/third_party/python/tqdm/tqdm/_utils.py
new file mode 100644
index 0000000000..2cf10909f5
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/_utils.py
@@ -0,0 +1,12 @@
+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/third_party/python/tqdm/tqdm/asyncio.py b/third_party/python/tqdm/tqdm/asyncio.py
new file mode 100644
index 0000000000..97c5f88fc2
--- /dev/null
+++ b/third_party/python/tqdm/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/third_party/python/tqdm/tqdm/auto.py b/third_party/python/tqdm/tqdm/auto.py
new file mode 100644
index 0000000000..cffca206ff
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/auto.py
@@ -0,0 +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 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/third_party/python/tqdm/tqdm/autonotebook.py b/third_party/python/tqdm/tqdm/autonotebook.py
new file mode 100644
index 0000000000..b032061bfb
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/autonotebook.py
@@ -0,0 +1,28 @@
+"""
+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:
+ 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 Exception:
+ from .std import tqdm, trange
+else: # pragma: no cover
+ from warnings import warn
+
+ from .notebook import tqdm, trange
+ from .std import TqdmExperimentalWarning
+ warn("Using `tqdm.autonotebook.tqdm` in notebook mode."
+ " Use `tqdm.tqdm` instead to force console mode"
+ " (e.g. in jupyter console)", TqdmExperimentalWarning, stacklevel=2)
+__all__ = ["tqdm", "trange"]
diff --git a/third_party/python/tqdm/tqdm/cli.py b/third_party/python/tqdm/tqdm/cli.py
new file mode 100644
index 0000000000..b5a16142b9
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/cli.py
@@ -0,0 +1,308 @@
+"""
+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.debug((val, typ))
+ if " or " in typ:
+ for t in typ.split(" or "):
+ try:
+ return cast(val, t)
+ except TqdmTypeError:
+ pass
+ raise TqdmTypeError(val + ' : ' + typ)
+
+ # sys.stderr.write('\ndebug | `val:type`: `' + val + ':' + typ + '`.\n')
+ if typ == 'bool':
+ if (val == 'True') or (val == ''):
+ return True
+ elif val == 'False':
+ return False
+ else:
+ raise TqdmTypeError(val + ' : ' + typ)
+ try:
+ return eval(typ + '("' + val + '")')
+ except Exception:
+ if typ == 'chr':
+ return chr(ord(eval('"' + val + '"'))).encode()
+ else:
+ raise TqdmTypeError(val + ' : ' + typ)
+
+
+def posix_pipe(fin, fout, delim=b'\\n', buf_size=256,
+ callback=lambda float: None, callback_len=True):
+ """
+ Params
+ ------
+ 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
+
+ if not delim:
+ while True:
+ tmp = fin.read(buf_size)
+
+ # flush at EOF
+ if not tmp:
+ getattr(fout, 'flush', lambda: None)()
+ return
+
+ fp_write(tmp)
+ callback(len(tmp))
+ # return
+
+ buf = b''
+ # n = 0
+ while True:
+ tmp = fin.read(buf_size)
+
+ # flush at EOF
+ if not tmp:
+ if buf:
+ fp_write(buf)
+ 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:
+ try:
+ i = tmp.index(delim)
+ except ValueError:
+ buf += tmp
+ break
+ else:
+ fp_write(buf + tmp[:i + len(delim)])
+ # n += 1
+ callback(1 if callback_len else (buf + tmp[:i]))
+ buf = b''
+ tmp = tmp[i + len(delim):]
+
+
+# ((opt, type), ... )
+RE_OPTS = re.compile(r'\n {8}(\S+)\s{2,}:\s*([^,]+)')
+# better split method assuming no positional args
+RE_SHLEX = re.compile(r'\s*(?<!\S)--?([^\s=]+)(\s+|=|$)')
+
+# TODO: add custom support for some of the following?
+UNSUPPORTED_OPTS = ('iterable', 'gui', 'out', 'file')
+
+# The 8 leading spaces are required for consistency
+CLI_EXTRA_DOC = r"""
+ Extra CLI Options
+ -----------------
+ name : type, optional
+ TODO: find out why this is needed.
+ delim : chr, optional
+ Delimiting character [default: '\n']. Use '\0' for null.
+ N.B.: on Windows systems, Python converts '\n' to '\r\n'.
+ buf_size : int, optional
+ String buffer size in bytes [default: 256]
+ used when `delim` is specified.
+ 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
+ Directory in which to place tqdm completion.
+ log : str, optional
+ CRITICAL|FATAL|ERROR|WARN(ING)|[default: 'INFO']|DEBUG|NOTSET.
+"""
+
+
+def main(fp=sys.stderr, argv=None):
+ """
+ Parameters (internal use only)
+ ---------
+ fp : file-like object for tqdm
+ argv : list (default: sys.argv[1:])
+ """
+ if argv is None:
+ argv = sys.argv[1:]
+ try:
+ log_idx = argv.index('--log')
+ except ValueError:
+ for i in argv:
+ if i.startswith('--log='):
+ logLevel = i[len('--log='):]
+ break
+ else:
+ logLevel = 'INFO'
+ else:
+ # 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
+
+ opt_types = dict(RE_OPTS.findall(d))
+ # opt_types['delim'] = 'chr'
+
+ for o in UNSUPPORTED_OPTS:
+ opt_types.pop(o)
+
+ log.debug(sorted(opt_types.items()))
+
+ # 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} : {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.
+""" + d.strip('\n') + '\n'
+
+ # opts = docopt(d, version=__version__)
+ if any(v in argv for v in ('-v', '--version')):
+ sys.stdout.write(__version__ + '\n')
+ sys.exit(0)
+ elif any(v in argv for v in ('-h', '--help')):
+ sys.stdout.write(d + '\n')
+ sys.exit(0)
+
+ argv = RE_SHLEX.split(' '.join(["tqdm"] + argv))
+ opts = dict(zip(argv[1::3], argv[3::3]))
+
+ log.debug(opts)
+ opts.pop('log', True)
+
+ 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))
+
+ 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', 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)
+ if manpath or comppath:
+ from os import path
+ from shutil import copyfile
+
+ from pkg_resources import Requirement, resource_filename
+
+ def cp(src, dst):
+ """copies from src path to dst"""
+ copyfile(src, dst)
+ log.info("written:" + dst)
+ if manpath is not None:
+ 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'),
+ 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)
+ tqdm_args.setdefault('unit_divisor', 1024)
+ log.debug(tqdm_args)
+ with tqdm(**tqdm_args) as t:
+ posix_pipe(stdin, stdout, '', buf_size, t.update)
+ elif delim == b'\\n':
+ log.debug(tqdm_args)
+ 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:
+ 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/third_party/python/tqdm/tqdm/completion.sh b/third_party/python/tqdm/tqdm/completion.sh
new file mode 100755
index 0000000000..9f61c7f14b
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/completion.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+_tqdm(){
+ local cur prv
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prv="${COMP_WORDS[COMP_CWORD - 1]}"
+
+ case ${prv} in
+ --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 --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
+}
+complete -F _tqdm tqdm
diff --git a/third_party/python/tqdm/tqdm/contrib/__init__.py b/third_party/python/tqdm/tqdm/contrib/__init__.py
new file mode 100644
index 0000000000..0b52177073
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/contrib/__init__.py
@@ -0,0 +1,98 @@
+"""
+Thin wrappers around common functions.
+
+Subpackages contain potentially unstable extensions.
+"""
+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):
+ 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 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`.
+
+ Parameters
+ ----------
+ tqdm_class : [default: tqdm.auto.tqdm].
+ """
+ try:
+ import numpy as np
+ except ImportError:
+ 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, total=total, **tqdm_kwargs), start)
+
+
+@builtin_iterable
+def tzip(iter1, *iter2plus, **tqdm_kwargs):
+ """
+ Equivalent of builtin `zip`.
+
+ Parameters
+ ----------
+ tqdm_class : [default: tqdm.auto.tqdm].
+ """
+ kwargs = tqdm_kwargs.copy()
+ tqdm_class = kwargs.pop("tqdm_class", tqdm_auto)
+ for i in zip(tqdm_class(iter1, **kwargs), *iter2plus):
+ yield i
+
+
+@builtin_iterable
+def tmap(function, *sequences, **tqdm_kwargs):
+ """
+ Equivalent of builtin `map`.
+
+ Parameters
+ ----------
+ tqdm_class : [default: tqdm.auto.tqdm].
+ """
+ for i in tzip(*sequences, **tqdm_kwargs):
+ yield function(*i)
diff --git a/third_party/python/tqdm/tqdm/contrib/bells.py b/third_party/python/tqdm/tqdm/contrib/bells.py
new file mode 100644
index 0000000000..be22768842
--- /dev/null
+++ b/third_party/python/tqdm/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/third_party/python/tqdm/tqdm/contrib/concurrent.py b/third_party/python/tqdm/tqdm/contrib/concurrent.py
new file mode 100644
index 0000000000..ccb5e12529
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/contrib/concurrent.py
@@ -0,0 +1,130 @@
+"""
+Thin wrappers around `concurrent.futures`.
+"""
+from __future__ import absolute_import
+
+from contextlib import contextmanager
+
+from ..auto import tqdm as tqdm_auto
+from ..std import TqdmWarning
+
+try:
+ from operator import length_hint
+except ImportError:
+ def length_hint(it, default=0):
+ """Returns `len(it)`, falling back to `default`"""
+ try:
+ return len(it)
+ except TypeError:
+ return default
+try:
+ from os import cpu_count
+except ImportError:
+ try:
+ from multiprocessing import cpu_count
+ 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`.
+
+ Parameters
+ ----------
+ tqdm_class : [default: tqdm.auto.tqdm].
+ max_workers : [default: min(32, cpu_count() + 4)].
+ chunksize : [default: 1].
+ lock_name : [default: "":str].
+ """
+ kwargs = tqdm_kwargs.copy()
+ if "total" not in kwargs:
+ 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)
+ 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):
+ """
+ Equivalent of `list(map(fn, *iterables))`
+ driven by `concurrent.futures.ThreadPoolExecutor`.
+
+ Parameters
+ ----------
+ tqdm_class : optional
+ `tqdm` class to use for bars [default: tqdm.auto.tqdm].
+ max_workers : int, optional
+ Maximum number of workers to spawn; passed to
+ `concurrent.futures.ThreadPoolExecutor.__init__`.
+ [default: max(32, cpu_count() + 4)].
+ """
+ from concurrent.futures import ThreadPoolExecutor
+ return _executor_map(ThreadPoolExecutor, fn, *iterables, **tqdm_kwargs)
+
+
+def process_map(fn, *iterables, **tqdm_kwargs):
+ """
+ Equivalent of `list(map(fn, *iterables))`
+ driven by `concurrent.futures.ProcessPoolExecutor`.
+
+ Parameters
+ ----------
+ tqdm_class : optional
+ `tqdm` class to use for bars [default: tqdm.auto.tqdm].
+ 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
+ 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:
+ # default `chunksize=1` has poor performance for large iterables
+ # (most time spent dispatching items to workers).
+ longest_iterable_len = max(map(length_hint, iterables))
+ if longest_iterable_len > 1000:
+ from warnings import warn
+ warn("Iterable length %d > 1000 but `chunksize` is not set."
+ " 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/third_party/python/tqdm/tqdm/contrib/discord.py b/third_party/python/tqdm/tqdm/contrib/discord.py
new file mode 100644
index 0000000000..713a2f8220
--- /dev/null
+++ b/third_party/python/tqdm/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/third_party/python/tqdm/tqdm/contrib/itertools.py b/third_party/python/tqdm/tqdm/contrib/itertools.py
new file mode 100644
index 0000000000..9cce75e8f8
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/contrib/itertools.py
@@ -0,0 +1,36 @@
+"""
+Thin wrappers around `itertools`.
+"""
+from __future__ import absolute_import
+
+import itertools
+
+from ..auto import tqdm as tqdm_auto
+
+__author__ = {"github.com/": ["casperdcl"]}
+__all__ = ['product']
+
+
+def product(*iterables, **tqdm_kwargs):
+ """
+ Equivalent of `itertools.product`.
+
+ Parameters
+ ----------
+ tqdm_class : [default: tqdm.auto.tqdm].
+ """
+ kwargs = tqdm_kwargs.copy()
+ tqdm_class = kwargs.pop("tqdm_class", tqdm_auto)
+ try:
+ lens = list(map(len, iterables))
+ except TypeError:
+ total = None
+ else:
+ total = 1
+ for i in lens:
+ total *= i
+ kwargs.setdefault("total", total)
+ with tqdm_class(**kwargs) as t:
+ for i in itertools.product(*iterables):
+ yield i
+ t.update()
diff --git a/third_party/python/tqdm/tqdm/contrib/logging.py b/third_party/python/tqdm/tqdm/contrib/logging.py
new file mode 100644
index 0000000000..cd9925ec13
--- /dev/null
+++ b/third_party/python/tqdm/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/third_party/python/tqdm/tqdm/contrib/telegram.py b/third_party/python/tqdm/tqdm/contrib/telegram.py
new file mode 100644
index 0000000000..99cbe8c888
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/contrib/telegram.py
@@ -0,0 +1,159 @@
+"""
+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 os import getenv
+from warnings import warn
+
+from requests import Session
+
+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(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()
+ self.text = self.__class__.__name__
+ self.message_id
+
+ @property
+ def message_id(self):
+ if hasattr(self, '_message_id'):
+ return self._message_id
+ try:
+ res = self.session.post(
+ self.API + '%s/sendMessage' % self.token,
+ data={'text': '`' + self.text + '`', 'chat_id': self.chat_id,
+ 'parse_mode': 'MarkdownV2'}).json()
+ except Exception as e:
+ tqdm_auto.write(str(e))
+ else:
+ 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:
+ 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:
+ 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:
+ return future
+
+ def delete(self):
+ """Deletes internal `message_id`."""
+ try:
+ 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__`).
+
+ - 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='{token}', chat_id='{chat_id}'):
+ ... ...
+ """
+ def __init__(self, *args, **kwargs):
+ """
+ Parameters
+ ----------
+ 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.
+ """
+ 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 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.tgio.write(self.format_meter(**fmt))
+
+ 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):
+ """
+ A shortcut for `tqdm.contrib.telegram.tqdm(xrange(*args), **kwargs)`.
+ On Python3+, `range` is used instead of `xrange`.
+ """
+ return tqdm_telegram(_range(*args), **kwargs)
+
+
+# Aliases
+tqdm = tqdm_telegram
+trange = ttgrange
diff --git a/third_party/python/tqdm/tqdm/contrib/utils_worker.py b/third_party/python/tqdm/tqdm/contrib/utils_worker.py
new file mode 100644
index 0000000000..17adda6678
--- /dev/null
+++ b/third_party/python/tqdm/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/third_party/python/tqdm/tqdm/dask.py b/third_party/python/tqdm/tqdm/dask.py
new file mode 100644
index 0000000000..6fc7504c79
--- /dev/null
+++ b/third_party/python/tqdm/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/third_party/python/tqdm/tqdm/gui.py b/third_party/python/tqdm/tqdm/gui.py
new file mode 100644
index 0000000000..4612701d2a
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/gui.py
@@ -0,0 +1,191 @@
+"""
+Matplotlib GUI progressbar decorator for iterators.
+
+Usage:
+>>> 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 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 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
+ kwargs = kwargs.copy()
+ kwargs['gui'] = True
+ colour = kwargs.pop('colour', 'g')
+ super(tqdm_gui, self).__init__(*args, **kwargs)
+
+ if self.disable:
+ return
+
+ warn("GUI is experimental/alpha", TqdmExperimentalWarning, stacklevel=2)
+ self.mpl = mpl
+ self.plt = plt
+
+ # Remember if external environment uses toolbars
+ self.toolbar = self.mpl.rcParams['toolbar']
+ self.mpl.rcParams['toolbar'] = 'None'
+
+ self.mininterval = max(self.mininterval, 0.5)
+ self.fig, ax = plt.subplots(figsize=(9, 2.2))
+ # self.fig.subplots_adjust(bottom=0.2)
+ total = self.__len__() # avoids TypeError on None #971
+ if total is not None:
+ self.xdata = []
+ self.ydata = []
+ self.zdata = []
+ else:
+ self.xdata = deque([])
+ self.ydata = deque([])
+ self.zdata = deque([])
+ self.line1, = ax.plot(self.xdata, self.ydata, color='b')
+ self.line2, = ax.plot(self.xdata, self.zdata, color='k')
+ 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"),
+ loc='center right')
+ # progressbar
+ 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.grid()
+ # ax.set_xlabel('seconds')
+ 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))
+ ax.yaxis.get_offset_text().set_x(-0.15)
+
+ # Remember if external environment is interactive
+ self.wasion = plt.isinteractive()
+ plt.ion()
+ self.ax = ax
+
+ def close(self):
+ if self.disable:
+ return
+
+ self.disable = True
+
+ with self.get_lock():
+ self._instances.remove(self)
+
+ # Restore toolbars
+ self.mpl.rcParams['toolbar'] = self.toolbar
+ # Return to non-interactive mode
+ if not self.wasion:
+ self.plt.ioff()
+ if self.leave:
+ self.display()
+ else:
+ self.plt.close(self.fig)
+
+ def clear(self, *_, **__):
+ pass
+
+ def display(self, *_, **__):
+ n = self.n
+ cur_t = self._time()
+ elapsed = cur_t - self.start_t
+ delta_it = n - self.last_print_n
+ delta_t = cur_t - self.last_print_t
+
+ # Inline due to multiple calls
+ total = self.total
+ xdata = self.xdata
+ ydata = self.ydata
+ zdata = self.zdata
+ ax = self.ax
+ line1 = self.line1
+ line2 = self.line2
+ # instantaneous rate
+ y = delta_it / delta_t
+ # overall rate
+ z = n / elapsed
+ # update line data
+ xdata.append(n * 100.0 / total if total else cur_t)
+ ydata.append(y)
+ zdata.append(z)
+
+ # Discard old values
+ # xmin, xmax = ax.get_xlim()
+ # if (not total) and elapsed > xmin * 1.1:
+ if (not total) and elapsed > 66:
+ xdata.popleft()
+ ydata.popleft()
+ zdata.popleft()
+
+ ymin, ymax = ax.get_ylim()
+ if y > ymax or z > ymax:
+ ymax = 1.1 * y
+ ax.set_ylim(ymin, ymax)
+ ax.figure.canvas.draw()
+
+ if total:
+ line1.set_data(xdata, ydata)
+ line2.set_data(xdata, zdata)
+ try:
+ poly_lims = self.hspan.get_xy()
+ except AttributeError:
+ 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
+ poly_lims[2] = [n / total, ymax]
+ poly_lims[3] = [poly_lims[2, 0], ymin]
+ if len(poly_lims) > 4:
+ poly_lims[4, 1] = ymin
+ self.hspan.set_xy(poly_lims)
+ else:
+ t_ago = [cur_t - i for i in xdata]
+ line1.set_data(t_ago, ydata)
+ line2.set_data(t_ago, zdata)
+
+ 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)
+
+
+def tgrange(*args, **kwargs):
+ """
+ A shortcut for `tqdm.gui.tqdm(xrange(*args), **kwargs)`.
+ On Python3+, `range` is used instead of `xrange`.
+ """
+ return tqdm_gui(_range(*args), **kwargs)
+
+
+# Aliases
+tqdm = tqdm_gui
+trange = tgrange
diff --git a/third_party/python/tqdm/tqdm/keras.py b/third_party/python/tqdm/tqdm/keras.py
new file mode 100644
index 0000000000..523e62e947
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/keras.py
@@ -0,0 +1,124 @@
+from __future__ import absolute_import, division
+
+from copy import copy
+from functools import partial
+
+from .auto import tqdm as tqdm_auto
+
+try:
+ import keras
+except (ImportError, AttributeError) as e:
+ try:
+ from tensorflow import keras
+ except ImportError:
+ raise e
+__author__ = {"github.com/": ["casperdcl"]}
+__all__ = ['TqdmCallback']
+
+
+class TqdmCallback(keras.callbacks.Callback):
+ """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 = copy(logs)
+ [logs.pop(i, 0) for i in pop]
+ bar.set_postfix(logs, refresh=False)
+ bar.update(n)
+
+ return callback
+
+ def __init__(self, epochs=None, data_size=None, batch_size=None, verbose=1,
+ tqdm_class=tqdm_auto, **tqdm_kwargs):
+ """
+ Parameters
+ ----------
+ epochs : int, optional
+ data_size : int, optional
+ Number of training pairs.
+ batch_size : int, optional
+ Number of training pairs per batch.
+ verbose : int
+ 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 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)
+ if data_size and batch_size:
+ self.batches = batches = (data_size + batch_size - 1) // batch_size
+ else:
+ self.batches = batches = None
+ self.verbose = verbose
+ if verbose == 1:
+ self.batch_bar = tqdm_class(total=batches, unit='batch', leave=False)
+ self.on_batch_end = self.bar2callback(
+ 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 and auto_total != self.epoch_bar.total:
+ self.epoch_bar.reset(total=auto_total)
+
+ 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(
+ 'nb_sample', params('steps', None))) or self.batches
+ if self.verbose == 2:
+ if hasattr(self, 'batch_bar'):
+ self.batch_bar.close()
+ self.batch_bar = self.tqdm_class(
+ 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'],
+ delta=lambda logs: logs.get('size', 1))
+ elif self.verbose == 1:
+ self.batch_bar.unit_scale = 1 / (params('batch_size', 1) or 1)
+ self.batch_bar.reset(total=total)
+ else:
+ raise KeyError('Unknown verbosity')
+
+ def on_train_end(self, *_, **__):
+ if self.verbose:
+ 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
+
+ @staticmethod
+ def _implements_test_batch_hooks():
+ return True
+
+ @staticmethod
+ def _implements_predict_batch_hooks():
+ return True
diff --git a/third_party/python/tqdm/tqdm/notebook.py b/third_party/python/tqdm/tqdm/notebook.py
new file mode 100644
index 0000000000..1f488d25f3
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/notebook.py
@@ -0,0 +1,327 @@
+"""
+IPython/Jupyter Notebook progressbar decorator for iterators.
+Includes a default `range` iterator printing to `stderr`.
+
+Usage:
+>>> 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 absolute_import, division
+
+# import compatibility functions and utilities
+import re
+import sys
+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
+ try: # IPython 4.x
+ import ipywidgets
+ IPY = 4
+ 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.*")
+ try:
+ 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
+ IPY = 3
+ else:
+ from ipywidgets import HTML
+ from ipywidgets import FloatProgress as IProgress
+ from ipywidgets import HBox
+ except ImportError:
+ try: # IPython 2.x
+ 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
+ except ImportError:
+ pass
+
+ # HTML encoding
+ try: # Py3
+ from html import escape
+ 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):
+ """
+ Manage the printing of an IPython/Jupyter Notebook progress bar widget.
+ """
+ # Fallback to text bar if there's no total
+ # DEPRECATED: replaced with an 'info' style bar
+ # if not total:
+ # return super(tqdm_notebook, tqdm_notebook).status_printer(file)
+
+ # fp = file
+
+ # Prepare IPython progress bar
+ if IProgress is None: # #187 #451 #558 #872
+ raise ImportError(
+ "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:
+ 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%"
+ ncols = str(ncols) # ipywidgets only accepts string
+ try:
+ if int(ncols) > 0: # isnumeric and positive
+ ncols += 'px'
+ except ValueError:
+ pass
+ pbar.layout.flex = '2'
+ container.layout.width = ncols
+ container.layout.display = 'inline-flex'
+ container.layout.flex_flow = 'row wrap'
+
+ return container
+
+ def display(self, msg=None, pos=None,
+ # additional signals
+ 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.
+
+ # Clear previous output (really necessary?)
+ # clear_output(wait=1)
+
+ if not msg and not close:
+ 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)
+
+ 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, re.split(r'\|?<bar/>\|?', msg, 1))
+ else:
+ left, right = '', escape(msg)
+
+ # Update description
+ ltext.value = left
+ # never clear the bar (signal: msg='')
+ if 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 pbar.bar_style != 'danger' or bar_style != 'success':
+ pbar.bar_style = bar_style
+
+ # Special signal to close the bar
+ if close and pbar.bar_style != 'danger': # hide only if no error
+ try:
+ self.container.close()
+ 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:
+ kwargs['file'] = sys.stdout # avoid the red block in IPython
+
+ # Initialize parent class + avoid printing by using gui=True
+ kwargs['gui'] = True
+ # 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.disp = lambda *_, **__: None
+ return
+
+ # Get bar width
+ self.ncols = '100%' if self.dynamic_ncols else kwargs.get("ncols", None)
+
+ # 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.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(check_delay=False)
+
+ def __iter__(self):
+ try:
+ 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.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, n=1):
+ try:
+ 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.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):
+ 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.disp(bar_style='danger', check_delay=False)
+ else:
+ if self.leave:
+ self.disp(bar_style='success', check_delay=False)
+ else:
+ self.disp(close=True, check_delay=False)
+
+ def clear(self, *_, **__):
+ pass
+
+ def reset(self, total=None):
+ """
+ Resets to 0 iterations for repeated use.
+
+ Consider combining with `leave=True`.
+
+ Parameters
+ ----------
+ 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.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)
+
+
+def tnrange(*args, **kwargs):
+ """
+ A shortcut for `tqdm.notebook.tqdm(xrange(*args), **kwargs)`.
+ On Python3+, `range` is used instead of `xrange`.
+ """
+ return tqdm_notebook(_range(*args), **kwargs)
+
+
+# Aliases
+tqdm = tqdm_notebook
+trange = tnrange
diff --git a/third_party/python/tqdm/tqdm/rich.py b/third_party/python/tqdm/tqdm/rich.py
new file mode 100644
index 0000000000..cf8e714326
--- /dev/null
+++ b/third_party/python/tqdm/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/third_party/python/tqdm/tqdm/std.py b/third_party/python/tqdm/tqdm/std.py
new file mode 100644
index 0000000000..e81c836808
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/std.py
@@ -0,0 +1,1526 @@
+"""
+Customisable progressbar decorator for iterators.
+Includes a default `range` iterator printing to `stderr`.
+
+Usage:
+>>> from tqdm import trange, tqdm
+>>> for i in trange(10):
+... ...
+"""
+from __future__ import absolute_import, division
+
+import sys
+from collections import OrderedDict, defaultdict
+from contextlib import contextmanager
+from datetime import datetime, timedelta
+from numbers import Number
+from time import time
+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__ = "https://github.com/tqdm/tqdm#contributions"
+__all__ = ['tqdm', 'trange',
+ 'TqdmTypeError', 'TqdmKeyError', 'TqdmWarning',
+ 'TqdmExperimentalWarning', 'TqdmDeprecationWarning',
+ 'TqdmMonitorWarning']
+
+
+class TqdmTypeError(TypeError):
+ pass
+
+
+class TqdmKeyError(KeyError):
+ pass
+
+
+class TqdmWarning(Warning):
+ """base class for all tqdm warnings.
+
+ Used for non-external-code-breaking errors, such as garbled printing.
+ """
+ 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')
+ else:
+ super(TqdmWarning, self).__init__(msg, *a, **k)
+
+
+class TqdmExperimentalWarning(TqdmWarning, FutureWarning):
+ """beta feature, unstable API and behaviour"""
+ pass
+
+
+class TqdmDeprecationWarning(TqdmWarning, DeprecationWarning):
+ # not suppressed if raised
+ pass
+
+
+class TqdmMonitorWarning(TqdmWarning, RuntimeWarning):
+ """tqdm monitor errors which do not affect external functionality"""
+ 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.
+ Works only on platforms supporting `fork` (so Windows is excluded).
+ You must initialise a `tqdm` or `TqdmDefaultWriteLock` instance
+ before forking in order for the write lock to work.
+ 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)
+ 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:
+ lock.acquire(*a, **k)
+
+ def release(self):
+ for lock in self.locks[::-1]: # Release in inverse order of acquisition
+ lock.release()
+
+ def __enter__(self):
+ self.acquire()
+
+ def __exit__(self, *exc):
+ self.release()
+
+ @classmethod
+ def create_mp_lock(cls):
+ if not hasattr(cls, 'mp_lock'):
+ try:
+ from multiprocessing import RLock
+ cls.mp_lock = RLock()
+ except (ImportError, OSError): # pragma: no cover
+ cls.mp_lock = None
+
+ @classmethod
+ def create_th_lock(cls):
+ assert hasattr(cls, 'th_lock')
+ warn("create_th_lock not needed anymore", TqdmDeprecationWarning, stacklevel=2)
+
+
+class Bar(object):
+ """
+ `str.format`-able bar with format specifiers: `[width][type]`
+
+ - `width`
+ + unspecified (default): use `self.default_len`
+ + `int >= 0`: overrides `self.default_len`
+ + `int < 0`: subtract from `self.default_len`
+ - `type`
+ + `a`: ascii (`charset=self.ASCII` override)
+ + `u`: unicode (`charset=self.UTF` override)
+ + `b`: blank (`charset=" "` override)
+ """
+ ASCII = " 123456789#"
+ UTF = u" " + u''.join(map(_unich, range(0x258F, 0x2587, -1)))
+ BLANK = " "
+ COLOUR_RESET = '\x1b[0m'
+ COLOUR_RGB = '\x1b[38;2;%d;%d;%dm'
+ COLOURS = {'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 = {'a': self.ASCII, 'u': self.UTF, 'b': self.BLANK}[_type]
+ except KeyError:
+ charset = self.charset
+ else:
+ format_spec = format_spec[:-1]
+ if format_spec:
+ N_BARS = int(format_spec)
+ if N_BARS < 0:
+ N_BARS += self.default_len
+ else:
+ N_BARS = self.default_len
+ else:
+ charset = self.charset
+ N_BARS = self.default_len
+
+ nsyms = len(charset) - 1
+ 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
+
+
+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
+
+ 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):
+ """
+ Decorate an iterable object, returning an iterator which acts exactly
+ like the original iterable, but prints a dynamically updating
+ progressbar every time a value is requested.
+ """
+
+ monitor_interval = 10 # set to 0 to disable the thread
+ monitor = None
+ _instances = WeakSet()
+
+ @staticmethod
+ def format_sizeof(num, suffix='', divisor=1000):
+ """
+ Formats a number (greater than unity) with SI Order of Magnitude
+ prefixes.
+
+ Parameters
+ ----------
+ num : float
+ Number ( >= 1) to format.
+ suffix : str, optional
+ Post-postfix [default: ''].
+ divisor : float, optional
+ Divisor between prefixes [default: 1000].
+
+ Returns
+ -------
+ out : str
+ Number with Order of Magnitude SI unit postfix.
+ """
+ for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z']:
+ if abs(num) < 999.5:
+ if abs(num) < 99.95:
+ if abs(num) < 9.995:
+ return '{0:1.2f}'.format(num) + unit + suffix
+ return '{0:2.1f}'.format(num) + unit + suffix
+ return '{0:3.0f}'.format(num) + unit + suffix
+ num /= divisor
+ return '{0:3.1f}Y'.format(num) + suffix
+
+ @staticmethod
+ def format_interval(t):
+ """
+ Formats a number of seconds as a clock time, [H:]MM:SS
+
+ Parameters
+ ----------
+ t : int
+ Number of seconds.
+
+ Returns
+ -------
+ out : str
+ [H:]MM:SS
+ """
+ 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)
+
+ @staticmethod
+ def format_num(n):
+ """
+ Intelligent scientific notation (.3g).
+
+ Parameters
+ ----------
+ n : int or float or Numeric
+ A Number.
+
+ Returns
+ -------
+ out : str
+ Formatted number.
+ """
+ f = '{0:.3g}'.format(n).replace('+0', '+').replace('-0', '-')
+ n = str(n)
+ return f if len(f) < len(n) else n
+
+ @staticmethod
+ def status_printer(file):
+ """
+ Manage the printing and in-place updating of a line of characters.
+ Note that if the string is longer than a line, then in-place
+ updating may not work (it will print a new line at each refresh).
+ """
+ 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))
+ fp_flush()
+
+ last_len = [0]
+
+ def print_status(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, initial=0, colour=None, **extra_kwargs):
+ """
+ Return a string-based progress bar given some parameters
+
+ Parameters
+ ----------
+ n : int or float
+ Number of finished iterations.
+ total : int or float
+ The expected total number of iterations. If meaningless (None),
+ only basic progress statistics are displayed (no ETA).
+ elapsed : float
+ Number of seconds passed since start.
+ ncols : int, optional
+ The width of the entire output message. If specified,
+ dynamically resizes `{bar}` to stay within this bound
+ [default: None]. If `0`, will not print any bar (only stats).
+ The fallback is `{bar:10}`.
+ prefix : str, optional
+ Prefix message (included in total width) [default: ''].
+ Use as {desc} in bar_format string.
+ ascii : bool, optional or str, optional
+ If not set, use unicode (smooth blocks) to fill the meter
+ [default: False]. The fallback is to use ASCII characters
+ " 123456789#".
+ unit : str, optional
+ The iteration unit [default: 'it'].
+ unit_scale : bool or int or float, optional
+ If 1 or True, the number of iterations will be printed with an
+ appropriate SI metric prefix (k = 10^3, M = 10^6, etc.)
+ [default: False]. If any other non-zero number, will scale
+ `total` and `n`.
+ rate : float, optional
+ Manual override for iteration rate.
+ If [default: None], uses n/elapsed.
+ bar_format : str, optional
+ Specify a custom bar string formatting. May impact performance.
+ [default: '{l_bar}{bar}{r_bar}'], where
+ l_bar='{desc}: {percentage:3.0f}%|' and
+ r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, '
+ '{rate_fmt}{postfix}]'
+ Possible 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, eta.
+ Note that a trailing ": " is automatically removed after {desc}
+ if the latter is empty.
+ postfix : *, optional
+ Similar to `prefix`, but placed at the end
+ (e.g. for additional stats).
+ Note: postfix is usually a string (not a dict) for this method,
+ and will if possible be set to postfix = ', ' + postfix.
+ 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
+ -------
+ out : Formatted meter and stats, ready to display.
+ """
+
+ # sanity check: total
+ if total and n >= (total + 0.5): # allow float imprecision (#849)
+ total = None
+
+ # apply custom scale if necessary
+ if unit_scale and unit_scale not in (True, 1):
+ if total:
+ total *= unit_scale
+ n *= unit_scale
+ if rate:
+ rate *= unit_scale # by default rate = self.avg_dn / self.avg_dt
+ unit_scale = False
+
+ elapsed_str = tqdm.format_interval(elapsed)
+
+ # 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 - 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
+ 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 '?'
+ else:
+ n_fmt = str(n)
+ total_fmt = str(total) if total is not None else '?'
+
+ try:
+ postfix = ', ' + postfix if postfix else ''
+ except TypeError:
+ pass
+
+ 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:
+ # old prefix setup work around
+ bool_prefix_colon_already = (prefix[-2:] == ": ")
+ l_bar = prefix if bool_prefix_colon_already else prefix + ": "
+ else:
+ l_bar = ''
+
+ r_bar = '| {0}/{1} [{2}<{3}, {4}{5}]'.format(
+ n_fmt, total_fmt, elapsed_str, remaining_str, rate_fmt, postfix)
+
+ # Custom bar formatting
+ # Populate a dict with all available progress indicators
+ format_dict = dict(
+ # slight extension of self.format_dict
+ n=n, n_fmt=n_fmt, total=total, total_fmt=total_fmt,
+ elapsed=elapsed_str, elapsed_s=elapsed,
+ ncols=ncols, desc=prefix or '', unit=unit,
+ rate=inv_rate if inv_rate and inv_rate > 1 else rate,
+ rate_fmt=rate_fmt, rate_noinv=rate,
+ 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, eta=eta_dt,
+ **extra_kwargs)
+
+ # total is known: we can predict some stats
+ if total:
+ # fractional and percentage progress
+ frac = n / total
+ percentage = frac * 100
+
+ l_bar += '{0:3.0f}%|'.format(percentage)
+
+ if ncols == 0:
+ return l_bar[:-1] + r_bar[1:]
+
+ format_dict.update(l_bar=l_bar)
+ if bar_format:
+ format_dict.update(percentage=percentage)
+
+ # auto-remove colon for empty `desc`
+ if not prefix:
+ bar_format = bar_format.replace("{desc}: ", '')
+ else:
+ bar_format = "{l_bar}{bar}{r_bar}"
+
+ full_bar = FormatReplace()
+ try:
+ nobar = bar_format.format(bar=full_bar, **format_dict)
+ except UnicodeEncodeError:
+ bar_format = _unicode(bar_format)
+ nobar = bar_format.format(bar=full_bar, **format_dict)
+ if not full_bar.format_called:
+ # no {bar}, we can just format and return
+ 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,
+ 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)
+ return disp_trim(res, ncols) if ncols else res
+
+ elif bar_format:
+ # user-specified bar_format but no total
+ l_bar += '|'
+ format_dict.update(l_bar=l_bar, percentage=0)
+ full_bar = FormatReplace()
+ 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, 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 '{0}{1}{2} [{3}, {4}{5}]'.format(
+ (prefix + ": ") if prefix else '', n_fmt, unit, elapsed_str, rate_fmt, postfix)
+
+ def __new__(cls, *_, **__):
+ instance = object.__new__(cls)
+ with cls.get_lock(): # also constructs lock if non-existent
+ cls._instances.add(instance)
+ # 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
+ warn("tqdm:disabling monitor support"
+ " (monitor_interval = 0) due to:\n" + str(e),
+ TqdmMonitorWarning, stacklevel=2)
+ cls.monitor_interval = 0
+ return instance
+
+ @classmethod
+ def _get_free_pos(cls, instance=None):
+ """Skips specified instance."""
+ 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
+ def _decr_instances(cls, instance):
+ """
+ Remove from list and reposition another unfixed bar
+ to fill the new gap.
+
+ This means that by default (where all nested bars are unfixed),
+ order is not maintained but screen flicker/blank space is minimised.
+ (tqdm<=4.44.1 moved ALL subsequent unfixed bars up.)
+ """
+ with cls._lock:
+ try:
+ cls._instances.remove(instance)
+ except KeyError:
+ # if not instance.gui: # pragma: no cover
+ # raise
+ pass # py2: maybe magically removed already
+ # else:
+ if not instance.gui:
+ last = (instance.nrows or 20) - 1
+ # find unfixed (`pos >= 0`) overflow (`pos >= nrows - 1`)
+ instances = list(filter(
+ lambda i: hasattr(i, "pos") and last <= i.pos,
+ cls._instances))
+ # set first found to current `pos`
+ if instances:
+ inst = min(instances, key=lambda i: i.pos)
+ inst.clear(nolock=True)
+ inst.pos = abs(instance.pos)
+
+ @classmethod
+ def write(cls, s, file=None, end="\n", nolock=False):
+ """Print a message via tqdm (without overlap with bars)."""
+ fp = file if file is not None else sys.stdout
+ with cls.external_write_mode(file=file, nolock=nolock):
+ # Write the message
+ fp.write(s)
+ fp.write(end)
+
+ @classmethod
+ @contextmanager
+ def external_write_mode(cls, file=None, nolock=False):
+ """
+ Disable tqdm within context and refresh tqdm when exits.
+ Useful when writing to standard output stream
+ """
+ fp = file if file is not None else sys.stdout
+
+ try:
+ if not nolock:
+ cls.get_lock().acquire()
+ # Clear all bars
+ inst_cleared = []
+ for inst in getattr(cls, '_instances', []):
+ # Clear instance if in the target output file
+ # or if write output + tqdm output are both either
+ # sys.stdout or sys.stderr (because both are mixed in terminal)
+ if hasattr(inst, "start_t") and (inst.fp == fp or all(
+ f in (sys.stdout, sys.stderr) for f in (fp, inst.fp))):
+ inst.clear(nolock=True)
+ inst_cleared.append(inst)
+ yield
+ # Force refresh display of bars we cleared
+ for inst in inst_cleared:
+ inst.refresh(nolock=True)
+ finally:
+ if not nolock:
+ cls._lock.release()
+
+ @classmethod
+ def set_lock(cls, lock):
+ """Set the global lock."""
+ cls._lock = lock
+
+ @classmethod
+ def get_lock(cls):
+ """Get the global lock. Construct it if it does not exist."""
+ if not hasattr(cls, '_lock'):
+ cls._lock = TqdmDefaultWriteLock()
+ return cls._lock
+
+ @classmethod
+ def pandas(cls, **tqdm_kwargs):
+ """
+ Registers the current `tqdm` class with
+ pandas.core.
+ ( frame.DataFrame
+ | series.Series
+ | groupby.(generic.)DataFrameGroupBy
+ | groupby.(generic.)SeriesGroupBy
+ ).progress_apply
+
+ A new instance will be create every time `progress_apply` is called,
+ and each instance will automatically `close()` upon completion.
+
+ Parameters
+ ----------
+ tqdm_kwargs : arguments for the tqdm instance
+
+ Examples
+ --------
+ >>> import pandas as pd
+ >>> import numpy as np
+ >>> from tqdm import tqdm
+ >>> from tqdm.gui import tqdm as tqdm_gui
+ >>>
+ >>> df = pd.DataFrame(np.random.randint(0, 100, (100000, 6)))
+ >>> tqdm.pandas(ncols=50) # 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 warnings import catch_warnings, simplefilter
+
+ from pandas.core.frame import DataFrame
+ from pandas.core.series import Series
+ try:
+ 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: # 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 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
+ except ImportError:
+ from pandas.core.groupby import DataFrameGroupBy, SeriesGroupBy
+ try: # pandas>=0.23.0
+ from pandas.core.groupby.groupby import GroupBy
+ except ImportError: # pragma: no cover
+ from pandas.core.groupby import GroupBy
+
+ try: # pandas>=0.23.0
+ from pandas.core.groupby.groupby import PanelGroupBy
+ except ImportError:
+ try:
+ from pandas.core.groupby import PanelGroupBy
+ except ImportError: # pandas>=0.25.0
+ PanelGroupBy = 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):
+ """
+ Parameters
+ ----------
+ df : (DataFrame|Series)[GroupBy]
+ Data (may be grouped).
+ func : function
+ To be applied on the (grouped) data.
+ **kwargs : optional
+ Transmitted to `df.apply()`.
+ """
+
+ # Precompute total iterations
+ 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)):
+ # DataFrame or Panel
+ axis = kwargs.get('axis', 0)
+ if axis == 'index':
+ axis = 0
+ elif axis == 'columns':
+ axis = 1
+ # when axis=0, total is shape[axis1]
+ total = df.size // df.shape[axis]
+
+ # Init bar
+ if deprecated_t[0] is not None:
+ t = deprecated_t[0]
+ deprecated_t[0] = None
+ else:
+ t = cls(total=total, **tqdm_kwargs)
+
+ if len(args) > 0:
+ # *args intentionally not supported (see #244, #299)
+ TqdmDeprecationWarning(
+ "Except func, normal arguments are intentionally" +
+ " not supported by" +
+ " `(DataFrame|Series|GroupBy).progress_apply`." +
+ " 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 = is_builtin_func(func)
+ except TypeError:
+ pass
+
+ # Define bar updating wrapper
+ def wrapper(*args, **kwargs):
+ # update tbar correctly
+ # it seems `pandas apply` calls `func` twice
+ # on the first column/row to decide whether it can
+ # take a fast or slow code path; so stop when t.total==t.n
+ t.update(n=1 if not t.total or t.n < t.total else 0)
+ return func(*args, **kwargs)
+
+ # Apply the provided function (in **kwargs)
+ # on the df using our wrapper (which provides bar updating)
+ try:
+ return getattr(df, df_function)(wrapper, **kwargs)
+ finally:
+ t.close()
+
+ return inner
+
+ # Monkeypatch pandas to provide easy methods
+ # Enable custom tqdm progress in pandas!
+ Series.progress_apply = inner_generator()
+ SeriesGroupBy.progress_apply = inner_generator()
+ Series.progress_map = inner_generator('map')
+ SeriesGroupBy.progress_map = inner_generator('map')
+
+ DataFrame.progress_apply = inner_generator()
+ DataFrameGroupBy.progress_apply = inner_generator()
+ DataFrame.progress_applymap = inner_generator('applymap')
+
+ if Panel is not None:
+ Panel.progress_apply = inner_generator()
+ if PanelGroupBy is not None:
+ PanelGroupBy.progress_apply = inner_generator()
+
+ GroupBy.progress_apply = inner_generator()
+ GroupBy.progress_aggregate = inner_generator('aggregate')
+ GroupBy.progress_transform = inner_generator('transform')
+
+ 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, colour=None, delay=0, gui=False,
+ **kwargs):
+ """
+ Parameters
+ ----------
+ iterable : iterable, optional
+ Iterable to decorate with a progressbar.
+ Leave blank to manually manage the updates.
+ desc : str, optional
+ Prefix for the progressbar.
+ total : int or float, optional
+ The number of expected iterations. If unspecified,
+ len(iterable) is used if possible. If float("inf") or as a last
+ resort, only basic progress statistics are displayed
+ (no ETA, no progressbar).
+ If `gui` is True and this parameter needs subsequent updating,
+ specify an initial arbitrary large positive number,
+ e.g. 9e9.
+ leave : bool, optional
+ If [default: True], keeps all traces of the progressbar
+ upon termination of iteration.
+ If `None`, will leave only if `position` is `0`.
+ file : `io.TextIOWrapper` or `io.StringIO`, optional
+ Specifies where to output the progress messages
+ (default: sys.stderr). Uses `file.write(str)` and `file.flush()`
+ methods. For encoding, see `write_bytes`.
+ ncols : int, optional
+ The width of the entire output message. If specified,
+ dynamically resizes the progressbar to stay within this bound.
+ If unspecified, attempts to use environment width. The
+ fallback is a meter width of 10 and no limit for the counter and
+ statistics. If 0, will not print any meter (only stats).
+ mininterval : float, optional
+ Minimum progress display update interval [default: 0.1] seconds.
+ maxinterval : float, optional
+ Maximum progress display update interval [default: 10] seconds.
+ Automatically adjusts `miniters` to correspond to `mininterval`
+ after long display update lag. Only works if `dynamic_miniters`
+ or monitor thread is enabled.
+ miniters : int or float, optional
+ Minimum progress display update interval, in iterations.
+ If 0 and `dynamic_miniters`, will automatically adjust to equal
+ `mininterval` (more CPU efficient, good for tight loops).
+ If > 0, will skip display of specified number of iterations.
+ Tweak this and `mininterval` to get very efficient loops.
+ If your progress is erratic with both fast and slow iterations
+ (network, skipping items, etc) you should set miniters=1.
+ ascii : bool or str, optional
+ If unspecified or False, use unicode (smooth blocks) to fill
+ the meter. The fallback is to use ASCII characters " 123456789#".
+ disable : bool, optional
+ Whether to disable the entire progressbar wrapper
+ [default: False]. If set to None, disable on non-TTY.
+ unit : str, optional
+ String that will be used to define the unit of each iteration
+ [default: it].
+ unit_scale : 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 Units standard will be added
+ (kilo, mega, etc.) [default: False]. If any other non-zero
+ number, will scale `total` and `n`.
+ dynamic_ncols : bool, optional
+ If set, constantly alters `ncols` and `nrows` to the
+ environment (allowing for window resizes) [default: False].
+ smoothing : float, optional
+ Exponential moving average smoothing factor for speed estimates
+ (ignored in GUI mode). Ranges from 0 (average speed) to 1
+ (current/instantaneous speed) [default: 0.3].
+ bar_format : str, optional
+ Specify a custom bar string formatting. May impact performance.
+ [default: '{l_bar}{bar}{r_bar}'], where
+ l_bar='{desc}: {percentage:3.0f}%|' and
+ r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, '
+ '{rate_fmt}{postfix}]'
+ Possible 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, eta.
+ Note that a trailing ": " is automatically removed after {desc}
+ if the latter is empty.
+ initial : int or float, optional
+ The initial counter value. Useful when restarting a progress
+ bar [default: 0]. If using float, consider specifying `{n:.3f}`
+ or similar in `bar_format`, or specifying `unit_scale`.
+ position : int, optional
+ Specify the line offset to print this bar (starting from 0)
+ Automatic if unspecified.
+ Useful to manage multiple bars at once (eg, from threads).
+ postfix : dict or *, optional
+ Specify additional stats to display at the end of the bar.
+ Calls `set_postfix(**postfix)` if possible (dict).
+ unit_divisor : float, optional
+ [default: 1000], ignored unless `unit_scale` is True.
+ write_bytes : bool, optional
+ If (default: None) and `file` is unspecified,
+ bytes will be written in Python 2. If `True` will also write
+ bytes. In all other cases will default to unicode.
+ lock_args : tuple, optional
+ Passed to `refresh` for intermediate output
+ (initialisation, iterating, and updating).
+ nrows : int, optional
+ 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
+ matplotlib animations for a graphical output [default: False].
+
+ Returns
+ -------
+ out : decorated iterator.
+ """
+ if write_bytes is None:
+ write_bytes = file is None and sys.version_info < (3,)
+
+ if file is None:
+ file = sys.stderr
+
+ if write_bytes:
+ # Despite coercing unicode into bytes, py2 sys.std* streams
+ # should have bytes written to them.
+ 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
+
+ if total is None and iterable is not None:
+ try:
+ total = len(iterable)
+ except (TypeError, AttributeError):
+ total = None
+ if total == float("inf"):
+ # Infinite iterations, behave same as unknown
+ total = None
+
+ if disable:
+ self.iterable = iterable
+ self.disable = disable
+ with self._lock:
+ self.pos = self._get_free_pos(self)
+ self._instances.remove(self)
+ self.n = initial
+ self.total = total
+ self.leave = leave
+ return
+
+ if kwargs:
+ self.disable = True
+ with self._lock:
+ self.pos = self._get_free_pos(self)
+ self._instances.remove(self)
+ raise (
+ TqdmDeprecationWarning(
+ "`nested` is deprecated and automated.\n"
+ "Use `position` instead for manual control.\n",
+ fp_write=getattr(file, 'write', sys.stderr.write))
+ if "nested" in kwargs else
+ 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 dynamic_ncols:
+ dynamic_ncols = _screen_shape_wrapper()
+ if dynamic_ncols:
+ ncols, nrows = dynamic_ncols(file)
+ else:
+ _dynamic_ncols = _screen_shape_wrapper()
+ if _dynamic_ncols:
+ _ncols, _nrows = _dynamic_ncols(file)
+ if ncols is None:
+ ncols = _ncols
+ if nrows is None:
+ nrows = _nrows
+
+ if miniters is None:
+ miniters = 0
+ dynamic_miniters = True
+ else:
+ dynamic_miniters = False
+
+ if mininterval is None:
+ mininterval = 0
+
+ if maxinterval is None:
+ maxinterval = 0
+
+ if ascii is None:
+ ascii = not _supports_unicode(file)
+
+ 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)
+
+ if smoothing is None:
+ smoothing = 0
+
+ # Store the arguments
+ self.iterable = iterable
+ self.desc = desc or ''
+ self.total = total
+ self.leave = leave
+ self.fp = file
+ self.ncols = ncols
+ self.nrows = nrows
+ self.mininterval = mininterval
+ self.maxinterval = maxinterval
+ self.miniters = miniters
+ self.dynamic_miniters = dynamic_miniters
+ self.ascii = ascii
+ self.disable = disable
+ 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._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)
+ except TypeError:
+ self.postfix = postfix
+
+ # Init the iterations counters
+ self.last_print_n = initial
+ self.n = initial
+
+ # if nested, at initial sp() call we replace '\r' by '\n' to
+ # not overwrite the outer progress bar
+ with self._lock:
+ # 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)
+ if delay <= 0:
+ self.refresh(lock_args=self.lock_args)
+
+ # Init the time counter
+ self.last_print_t = self._time()
+ # NB: Avoid race conditions by setting start_t at the very end of init
+ self.start_t = self.last_print_t
+
+ def __bool__(self):
+ if self.total is not None:
+ return self.total > 0
+ if self.iterable is None:
+ raise TypeError('bool() undefined when iterable == total == None')
+ return bool(self.iterable)
+
+ def __nonzero__(self):
+ 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 self.iterable.__length_hint__() if hasattr(self.iterable, "__length_hint__")
+ else getattr(self, "total", None))
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ try:
+ self.close()
+ except AttributeError:
+ # maybe eager thread cleanup upon external error
+ if (exc_type, exc_value, traceback) == (None, None, None):
+ raise
+ warn("AttributeError ignored", TqdmWarning, stacklevel=2)
+
+ def __del__(self):
+ self.close()
+
+ def __str__(self):
+ return self.format_meter(**self.format_dict)
+
+ @property
+ def _comparable(self):
+ return abs(getattr(self, "pos", 1 << 31))
+
+ def __hash__(self):
+ return id(self)
+
+ def __iter__(self):
+ """Backward-compatibility to use: for x in tqdm(iterable)"""
+
+ # Inlining instance variables as locals (speed optimisation)
+ iterable = self.iterable
+
+ # If the bar is disabled, then just walk the iterable
+ # (note: keep this check outside the loop for performance)
+ if self.disable:
+ for obj in iterable:
+ yield obj
+ return
+
+ mininterval = self.mininterval
+ 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
+ time = self._time
+
+ 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
+
+ if n - last_print_n >= self.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:
+ self.n = n
+ self.close()
+
+ def update(self, n=1):
+ """
+ Manually update the progress bar, useful for streams
+ such as reading files.
+ E.g.:
+ >>> t = tqdm(total=filesize) # Initialise
+ >>> for current_buffer in stream:
+ ... ...
+ ... t.update(len(current_buffer))
+ >>> t.close()
+ The last line is highly recommended, but possibly not necessary if
+ `t.update()` will be called in such a way that `filesize` will be
+ exactly reached and printed.
+
+ Parameters
+ ----------
+ n : int or float, optional
+ 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.
+ """
+ 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:
+ 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()
+ 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 self.dynamic_miniters:
+ # 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:
+ # EMA miniters update
+ self.miniters = self._ema_miniters(
+ dn * (self.mininterval / dt if self.mininterval and dt
+ else 1))
+ else:
+ # 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."""
+ if self.disable:
+ return
+
+ # Prevent multiple closures
+ self.disable = True
+
+ # decrement instance pos and remove from internal set
+ 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 getattr(self, 'sp', None) is None:
+ return
+
+ # annoyingly, _supports_unicode isn't good enough
+ def fp_write(s):
+ self.fp.write(_unicode(s))
+
+ try:
+ fp_write('')
+ except ValueError as e:
+ if 'closed' in str(e):
+ return
+ raise # pragma: no cover
+
+ leave = pos == 0 if self.leave is None else self.leave
+
+ with self._lock:
+ if leave:
+ # stats for overall rate (no weighted average)
+ self._ema_dt = lambda: None
+ self.display(pos=0)
+ fp_write('\n')
+ else:
+ # clear previous display
+ if self.display(msg='', pos=pos) and not pos:
+ fp_write('\r')
+
+ def clear(self, nolock=False):
+ """Clear current bar display."""
+ if self.disable:
+ return
+
+ if not nolock:
+ self._lock.acquire()
+ pos = abs(self.pos)
+ if pos < (self.nrows or 20):
+ self.moveto(pos)
+ self.sp('')
+ self.fp.write('\r') # place cursor back at the beginning of line
+ self.moveto(-pos)
+ if not nolock:
+ self._lock.release()
+
+ def refresh(self, nolock=False, lock_args=None):
+ """
+ Force refresh the display of this bar.
+
+ Parameters
+ ----------
+ nolock : bool, optional
+ If `True`, does not lock.
+ If [default: `False`]: calls `acquire()` on internal lock.
+ lock_args : tuple, optional
+ Passed to internal lock's `acquire()`.
+ If specified, will only `display()` if `acquire()` returns `True`.
+ """
+ if self.disable:
+ return
+
+ if not nolock:
+ if lock_args:
+ if not self._lock.acquire(*lock_args):
+ return False
+ else:
+ self._lock.acquire()
+ self.display()
+ if not nolock:
+ self._lock.release()
+ return True
+
+ 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
+
+ def reset(self, total=None):
+ """
+ Resets to 0 iterations for repeated use.
+
+ Consider combining with `leave=True`.
+
+ Parameters
+ ----------
+ total : int or float, optional. Total to use for the new bar.
+ """
+ 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):
+ """
+ Set/modify description of the progress bar.
+
+ Parameters
+ ----------
+ desc : str, optional
+ refresh : bool, optional
+ Forces refresh [default: True].
+ """
+ self.desc = desc + ': ' if desc else ''
+ if refresh:
+ self.refresh()
+
+ def set_description_str(self, desc=None, refresh=True):
+ """Set/modify description without ': ' appended."""
+ self.desc = desc or ''
+ if refresh:
+ self.refresh()
+
+ def set_postfix(self, ordered_dict=None, refresh=True, **kwargs):
+ """
+ Set/modify postfix (additional stats)
+ with automatic formatting based on datatype.
+
+ Parameters
+ ----------
+ ordered_dict : dict or OrderedDict, optional
+ refresh : bool, optional
+ Forces refresh [default: True].
+ kwargs : dict, optional
+ """
+ # Sort in alphabetical order to be more deterministic
+ 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
+ for key in postfix.keys():
+ # Number: limit the length of the string
+ if isinstance(postfix[key], Number):
+ postfix[key] = self.format_num(postfix[key])
+ # Else for any other type, try to get the string conversion
+ elif not isinstance(postfix[key], _basestring):
+ postfix[key] = str(postfix[key])
+ # Else if it's a string, don't need to preprocess anything
+ # Stitch together to get the final postfix
+ self.postfix = ', '.join(key + '=' + postfix[key].strip()
+ for key in postfix.keys())
+ if refresh:
+ self.refresh()
+
+ def set_postfix_str(self, s='', refresh=True):
+ """
+ Postfix without dictionary expansion, similar to prefix handling.
+ """
+ self.postfix = str(s)
+ if refresh:
+ self.refresh()
+
+ def moveto(self, n):
+ # TODO: private method
+ self.fp.write(_unicode('\n' * n + _term_move_up() * -n))
+ self.fp.flush()
+
+ @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)
+ 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):
+ """
+ Use `self.sp` to display `msg` in the specified `pos`.
+
+ Consider overloading this function when inheriting to use e.g.:
+ `self.some_frontend(**self.format_dict)` instead of `self.sp`.
+
+ Parameters
+ ----------
+ msg : str, optional. What to display (default: `repr(self)`).
+ pos : int, optional. Position to `moveto`
+ (default: `abs(self.pos)`).
+ """
+ if pos is None:
+ pos = abs(self.pos)
+
+ nrows = self.nrows or 20
+ if pos >= nrows - 1:
+ if pos >= nrows:
+ return False
+ 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.__str__() if msg is None else msg)
+ if pos:
+ self.moveto(-pos)
+ return True
+
+ @classmethod
+ @contextmanager
+ 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
+ the first argument of `write()` should have a `len()`.
+
+ >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj:
+ ... while True:
+ ... chunk = fobj.read(chunk_size)
+ ... if not chunk:
+ ... break
+ """
+ with cls(total=total, **tqdm_kwargs) as t:
+ if bytes:
+ t.unit = "B"
+ t.unit_scale = True
+ t.unit_divisor = 1024
+ yield CallbackIOWrapper(t.update, stream, method)
+
+
+def trange(*args, **kwargs):
+ """
+ A shortcut for tqdm(xrange(*args), **kwargs).
+ On Python3+ range is used instead of xrange.
+ """
+ return tqdm(_range(*args), **kwargs)
diff --git a/third_party/python/tqdm/tqdm/tk.py b/third_party/python/tqdm/tqdm/tk.py
new file mode 100644
index 0000000000..92adb51db3
--- /dev/null
+++ b/third_party/python/tqdm/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/third_party/python/tqdm/tqdm/tqdm.1 b/third_party/python/tqdm/tqdm/tqdm.1
new file mode 100644
index 0000000000..0533198ca5
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/tqdm.1
@@ -0,0 +1,316 @@
+.\" Automatically generated by Pandoc 1.19.2
+.\"
+.TH "TQDM" "1" "2015\-2021" "tqdm User Manuals" ""
+.hy
+.SH NAME
+.PP
+tqdm \- fast, extensible progress bar for Python and CLI
+.SH SYNOPSIS
+.PP
+tqdm [\f[I]options\f[]]
+.SH DESCRIPTION
+.PP
+See <https://github.com/tqdm/tqdm>.
+Can be used as a pipe:
+.IP
+.nf
+\f[C]
+$\ #\ count\ lines\ of\ code
+$\ cat\ *.py\ |\ tqdm\ |\ wc\ \-l
+327it\ [00:00,\ 981773.38it/s]
+327
+
+$\ #\ find\ all\ files
+$\ find\ .\ \-name\ "*.py"\ |\ tqdm\ |\ wc\ \-l
+432it\ [00:00,\ 833842.30it/s]
+432
+
+#\ ...\ and\ more\ info
+$\ find\ .\ \-name\ \[aq]*.py\[aq]\ \-exec\ wc\ \-l\ \\{}\ \\;\ \\
+\ \ |\ tqdm\ \-\-total\ 432\ \-\-unit\ files\ \-\-desc\ counting\ \\
+\ \ |\ awk\ \[aq]{\ sum\ +=\ $1\ };\ END\ {\ print\ sum\ }\[aq]
+counting:\ 100%|█████████|\ 432/432\ [00:00<00:00,\ 794361.83files/s]
+131998
+\f[]
+.fi
+.SH OPTIONS
+.TP
+.B \-h, \-\-help
+Print this help and exit.
+.RS
+.RE
+.TP
+.B \-v, \-\-version
+Print version and exit.
+.RS
+.RE
+.TP
+.B \-\-desc=\f[I]desc\f[]
+str, optional.
+Prefix for the progressbar.
+.RS
+.RE
+.TP
+.B \-\-total=\f[I]total\f[]
+int or float, optional.
+The number of expected iterations.
+If unspecified, len(iterable) is used if possible.
+If float("inf") or as a last resort, only basic progress statistics are
+displayed (no ETA, no progressbar).
+If \f[C]gui\f[] is True and this parameter needs subsequent updating,
+specify an initial arbitrary large positive number, e.g.
+9e9.
+.RS
+.RE
+.TP
+.B \-\-leave
+bool, optional.
+If [default: True], keeps all traces of the progressbar upon termination
+of iteration.
+If \f[C]None\f[], will leave only if \f[C]position\f[] is \f[C]0\f[].
+.RS
+.RE
+.TP
+.B \-\-ncols=\f[I]ncols\f[]
+int, optional.
+The width of the entire output message.
+If specified, dynamically resizes the progressbar to stay within this
+bound.
+If unspecified, attempts to use environment width.
+The fallback is a meter width of 10 and no limit for the counter and
+statistics.
+If 0, will not print any meter (only stats).
+.RS
+.RE
+.TP
+.B \-\-mininterval=\f[I]mininterval\f[]
+float, optional.
+Minimum progress display update interval [default: 0.1] seconds.
+.RS
+.RE
+.TP
+.B \-\-maxinterval=\f[I]maxinterval\f[]
+float, optional.
+Maximum progress display update interval [default: 10] seconds.
+Automatically adjusts \f[C]miniters\f[] to correspond to
+\f[C]mininterval\f[] after long display update lag.
+Only works if \f[C]dynamic_miniters\f[] or monitor thread is enabled.
+.RS
+.RE
+.TP
+.B \-\-miniters=\f[I]miniters\f[]
+int or float, optional.
+Minimum progress display update interval, in iterations.
+If 0 and \f[C]dynamic_miniters\f[], will automatically adjust to equal
+\f[C]mininterval\f[] (more CPU efficient, good for tight loops).
+If > 0, will skip display of specified number of iterations.
+Tweak this and \f[C]mininterval\f[] to get very efficient loops.
+If your progress is erratic with both fast and slow iterations (network,
+skipping items, etc) you should set miniters=1.
+.RS
+.RE
+.TP
+.B \-\-ascii=\f[I]ascii\f[]
+bool or str, optional.
+If unspecified or False, use unicode (smooth blocks) to fill the meter.
+The fallback is to use ASCII characters " 123456789#".
+.RS
+.RE
+.TP
+.B \-\-disable
+bool, optional.
+Whether to disable the entire progressbar wrapper [default: False].
+If set to None, disable on non\-TTY.
+.RS
+.RE
+.TP
+.B \-\-unit=\f[I]unit\f[]
+str, optional.
+String that will be used to define the unit of each iteration [default:
+it].
+.RS
+.RE
+.TP
+.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
+Units standard will be added (kilo, mega, etc.) [default: False].
+If any other non\-zero number, will scale \f[C]total\f[] and \f[C]n\f[].
+.RS
+.RE
+.TP
+.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].
+.RS
+.RE
+.TP
+.B \-\-smoothing=\f[I]smoothing\f[]
+float, optional.
+Exponential moving average smoothing factor for speed estimates (ignored
+in GUI mode).
+Ranges from 0 (average speed) to 1 (current/instantaneous speed)
+[default: 0.3].
+.RS
+.RE
+.TP
+.B \-\-bar\-format=\f[I]bar_format\f[]
+str, optional.
+Specify a custom bar string formatting.
+May impact performance.
+[default: \[aq]{l_bar}{bar}{r_bar}\[aq]], where l_bar=\[aq]{desc}:
+{percentage:3.0f}%|\[aq] and r_bar=\[aq]| {n_fmt}/{total_fmt}
+[{elapsed}<{remaining}, \[aq] \[aq]{rate_fmt}{postfix}]\[aq] Possible
+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, eta.
+Note that a trailing ": " is automatically removed after {desc} if the
+latter is empty.
+.RS
+.RE
+.TP
+.B \-\-initial=\f[I]initial\f[]
+int or float, optional.
+The initial counter value.
+Useful when restarting a progress bar [default: 0].
+If using float, consider specifying \f[C]{n:.3f}\f[] or similar in
+\f[C]bar_format\f[], or specifying \f[C]unit_scale\f[].
+.RS
+.RE
+.TP
+.B \-\-position=\f[I]position\f[]
+int, optional.
+Specify the line offset to print this bar (starting from 0) Automatic if
+unspecified.
+Useful to manage multiple bars at once (eg, from threads).
+.RS
+.RE
+.TP
+.B \-\-postfix=\f[I]postfix\f[]
+dict or *, optional.
+Specify additional stats to display at the end of the bar.
+Calls \f[C]set_postfix(**postfix)\f[] if possible (dict).
+.RS
+.RE
+.TP
+.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
+bool, optional.
+If (default: None) and \f[C]file\f[] is unspecified, bytes will be
+written in Python 2.
+If \f[C]True\f[] will also write bytes.
+In all other cases will default to unicode.
+.RS
+.RE
+.TP
+.B \-\-lock\-args=\f[I]lock_args\f[]
+tuple, optional.
+Passed to \f[C]refresh\f[] for intermediate output (initialisation,
+iterating, and updating).
+.RS
+.RE
+.TP
+.B \-\-nrows=\f[I]nrows\f[]
+int, optional.
+The screen height.
+If specified, hides nested bars outside this bound.
+If unspecified, attempts to use environment height.
+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]].
+Use \[aq]\\0\[aq] for null.
+N.B.: on Windows systems, Python converts \[aq]\\n\[aq] to
+\[aq]\\r\\n\[aq].
+.RS
+.RE
+.TP
+.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
+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
+\f[C]unit\f[] to \[aq]B\[aq].
+.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.
+.RS
+.RE
+.TP
+.B \-\-comppath=\f[I]comppath\f[]
+str, optional.
+Directory in which to place tqdm completion.
+.RS
+.RE
+.TP
+.B \-\-log=\f[I]log\f[]
+str, optional.
+CRITICAL|FATAL|ERROR|WARN(ING)|[default: \[aq]INFO\[aq]]|DEBUG|NOTSET.
+.RS
+.RE
+.SH AUTHORS
+tqdm developers <https://github.com/tqdm>.
diff --git a/third_party/python/tqdm/tqdm/utils.py b/third_party/python/tqdm/tqdm/utils.py
new file mode 100644
index 0000000000..0632b8dd05
--- /dev/null
+++ b/third_party/python/tqdm/tqdm/utils.py
@@ -0,0 +1,354 @@
+"""
+General helpers required for `tqdm.std`.
+"""
+import os
+import re
+import sys
+from functools import wraps
+from warnings import warn
+from weakref import proxy
+
+# py2/3 compat
+try:
+ _range = xrange
+except NameError:
+ _range = range
+
+try:
+ _unich = unichr
+except NameError:
+ _unich = chr
+
+try:
+ _unicode = unicode
+except NameError:
+ _unicode = str
+
+try:
+ _basestring = basestring
+except NameError:
+ _basestring = 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
+else:
+ try:
+ colorama.init(strip=False)
+ except TypeError:
+ colorama.init()
+
+
+class FormatReplace(object):
+ """
+ >>> a = FormatReplace('something')
+ >>> "{:5d}".format(a)
+ 'something'
+ """ # NOQA: P102
+ def __init__(self, replace=''):
+ self.replace = replace
+ self.format_called = 0
+
+ def __format__(self, _):
+ self.format_called += 1
+ return self.replace
+
+
+class Comparable(object):
+ """Assumes child has self._comparable attr/@property"""
+ def __lt__(self, other):
+ return self._comparable < other._comparable
+
+ def __le__(self, other):
+ return (self < other) or (self == other)
+
+ def __eq__(self, other):
+ return self._comparable == other._comparable
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __gt__(self, other):
+ return not self <= other
+
+ def __ge__(self, other):
+ return not self < other
+
+
+class ObjectWrapper(object):
+ def __getattr__(self, name):
+ return getattr(self._wrapped, name)
+
+ def __setattr__(self, name, value):
+ return setattr(self._wrapped, name, value)
+
+ def wrapper_getattr(self, name):
+ """Actual `self.getattr` rather than self._wrapped.getattr"""
+ try:
+ return object.__getattr__(self, name)
+ except AttributeError: # py2
+ return getattr(self, name)
+
+ def wrapper_setattr(self, name, value):
+ """Actual `self.setattr` rather than self._wrapped.setattr"""
+ return object.__setattr__(self, name, value)
+
+ def __init__(self, wrapped):
+ """
+ Thin wrapper around a given object
+ """
+ self.wrapper_setattr('_wrapped', wrapped)
+
+
+class SimpleTextIOWrapper(ObjectWrapper):
+ """
+ Change only `.write()` of the wrapped object by encoding the passed
+ value and passing the result to the wrapped object's `.write()` method.
+ """
+ # pylint: disable=too-few-public-methods
+ def __init__(self, wrapped, encoding):
+ super(SimpleTextIOWrapper, self).__init__(wrapped)
+ self.wrapper_setattr('encoding', encoding)
+
+ def write(self, s):
+ """
+ Encode `s` and pass to the wrapped object's `.write()` method.
+ """
+ return self._wrapped.write(s.encode(self.wrapper_getattr('encoding')))
+
+ def __eq__(self, other):
+ 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"):
+ """
+ Wrap a given `file`-like object's `read()` or `write()` to report
+ lengths to the given `callback`
+ """
+ super(CallbackIOWrapper, self).__init__(stream)
+ func = getattr(stream, method)
+ if method == "write":
+ @wraps(func)
+ def write(data, *args, **kwargs):
+ res = func(data, *args, **kwargs)
+ callback(len(data))
+ return res
+ self.wrapper_setattr('write', write)
+ elif method == "read":
+ @wraps(func)
+ def read(*args, **kwargs):
+ data = func(*args, **kwargs)
+ callback(len(data))
+ return data
+ self.wrapper_setattr('read', read)
+ else:
+ raise KeyError("Can only wrap read/write methods")
+
+
+def _is_utf(encoding):
+ try:
+ u'\u2588\u2589'.encode(encoding)
+ except UnicodeEncodeError:
+ return False
+ except Exception:
+ try:
+ return encoding.lower().startswith('utf-') or ('U8' == encoding)
+ except Exception:
+ return False
+ else:
+ return True
+
+
+def _supports_unicode(fp):
+ try:
+ return _is_utf(fp.encoding)
+ except AttributeError:
+ return False
+
+
+def _is_ascii(s):
+ if isinstance(s, str):
+ for c in s:
+ if ord(c) > 255:
+ return False
+ return True
+ return _supports_unicode(s)
+
+
+def _screen_shape_wrapper(): # pragma: no cover
+ """
+ Return a function which returns console dimensions (width, height).
+ Supported: linux, osx, windows, cygwin.
+ """
+ _screen_shape = None
+ if IS_WIN:
+ _screen_shape = _screen_shape_windows
+ if _screen_shape is None:
+ _screen_shape = _screen_shape_tput
+ if IS_NIX:
+ _screen_shape = _screen_shape_linux
+ return _screen_shape
+
+
+def _screen_shape_windows(fp): # pragma: no cover
+ try:
+ import struct
+ from ctypes import create_string_buffer, windll
+ from sys import stdin, stdout
+
+ io_handle = -12 # assume stderr
+ if fp == stdin:
+ io_handle = -10
+ elif fp == stdout:
+ io_handle = -11
+
+ h = windll.kernel32.GetStdHandle(io_handle)
+ csbi = create_string_buffer(22)
+ res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
+ if res:
+ (_bufx, _bufy, _curx, _cury, _wattr, left, top, right, bottom,
+ _maxx, _maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
+ return right - left, bottom - top # +1
+ except Exception: # nosec
+ pass
+ return None, None
+
+
+def _screen_shape_tput(*_): # pragma: no cover
+ """cygwin xterm (windows)"""
+ try:
+ import shlex
+ from subprocess import check_call # nosec
+ return [int(check_call(shlex.split('tput ' + i))) - 1
+ for i in ('cols', 'lines')]
+ except Exception: # nosec
+ pass
+ return None, None
+
+
+def _screen_shape_linux(fp): # pragma: no cover
+
+ try:
+ from array import array
+ from fcntl import ioctl
+ from termios import TIOCGWINSZ
+ except ImportError:
+ return None, None
+ else:
+ try:
+ rows, cols = array('h', ioctl(fp, TIOCGWINSZ, '\0' * 8))[:2]
+ return cols, rows
+ except Exception:
+ try:
+ return [int(os.environ[i]) - 1 for i in ("COLUMNS", "LINES")]
+ except (KeyError, ValueError):
+ return None, None
+
+
+def _environ_cols_wrapper(): # pragma: no cover
+ """
+ Return a function which returns console width.
+ Supported: linux, osx, windows, cygwin.
+ """
+ warn("Use `_screen_shape_wrapper()(file)[0]` instead of"
+ " `_environ_cols_wrapper()(file)`", DeprecationWarning, stacklevel=2)
+ shape = _screen_shape_wrapper()
+ if not shape:
+ return None
+
+ @wraps(shape)
+ def inner(fp):
+ return shape(fp)[0]
+
+ return inner
+
+
+def _term_move_up(): # pragma: no cover
+ return '' if (os.name == 'nt') and (colorama is None) else '\x1b[A'
+
+
+try:
+ # TODO consider using wcswidth third-party package for 0-width characters
+ from unicodedata import east_asian_width
+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))
+
+
+def disp_len(data):
+ """
+ Returns the real on-screen length of a string which may contain
+ ANSI control codes and wide chars.
+ """
+ return _text_width(RE_ANSI.sub('', data))
+
+
+def disp_trim(data, length):
+ """
+ Trim a string which may contain ANSI control characters.
+ """
+ if len(data) == disp_len(data):
+ return data[:length]
+
+ ansi_present = bool(RE_ANSI.search(data))
+ while disp_len(data) > length: # carefully delete one char at a time
+ data = data[:-1]
+ if ansi_present and bool(RE_ANSI.search(data)):
+ # assume ANSI reset is required
+ return data if data.endswith("\033[0m") else data + "\033[0m"
+ return data
diff --git a/third_party/python/tqdm/tqdm/version.py b/third_party/python/tqdm/tqdm/version.py
new file mode 100644
index 0000000000..11cbaea79d
--- /dev/null
+++ b/third_party/python/tqdm/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"