1
0
Fork 0

Compare commits

...

5 commits

Author SHA1 Message Date
9769cec287
Adding upstream version 4.67.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-02-05 19:22:57 +01:00
b09a1c9c3a
Adding upstream version 4.67.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-02-05 19:22:20 +01:00
579fccd9fa
Adding upstream version 4.66.5.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-02-05 19:21:46 +01:00
49887fb75a
Adding upstream version 4.66.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-02-05 19:19:03 +01:00
ee135df3b4
Adding upstream version 4.66.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-02-05 19:14:23 +01:00
62 changed files with 1067 additions and 4461 deletions

View file

@ -2,7 +2,7 @@ default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
rev: v5.0.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
@ -37,9 +37,9 @@ repos:
- numpy
- pandas
- pytest-timeout
- pytest-asyncio
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
- pytest-asyncio>=0.24
- repo: https://github.com/PyCQA/flake8
rev: 7.1.1
hooks:
- id: flake8
args: [-j8]
@ -49,14 +49,14 @@ repos:
- flake8-comprehensions
- flake8-debugger
- flake8-isort
- flake8-pyproject
- flake8-string-format
- flake8-type-annotations
- repo: https://github.com/PyCQA/isort
rev: 5.10.1
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/kynan/nbstripout
rev: 0.5.0
rev: 0.7.1
hooks:
- id: nbstripout
args: [--keep-count, --keep-output]

View file

@ -12,7 +12,7 @@ Makefile:
```
make [<alias>] # on UNIX-like environments
python setup.py make [<alias>] # if make is unavailable
python -m pymake [<alias>] # if make is unavailable
```
The latter depends on [`py-make>=0.1.0`](https://github.com/tqdm/py-make).
@ -51,7 +51,7 @@ However it would be helpful to bear in mind:
* use two spaces between variable name and colon, specify a type, and most likely state that it's optional: `VAR<space><space>:<space>TYPE[, optional]`
* use [default: ...] for default values of keyword arguments
+ will not break backward compatibility unless there is a very good reason
* e.g. breaking py26 compatibility purely in favour of readability (such as converting `dict(a=1)` to `{'a': 1}`) is not a good enough reason
* e.g. breaking py26 compatibility purely in favour of minor readability changes (such as converting `dict(a=1)` to `{'a': 1}`) is not a good enough reason
+ API changes should be discussed carefully
+ remember, with millions of downloads per month, `tqdm` must be extremely fast and reliable
- Any other kind of change may be included in a (possibly new) submodule
@ -85,7 +85,7 @@ The standard way to run the tests:
- run the following command:
```
[python setup.py] make test
[python -m py]make test
# or:
tox --skip-missing-interpreters
```
@ -97,19 +97,19 @@ versions of Python.)
Note: to install all versions of the Python interpreter that are specified
in [tox.ini](https://github.com/tqdm/tqdm/blob/master/tox.ini),
you can use `MiniConda` to install a minimal setup. You must also make sure
that each distribution has an alias to call the Python interpreter:
`python27` for Python 2.7's interpreter, `python32` for Python 3.2's, etc.
you can use `MiniConda` to install a minimal setup. You must also ensure
that each distribution has an alias to call the Python interpreter
(e.g. `python312` for Python 3.12's interpreter).
### Alternative unit tests with pytest
Alternatively, use `pytest` to run the tests just for the current Python version:
- install test requirements: `[python setup.py] make install_test`
- install test requirements: `[python -m py]make install_test`
- run the following command:
```
[python setup.py] make alltests
[python -m py]make alltests
```
@ -118,9 +118,9 @@ Alternatively, use `pytest` to run the tests just for the current Python version
This section is intended for the project's maintainers and describes
how to build and upload a new release. Once again,
`[python setup.py] make [<alias>]` will help.
`[python -m py]make [<alias>]` will help.
Also consider `pip install`ing development utilities:
`[python setup.py] make install_build` at a minimum, or a more thorough `conda env create`.
`[python -m py]make install_build` at a minimum, or a more thorough `conda env create`.
## Pre-commit Hook
@ -137,20 +137,20 @@ The `tqdm` repository managers should:
- follow the [Semantic Versioning](https://semver.org) convention for tagging
## Checking setup.py
## Checking `pyproject.toml`
To check that the `setup.py`/`setup.cfg`/`pyproject.toml` file is compliant with PyPI
To check that the `pyproject.toml` file is compliant with PyPI
requirements (e.g. version number; reStructuredText in `README.rst`) use:
```
[python setup.py] make testsetup
[python -m py]make testsetup
```
To upload just metadata (including overwriting mistakenly uploaded metadata)
to PyPI, use:
```
[python setup.py] make pypimeta
[python -m py]make pypimeta
```
@ -199,7 +199,7 @@ git merge --no-ff pr-branch-name
### 4 Test
```
[python setup.py] make alltests
[python -m py]make alltests
```
### 5 Push to master
@ -233,7 +233,7 @@ Manual instructions are given below in case of failure.
Build `tqdm` into a distributable python package:
```
[python setup.py] make build
[python -m py]make build
```
This will generate several builds in the `dist/` folder. On non-windows
@ -243,13 +243,13 @@ Finally, upload everything to PyPI. This can be done easily using the
[twine](https://github.com/pypa/twine) module:
```
[python setup.py] make pypi
[python -m py]make pypi
```
Also, the new release can (should) be added to GitHub by creating a new
release from the [web interface](https://github.com/tqdm/tqdm/releases);
uploading packages from the `dist/` folder
created by `[python setup.py] make build`.
created by `[python -m py]make build`.
The [wiki] can be automatically updated with GitHub release notes by
running `make` within the wiki repository.
@ -282,7 +282,7 @@ before the real deployment
- in case of a mistake, you can delete an uploaded release on PyPI, but you
cannot re-upload another with the same version number
- in case of a mistake in the metadata on PyPI (e.g. bad README),
updating just the metadata is possible: `[python setup.py] make pypimeta`
updating just the metadata is possible: `[python -m py]make pypimeta`
## Updating Websites
@ -333,16 +333,16 @@ to assist with maintenance.
For experienced devs, once happy with local master, follow the steps below.
Much is automated so really it's steps 1-5, then 11(a).
1. test (`[python setup.py] make alltests` or rely on `pre-commit`)
1. test (`[python -m py]make alltests` or rely on `pre-commit`)
2. `git commit [--amend] # -m "bump version"`
3. `git push`
4. wait for tests to pass
a) in case of failure, fix and go back to (1)
5. `git tag vM.m.p && git push --tags` or comment `/tag vM.m.p commit_hash`
6. **`[AUTO:GHA]`** `[python setup.py] make distclean`
7. **`[AUTO:GHA]`** `[python setup.py] make build`
6. **`[AUTO:GHA]`** `[python -m py]make distclean`
7. **`[AUTO:GHA]`** `[python -m py]make build`
8. **`[AUTO:GHA]`** upload to PyPI. either:
a) `[python setup.py] make pypi`, or
a) `[python -m py]make pypi`, or
b) `twine upload -s -i $(git config user.signingkey) dist/tqdm-*`
9. **`[AUTO:GHA]`** upload to docker hub:
a) `make -B docker`
@ -359,7 +359,7 @@ Much is automated so really it's steps 1-5, then 11(a).
13. **`[SUB][AUTO:GHA-rel]`** run `make deploy` in the `docs` submodule to update website
14. **`[SUB][AUTO:GHA-rel]`** accept the automated PR in the `feedstock` submodule to update conda
15. **`[AUTO:GHA-rel]`** update the [gh-pages project] benchmarks
a) `[python setup.py] make testasvfull`
a) `[python -m py]make testasvfull`
b) `asv gh-pages`
Key:

View file

@ -5,12 +5,12 @@
"metadata": {},
"source": [
"<h1 align=\"center\">tqdm</h1>\n",
"<img src=\"https://img.tqdm.ml/logo.gif\" align=\"left\" />\n",
"<img src=\"https://tqdm.github.io/img/logo.gif\" align=\"left\" />\n",
"\n",
"[![Py-Versions](https://img.shields.io/pypi/pyversions/tqdm.svg?logo=python&logoColor=white)](https://pypi.org/project/tqdm)|[![Versions](https://img.shields.io/pypi/v/tqdm.svg)](https://tqdm.github.io/releases)|[![Conda-Forge-Status](https://img.shields.io/conda/v/conda-forge/tqdm.svg?label=conda-forge&logo=conda-forge)](https://anaconda.org/conda-forge/tqdm)|[![Docker](https://img.shields.io/badge/docker-pull-blue.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/tqdm/tqdm)|[![Snapcraft](https://img.shields.io/badge/snap-install-82BEA0.svg?logo=snapcraft)](https://snapcraft.io/tqdm)\n",
"-|-|-|-|-\n",
"\n",
"[![Build-Status](https://img.shields.io/github/workflow/status/tqdm/tqdm/Test/master?logo=GitHub)](https://github.com/tqdm/tqdm/actions?query=workflow%3ATest)|[![Coverage-Status](https://img.shields.io/coveralls/github/tqdm/tqdm/master?logo=coveralls)](https://coveralls.io/github/tqdm/tqdm)|[![Branch-Coverage-Status](https://codecov.io/gh/tqdm/tqdm/branch/master/graph/badge.svg)](https://codecov.io/gh/tqdm/tqdm)|[![Codacy-Grade](https://app.codacy.com/project/badge/Grade/3f965571598f44549c7818f29cdcf177)](https://www.codacy.com/gh/tqdm/tqdm/dashboard)|[![Libraries-Rank](https://img.shields.io/librariesio/sourcerank/pypi/tqdm.svg?logo=koding&logoColor=white)](https://libraries.io/pypi/tqdm)|[![PyPI-Downloads](https://img.shields.io/pypi/dm/tqdm.svg?label=pypi%20downloads&logo=PyPI&logoColor=white)](https://pepy.tech/project/tqdm)\n",
"[![Build-Status](https://img.shields.io/github/actions/workflow/status/tqdm/tqdm/test.yml?branch=master&label=tqdm&logo=GitHub)](https://github.com/tqdm/tqdm/actions/workflows/test.yml)|[![Coverage-Status](https://img.shields.io/coveralls/github/tqdm/tqdm/master?logo=coveralls)](https://coveralls.io/github/tqdm/tqdm)|[![Branch-Coverage-Status](https://codecov.io/gh/tqdm/tqdm/branch/master/graph/badge.svg)](https://codecov.io/gh/tqdm/tqdm)|[![Codacy-Grade](https://app.codacy.com/project/badge/Grade/3f965571598f44549c7818f29cdcf177)](https://www.codacy.com/gh/tqdm/tqdm/dashboard)|[![Libraries-Rank](https://img.shields.io/librariesio/sourcerank/pypi/tqdm.svg?logo=koding&logoColor=white)](https://libraries.io/pypi/tqdm)|[![PyPI-Downloads](https://img.shields.io/pypi/dm/tqdm.svg?label=pypi%20downloads&logo=PyPI&logoColor=white)](https://pepy.tech/project/tqdm)\n",
"-|-|-|-|-|-\n",
"\n",
"[![DOI](https://img.shields.io/badge/DOI-10.5281/zenodo.595120-blue.svg)](https://doi.org/10.5281/zenodo.595120)|[![LICENCE](https://img.shields.io/pypi/l/tqdm.svg)](https://raw.githubusercontent.com/tqdm/tqdm/master/LICENCE)|[![OpenHub-Status](https://www.openhub.net/p/tqdm/widgets/project_thin_badge?format=gif)](https://www.openhub.net/p/tqdm?ref=Thin+badge)|[![binder-demo](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/tqdm/tqdm/master?filepath=DEMO.ipynb)|[![awesome-python](https://awesome.re/mentioned-badge.svg)](https://github.com/vinta/awesome-python)\n",
@ -40,7 +40,7 @@
"metadata": {},
"source": [
"`trange(N)` can be also used as a convenient shortcut for\n",
"`tqdm(xrange(N))`."
"`tqdm(range(N))`."
]
},
{
@ -58,7 +58,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"![Screenshot](https://img.tqdm.ml/tqdm.gif)|[![Video](https://img.tqdm.ml/video.jpg)](https://tqdm.github.io/video) [![Slides](https://img.tqdm.ml/slides.jpg)](https://tqdm.github.io/PyData2019/slides.html) [![Merch](https://img.tqdm.ml/merch.jpg)](https://tqdm.github.io/merch)\n",
"![Screenshot](https://tqdm.github.io/img/tqdm.gif)|[![Video](https://tqdm.github.io/img/video.jpg)](https://tqdm.github.io/video) [![Slides](https://tqdm.github.io/img/slides.jpg)](https://tqdm.github.io/PyData2019/slides.html) [![Merch](https://tqdm.github.io/img/merch.jpg)](https://tqdm.github.io/merch)\n",
"-|-\n",
"\n",
"It can also be executed as a module with pipes:"
@ -413,7 +413,7 @@
" \"\"\"Provides a `total_time` format parameter\"\"\"\n",
" @property\n",
" def format_dict(self):\n",
" d = super(TqdmExtraFormat, self).format_dict\n",
" d = super().format_dict\n",
" total_time = d[\"elapsed\"] * (d[\"total\"] or 0) / max(d[\"n\"], 1)\n",
" d.update(total_time=self.format_interval(total_time) + \" in total\")\n",
" return d\n",
@ -737,7 +737,7 @@
"bars and colour hints (blue: normal, green: completed, red:\n",
"error/interrupt, light blue: no ETA); as demonstrated below.\n",
"\n",
"![Screenshot-Jupyter3](https://img.tqdm.ml/jupyter-3.gif)\n",
"![Screenshot-Jupyter3](https://tqdm.github.io/img/jupyter-3.gif)\n",
"\n",
"The `notebook` version supports percentage or pixels for overall width\n",
"(e.g.: `ncols='100%'` or `ncols='480px'`).\n",
@ -843,7 +843,7 @@
"specify any file-like object using the `file` argument. For example,\n",
"this can be used to redirect the messages writing to a log file or class.\n",
"\n",
"[![README-Hits](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)](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)|(Since 19 May 2016)\n",
"[![README-Hits](https://cgi.cdcl.ml/hits?q=tqdm&style=social&r=https://github.com/tqdm/tqdm&l=https://tqdm.github.io/img/favicon.png&f=https://tqdm.github.io/img/logo.gif)](https://cgi.cdcl.ml/hits?q=tqdm&a=plot&r=https://github.com/tqdm/tqdm&l=https://tqdm.github.io/img/favicon.png&f=https://tqdm.github.io/img/logo.gif&style=social)|(Since 19 May 2016)\n",
"-|-"
]
},

View file

@ -7,11 +7,11 @@ Exceptions or notable authors are listed below
in reverse chronological order:
* files: *
MPLv2.0 2015-2021 (c) Casper da Costa-Luis
MPL-2.0 2015-2024 (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
* files: tqdm/_tqdm.py README.rst .gitignore
MIT 2013 (c) Noam Yorav-Raphael, original author.
[PR #96]: https://github.com/tqdm/tqdm/pull/96

View file

@ -1,4 +1,4 @@
# IMPORTANT: for compatibility with `python setup.py make [alias]`, ensure:
# IMPORTANT: for compatibility with `python -m pymake [alias]`, ensure:
# 1. Every alias is preceded by @[+]make (eg: @make alias)
# 2. A maximum of one @make alias or command per line
# see: https://github.com/tqdm/py-make/issues/1
@ -31,7 +31,7 @@
run
help:
@python setup.py make -p
@python -m pymake -p
alltests:
@+make testcoverage
@ -58,15 +58,14 @@ testsetup:
@make README.rst
@make tqdm/tqdm.1
@make tqdm/completion.sh
python setup.py check --metadata --restructuredtext --strict
python setup.py make none
@make help
testnb:
pytest tests_notebook.ipynb --nbval --nbval-current-env -W=ignore --nbval-sanitize-with=setup.cfg --cov=tqdm.notebook --cov-report=term
pytest tests_notebook.ipynb --cov=tqdm.notebook --cov-report=term -W=ignore --nbval --nbval-current-env --nbval-sanitize-with=.meta/nbval.ini
testcoverage:
@make coverclean
pytest tests_notebook.ipynb --cov=tqdm --cov-report= --nbval --nbval-current-env --nbval-sanitize-with=setup.cfg -W=ignore
pytest tests_notebook.ipynb --cov=tqdm --cov-report= -W=ignore --nbval --nbval-current-env --nbval-sanitize-with=.meta/nbval.ini
pytest -k "not perf" --cov=tqdm --cov-report=xml --cov-report=term --cov-append --cov-fail-under=80
testperf:
@ -138,9 +137,9 @@ clean:
@+python -c "import os, glob; [os.remove(i) for i in glob.glob('*.py[co]')]"
@+python -c "import os, glob; [os.remove(i) for i in glob.glob('tests/*.py[co]')]"
@+python -c "import os, glob; [os.remove(i) for i in glob.glob('benchmarks/*.py[co]')]"
@+python -c "import os, glob; [os.remove(i) for i in glob.glob('examples/*.py[co]')]"
@+python -c "import os, glob; [os.remove(i) for i in glob.glob('tqdm/*.py[co]')]"
@+python -c "import os, glob; [os.remove(i) for i in glob.glob('tqdm/contrib/*.py[co]')]"
@+python -c "import os, glob; [os.remove(i) for i in glob.glob('tqdm/examples/*.py[co]')]"
toxclean:
@+python -c "import shutil; shutil.rmtree('.tox', True)"
@ -152,12 +151,11 @@ submodules:
cd feedstock && git remote add autotick-bot git@github.com:regro-cf-autotick-bot/tqdm-feedstock
install:
python setup.py install
python -m pip install .
install_dev:
python setup.py develop --uninstall
python setup.py develop
python -m pip install -e .
install_build:
python -m pip install -r .meta/requirements-dev.txt
python -m pip install -r .meta/requirements-build.txt
install_test:
python -m pip install -r .meta/requirements-test.txt
pre-commit install
@ -165,11 +163,11 @@ install_test:
build:
@make prebuildclean
@make testsetup
python setup.py sdist bdist_wheel
# python setup.py bdist_wininst
python -m build
python -m twine check dist/*
pypi:
twine upload dist/*
python -m twine upload dist/*
buildupload:
@make build

1581
PKG-INFO

File diff suppressed because it is too large Load diff

View file

@ -255,7 +255,7 @@ This can be beautified further:
.. code:: sh
$ BYTES="$(du -sb docs/ | cut -f1)"
$ BYTES=$(du -sb docs/ | cut -f1)
$ tar -cf - docs/ \
| tqdm --bytes --total "$BYTES" --desc Processing | gzip \
| tqdm --bytes --total "$BYTES" --desc Compressed --position 1 \
@ -291,6 +291,12 @@ 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``).
* Some cloud logging consoles which don't support ``\r`` properly
(`cloudwatch <https://github.com/tqdm/tqdm/issues/966>`__,
`K8s <https://github.com/tqdm/tqdm/issues/1319>`__) may benefit from
``export TQDM_POSITION=-1``.
- Nested progress bars:
* Consoles in general: require support for moving cursors up to the
@ -327,12 +333,14 @@ of a neat one-line progress bar.
* 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``.
- Overriding defaults via environment variables:
e.g. in CI/cloud jobs, ``export TQDM_MININTERVAL=5`` to avoid log spam.
This override logic is handled by the ``tqdm.utils.envwrap`` decorator
(useful independent of ``tqdm``).
If you come across any other difficulties, browse and file |GitHub-Issues|.
Documentation
@ -349,12 +357,14 @@ Documentation
progressbar every time a value is requested.
"""
@envwrap("TQDM_") # override defaults via env vars
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):
postfix=None, unit_divisor=1000, write_bytes=False,
lock_args=None, nrows=None, colour=None, delay=0):
Parameters
~~~~~~~~~~
@ -450,9 +460,7 @@ Parameters
* 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.
Whether to write bytes. If (default: False) will write unicode.
* lock_args : tuple, optional
Passed to ``refresh`` for intermediate output
(initialisation, iterating, and updating).
@ -631,10 +639,7 @@ Returns
"""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`.
"""
"""Shortcut for `tqdm(range(*args), **tqdm_kwargs)`."""
Convenience Functions
~~~~~~~~~~~~~~~~~~~~~
@ -737,7 +742,7 @@ with the ``desc`` and ``postfix`` arguments:
sleep(0.1)
with tqdm(total=10, bar_format="{postfix[0]} {postfix[1][value]:>8.2g}",
postfix=["Batch", dict(value=0)]) as t:
postfix=["Batch", {"value": 0}]) as t:
for i in range(10):
sleep(0.1)
t.postfix[1]["value"] = i / 2
@ -761,7 +766,7 @@ Additional ``bar_format`` parameters may also be defined by overriding
"""Provides a `total_time` format parameter"""
@property
def format_dict(self):
d = super(TqdmExtraFormat, self).format_dict
d = super().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
@ -825,7 +830,7 @@ first.
def progresser(n):
interval = 0.001 / (n + 2)
total = 5000
text = "#{}, est. {:<04.2}s".format(n, interval * total)
text = f"#{n}, est. {interval * total:<04.2}s"
for _ in trange(total, desc=text, position=n):
sleep(interval)
@ -848,7 +853,7 @@ Note that in Python 3, ``tqdm.write`` is thread-safe:
def progresser(n):
interval = 0.001 / (n + 2)
total = 5000
text = "#{}, est. {:<04.2}s".format(n, interval * total)
text = f"#{n}, est. {interval * total:<04.2}s"
for _ in trange(total, desc=text):
sleep(interval)
if n == 6:
@ -977,7 +982,7 @@ custom callback take advantage of this, simply use the return value of
class TqdmExt(std_tqdm):
def update(self, n=1):
displayed = super(TqdmExt, self).update(n)
displayed = super().update(n)
if displayed:
external_callback(**self.format_dict)
return displayed
@ -1405,16 +1410,17 @@ 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%
Casper da Costa-Luis `casperdcl <https://github.com/casperdcl>`__ ~80% primary maintainer |Gift-Casper|
Stephen Larroque `lrq3000 <https://github.com/lrq3000>`__ ~9% team member
Martin Zugnoni `martinzugnoni <https://github.com/martinzugnoni>`__ ~3%
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%
Helio Machado `0x2b3bfa0 <https://github.com/0x2b3bfa0>`__ ~1%
Kyle Altendorf `altendky <https://github.com/altendky>`__ <1%
Noam Yorav-Raphael `noamraph <https://github.com/noamraph>`__ <1% original author
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
==================== ======================================================== ==== ================================
@ -1434,16 +1440,16 @@ 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
.. |Logo| image:: https://tqdm.github.io/img/logo.gif
.. |Screenshot| image:: https://tqdm.github.io/img/tqdm.gif
.. |Video| image:: https://tqdm.github.io/img/video.jpg
:target: https://tqdm.github.io/video
.. |Slides| image:: https://img.tqdm.ml/slides.jpg
.. |Slides| image:: https://tqdm.github.io/img/slides.jpg
:target: https://tqdm.github.io/PyData2019/slides.html
.. |Merch| image:: https://img.tqdm.ml/merch.jpg
.. |Merch| image:: https://tqdm.github.io/img/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
.. |Build-Status| image:: https://img.shields.io/github/actions/workflow/status/tqdm/tqdm/test.yml?branch=master&label=tqdm&logo=GitHub
:target: https://github.com/tqdm/tqdm/actions/workflows/test.yml
.. |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
@ -1496,8 +1502,8 @@ Citation information: |DOI|
: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
.. |Screenshot-Jupyter1| image:: https://tqdm.github.io/img/jupyter-1.gif
.. |Screenshot-Jupyter2| image:: https://tqdm.github.io/img/jupyter-2.gif
.. |Screenshot-Jupyter3| image:: https://tqdm.github.io/img/jupyter-3.gif
.. |README-Hits| image:: https://cgi.cdcl.ml/hits?q=tqdm&style=social&r=https://github.com/tqdm/tqdm&l=https://tqdm.github.io/img/favicon.png&f=https://tqdm.github.io/img/logo.gif
:target: https://cgi.cdcl.ml/hits?q=tqdm&a=plot&r=https://github.com/tqdm/tqdm&l=https://tqdm.github.io/img/favicon.png&f=https://tqdm.github.io/img/logo.gif&style=social

View file

@ -5,7 +5,7 @@ channels:
- defaults
dependencies:
# base
- python=3
- python >=3.7
- pip
- ipykernel
- ipywidgets
@ -20,27 +20,28 @@ dependencies:
- pytest
- pytest-cov
- pytest-timeout
- pytest-asyncio # [py>=3.7]
- nbval
- pytest-asyncio>=0.24
- coverage
# extras
- dask # dask
- matplotlib # gui
- numpy # pandas, keras, contrib.tenumerate
- pandas
- pyarrow # pandas
- tensorflow # keras
- slack-sdk # contrib.slack
- requests # contrib.telegram
- rich # rich
- argopt # `cd wiki && pymake`
- twine # `pymake pypi`
- wheel # `setup.py bdist_wheel`
- twine # `pymake check pypi`
- python-build # `python -m build`
# `cd docs && pymake`
- mkdocs-material
- pydoc-markdown
- pygments
- pymdown-extensions
- pip:
- py-make >=0.1.0 # `setup.py make/pymake`
- git+https://github.com/casperdcl/nbval.git@master#egg=nbval # tests (native)
- py-make >=0.1.0 # `make/pymake`
- mkdocs-minify-plugin # `cd docs && pymake`
- git+https://github.com/tqdm/jsmin@python3-only#egg=jsmin # `cd docs && pymake`
- git+https://github.com/tqdm/jsmin@fix-pip#egg=jsmin # `cd docs && pymake`
- pydoc-markdown >=4.6 # `cd docs && pymake`

View file

@ -18,8 +18,6 @@ Options:
NOTSET
-d, --debug-trace Print lots of debugging information (-D NOTSET)
"""
from __future__ import print_function
import io
import logging
import os

View file

@ -1,6 +1,4 @@
"""
Asynchronous examples using `asyncio`, `async` and `await` on `python>=3.7`.
"""
"""Asynchronous examples using `asyncio`, `async` and `await`."""
import asyncio
from tqdm.asyncio import tqdm, trange

View file

@ -126,7 +126,7 @@
@misc{hits,
year="2019",
title="{tqdm} hits",
url="https://caspersci.uk.to/cgi-bin/hits.cgi?q=tqdm&a=plot",
url="https://cgi.cdcl.ml/hits?q=tqdm&a=plot",
author="Casper O. {da Costa-Luis}"
}
@book{miller,

View file

@ -1,6 +1,3 @@
from __future__ import print_function
import sys
from concurrent.futures import ThreadPoolExecutor
from functools import partial
from multiprocessing import Pool, RLock, freeze_support
@ -12,21 +9,19 @@ from tqdm.auto import tqdm, trange
from tqdm.contrib.concurrent import process_map, thread_map
NUM_SUBITERS = 9
PY2 = sys.version_info[:1] <= (2,)
def progresser(n, auto_position=True, write_safe=False, blocking=True, progress=False):
interval = random() * 0.002 / (NUM_SUBITERS - n + 2) # nosec
total = 5000
text = "#{0}, est. {1:<04.2}s".format(n, interval * total)
text = f"#{n}, est. {interval * total:<04.2g}s"
for _ in trange(total, desc=text, disable=not progress,
lock_args=None if blocking else (False,),
position=None if auto_position else n):
sleep(interval)
# NB: may not clear instances with higher `position` upon completion
# since this worker may not know about other bars #796
if write_safe:
# we think we know about other bars (currently only py3 threading)
if write_safe: # we think we know about other bars
if n == 6:
tqdm.write("n == 6 completed")
return n + 1
@ -37,7 +32,7 @@ if __name__ == '__main__':
L = list(range(NUM_SUBITERS))[::-1]
print("Simple thread mapping")
thread_map(partial(progresser, write_safe=not PY2), L, max_workers=4)
thread_map(partial(progresser, write_safe=True), L, max_workers=4)
print("Simple process mapping")
process_map(partial(progresser), L, max_workers=4)
@ -54,8 +49,5 @@ if __name__ == '__main__':
print("Multi-threading")
tqdm.set_lock(TRLock())
pool_args = {}
if not PY2:
pool_args.update(initializer=tqdm.set_lock, initargs=(tqdm.get_lock(),))
with ThreadPoolExecutor(**pool_args) as p:
p.map(partial(progresser, progress=True, write_safe=not PY2, blocking=False), L)
with ThreadPoolExecutor(initializer=tqdm.set_lock, initargs=(tqdm.get_lock(),)) as p:
p.map(partial(progresser, progress=True, write_safe=True, blocking=False), L)

View file

@ -10,8 +10,6 @@ any input string to `tqdm.write()`, and supply the arguments
A reusable canonical example is given below:
"""
from __future__ import print_function
import contextlib
import sys
from time import sleep

View file

@ -2,7 +2,7 @@
# Simple tqdm examples and profiling
# Benchmark
for i in _range(int(1e8)):
for i in range(int(1e8)):
pass
# Basic demo
@ -33,7 +33,7 @@ try:
except ImportError:
pass
else:
for i in ProgressBar()(_range(int(1e8))):
for i in ProgressBar()(range(int(1e8))):
pass
# Dynamic miniters benchmark
@ -61,5 +61,4 @@ for _ in trange(16, leave=True):
stmts = filter(None, re.split(r'\n\s*#.*?\n', __doc__))
for s in stmts:
print(s.replace('import tqdm\n', ''))
print(timeit(stmt='try:\n\t_range = xrange'
'\nexcept:\n\t_range = range\n' + s, number=1), 'seconds')
print(timeit(stmt=s, number=1), 'seconds')

View file

@ -20,11 +20,8 @@ Options:
The local file path in which to save the url [default: /dev/null].
"""
try:
from urllib import request as urllib
except ImportError: # py2
import urllib
from os import devnull
from urllib import request as urllib
from docopt import docopt

View file

@ -5,3 +5,135 @@ build-backend = "setuptools.build_meta"
[tool.setuptools_scm]
write_to = "tqdm/_dist_ver.py"
write_to_template = "__version__ = '{version}'\n"
[tool.setuptools.packages.find]
exclude = ["benchmarks", "examples", "tests", "wiki", "docs", "feedstock"]
[project.urls]
homepage = "https://tqdm.github.io"
repository = "https://github.com/tqdm/tqdm"
changelog = "https://tqdm.github.io/releases"
wiki = "https://github.com/tqdm/tqdm/wiki"
[project]
name = "tqdm"
dynamic = ["version"]
maintainers = [{name = "tqdm developers", email = "devs@tqdm.ml"}]
description = "Fast, Extensible Progress Meter"
readme = "README.rst"
requires-python = ">=3.7"
keywords = ["progressbar", "progressmeter", "progress", "bar", "meter", "rate", "eta", "console", "terminal", "time"]
license = {text = "MPL-2.0 AND MIT"}
# Trove classifiers (https://pypi.org/pypi?%3Aaction=list_classifiers)
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Environment :: MacOS X",
"Environment :: Other Environment",
"Environment :: Win32 (MS Windows)",
"Environment :: X11 Applications",
"Framework :: IPython",
"Framework :: Jupyter",
"Intended Audience :: Developers",
"Intended Audience :: Education",
"Intended Audience :: End Users/Desktop",
"Intended Audience :: Other Audience",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: MIT License",
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
"Operating System :: MacOS",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft",
"Operating System :: Microsoft :: MS-DOS",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX",
"Operating System :: POSIX :: BSD",
"Operating System :: POSIX :: BSD :: FreeBSD",
"Operating System :: POSIX :: Linux",
"Operating System :: POSIX :: SunOS/Solaris",
"Operating System :: Unix",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: Implementation",
"Programming Language :: Python :: Implementation :: IronPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Programming Language :: Unix Shell",
"Topic :: Desktop Environment",
"Topic :: Education :: Computer Aided Instruction (CAI)",
"Topic :: Education :: Testing",
"Topic :: Office/Business",
"Topic :: Other/Nonlisted Topic",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Pre-processors",
"Topic :: Software Development :: User Interfaces",
"Topic :: System :: Installation/Setup",
"Topic :: System :: Logging",
"Topic :: System :: Monitoring",
"Topic :: System :: Shells",
"Topic :: Terminals",
"Topic :: Utilities"]
dependencies = ['colorama; platform_system == "Windows"']
[project.optional-dependencies]
dev = ["pytest>=6", "pytest-cov", "pytest-timeout", "pytest-asyncio>=0.24", "nbval"]
discord = ["requests"]
slack = ["slack-sdk"]
telegram = ["requests"]
notebook = ["ipywidgets>=6"]
[project.scripts]
tqdm = "tqdm.cli:main"
[tool.flake8]
max_line_length = 99
exclude = [".git", "__pycache__", "build", "dist", ".eggs", ".asv", ".tox", ".ipynb_checkpoints"]
[tool.yapf]
spaces_before_comment = [15, 20]
arithmetic_precedence_indication = true
allow_split_before_dict_value = false
coalesce_brackets = true
column_limit = 99
each_dict_entry_on_separate_line = false
space_between_ending_comma_and_closing_bracket = false
split_before_named_assigns = false
split_before_closing_bracket = false
blank_line_before_nested_class_or_def = false
[tool.isort]
line_length = 99
multi_line_output = 4
known_first_party = ["tqdm", "tests"]
[tool.pytest.ini_options]
minversion = "6.0"
timeout = 30
log_level = "INFO"
markers = ["asyncio", "slow"]
python_files = ["tests_*.py", "tests_*.ipynb"]
testpaths = ["tests"]
addopts = "-v --tb=short -rxs -W=error --durations=0 --durations-min=0.1 --asyncio-mode=strict"
asyncio_default_fixture_loop_scope = "function"
[tool.coverage.run]
branch = true
include = ["tqdm/*"]
omit = [
"tqdm/contrib/bells.py",
"tqdm/contrib/slack.py",
"tqdm/contrib/discord.py",
"tqdm/contrib/telegram.py",
"tqdm/contrib/utils_worker.py"]
relative_files = true
disable_warnings = ["include-ignored"]
[tool.coverage.report]
show_missing = true

159
setup.cfg
View file

@ -1,159 +0,0 @@
[metadata]
name = tqdm
url = https://tqdm.github.io
project_urls =
Changelog=https://tqdm.github.io/releases
Source=https://github.com/tqdm/tqdm
Wiki=https://github.com/tqdm/tqdm/wiki
maintainer = tqdm developers
maintainer_email = python.tqdm@gmail.com
license = MPLv2.0, MIT Licences
license_file = LICENCE
description = Fast, Extensible Progress Meter
long_description = file: README.rst
long_description_content_type = text/x-rst
keywords = progressbar, progressmeter, progress, bar, meter, rate, eta, console, terminal, time
platforms = any
provides = tqdm
classifiers =
Development Status :: 5 - Production/Stable
Environment :: Console
Environment :: MacOS X
Environment :: Other Environment
Environment :: Win32 (MS Windows)
Environment :: X11 Applications
Framework :: IPython
Framework :: Jupyter
Intended Audience :: Developers
Intended Audience :: Education
Intended Audience :: End Users/Desktop
Intended Audience :: Other Audience
Intended Audience :: System Administrators
License :: OSI Approved :: MIT License
License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
Operating System :: MacOS
Operating System :: MacOS :: MacOS X
Operating System :: Microsoft
Operating System :: Microsoft :: MS-DOS
Operating System :: Microsoft :: Windows
Operating System :: POSIX
Operating System :: POSIX :: BSD
Operating System :: POSIX :: BSD :: FreeBSD
Operating System :: POSIX :: Linux
Operating System :: POSIX :: SunOS/Solaris
Operating System :: Unix
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: Implementation
Programming Language :: Python :: Implementation :: IronPython
Programming Language :: Python :: Implementation :: PyPy
Programming Language :: Unix Shell
Topic :: Desktop Environment
Topic :: Education :: Computer Aided Instruction (CAI)
Topic :: Education :: Testing
Topic :: Office/Business
Topic :: Other/Nonlisted Topic
Topic :: Software Development :: Build Tools
Topic :: Software Development :: Libraries
Topic :: Software Development :: Libraries :: Python Modules
Topic :: Software Development :: Pre-processors
Topic :: Software Development :: User Interfaces
Topic :: System :: Installation/Setup
Topic :: System :: Logging
Topic :: System :: Monitoring
Topic :: System :: Shells
Topic :: Terminals
Topic :: Utilities
[options]
setup_requires = setuptools>=42; setuptools_scm[toml]>=3.4
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
install_requires =
colorama; platform_system == 'Windows'
importlib_resources; python_version < "3.7"
tests_require = tox
include_package_data = True
packages = find:
[options.extras_require]
dev = py-make>=0.1.0; twine; wheel
slack = slack-sdk
telegram = requests
notebook = ipywidgets>=6
[options.entry_points]
console_scripts =
tqdm=tqdm.cli:main
[options.packages.find]
exclude = benchmarks, tests
[bdist_wheel]
universal = 1
[flake8]
max_line_length = 99
exclude = .asv,.eggs,.tox,.ipynb_checkpoints,build,dist,.git,__pycache__
[pydocstyle]
add_ignore = D400,D415
[yapf]
coalesce_brackets = True
column_limit = 99
each_dict_entry_on_separate_line = False
i18n_comment = NOQA
space_between_ending_comma_and_closing_bracket = False
split_before_named_assigns = False
split_before_closing_bracket = False
[isort]
line_length = 99
multi_line_output = 4
known_first_party = tqdm,tests
[tool:pytest]
timeout = 30
log_level = INFO
markers =
asyncio
slow
python_files = tests_*.py tests_*.ipynb
testpaths = tests
addopts = -v --tb=short -rxs -W=error --durations=0 --durations-min=0.1 --asyncio-mode=strict
[regex1]
regex = (?<= )[\s\d.]+(it/s|s/it)
replace = ??.??it/s
[regex2]
regex = 00:0[01]<00:0[01]
replace = 00:00<00:00
[coverage:run]
branch = True
include = tqdm/*
omit =
tqdm/contrib/bells.py
tqdm/contrib/slack.py
tqdm/contrib/discord.py
tqdm/contrib/telegram.py
tqdm/contrib/utils_worker.py
relative_files = True
disable_warnings = include-ignored
[coverage:report]
show_missing = True
[egg_info]
tag_build =
tag_date = 0

View file

@ -1,16 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from os import path
from setuptools import setup
src_dir = path.abspath(path.dirname(__file__))
if sys.argv[1].lower().strip() == 'make': # exec Makefile commands
import pymake
fpath = path.join(src_dir, 'Makefile')
pymake.main(['-f', fpath] + sys.argv[2:])
# Stop to avoid setup.py raising non-standard command error
sys.exit(0)
setup(use_scm_version=True)

View file

@ -18,24 +18,10 @@ def pretest_posttest():
n = len(tqdm._instances)
if n:
tqdm._instances.clear()
raise EnvironmentError(
"{0} `tqdm` instances still in existence PRE-test".format(n))
raise EnvironmentError(f"{n} `tqdm` instances still in existence PRE-test")
yield
if getattr(tqdm, "_instances", False):
n = len(tqdm._instances)
if n:
tqdm._instances.clear()
raise EnvironmentError(
"{0} `tqdm` instances still in existence POST-test".format(n))
if sys.version_info[0] > 2:
@fixture
def capsysbin(capsysbinary):
"""alias for capsysbinary (py3)"""
return capsysbinary
else:
@fixture
def capsysbin(capsys):
"""alias for capsys (py2)"""
return capsys
raise EnvironmentError(f"{n} `tqdm` instances still in existence POST-test")

View file

@ -1,128 +0,0 @@
import asyncio
from functools import partial
from sys import platform
from time import time
from tqdm.asyncio import tarange, tqdm_asyncio
from .tests_tqdm import StringIO, closing, mark
tqdm = partial(tqdm_asyncio, miniters=0, mininterval=0)
trange = partial(tarange, miniters=0, mininterval=0)
as_completed = partial(tqdm_asyncio.as_completed, miniters=0, mininterval=0)
gather = partial(tqdm_asyncio.gather, miniters=0, mininterval=0)
def count(start=0, step=1):
i = start
while True:
new_start = yield i
if new_start is None:
i += step
else:
i = new_start
async def acount(*args, **kwargs):
for i in count(*args, **kwargs):
yield i
@mark.asyncio
async def test_break():
"""Test asyncio break"""
pbar = tqdm(count())
async for _ in pbar:
break
pbar.close()
@mark.asyncio
async def test_generators(capsys):
"""Test asyncio generators"""
with tqdm(count(), desc="counter") as pbar:
async for i in pbar:
if i >= 8:
break
_, err = capsys.readouterr()
assert '9it' in err
with tqdm(acount(), desc="async_counter") as pbar:
async for i in pbar:
if i >= 8:
break
_, err = capsys.readouterr()
assert '9it' in err
@mark.asyncio
async def test_range():
"""Test asyncio range"""
with closing(StringIO()) as our_file:
async for _ in tqdm(range(9), desc="range", file=our_file):
pass
assert '9/9' in our_file.getvalue()
our_file.seek(0)
our_file.truncate()
async for _ in trange(9, desc="trange", file=our_file):
pass
assert '9/9' in our_file.getvalue()
@mark.asyncio
async def test_nested():
"""Test asyncio nested"""
with closing(StringIO()) as our_file:
async for _ in tqdm(trange(9, desc="inner", file=our_file),
desc="outer", file=our_file):
pass
assert 'inner: 100%' in our_file.getvalue()
assert 'outer: 100%' in our_file.getvalue()
@mark.asyncio
async def test_coroutines():
"""Test asyncio coroutine.send"""
with closing(StringIO()) as our_file:
with tqdm(count(), file=our_file) as pbar:
async for i in pbar:
if i == 9:
pbar.send(-10)
elif i < 0:
assert i == -9
break
assert '10it' in our_file.getvalue()
@mark.slow
@mark.asyncio
@mark.parametrize("tol", [0.2 if platform.startswith("darwin") else 0.1])
async def test_as_completed(capsys, tol):
"""Test asyncio as_completed"""
for retry in range(3):
t = time()
skew = time() - t
for i in as_completed([asyncio.sleep(0.01 * i) for i in range(30, 0, -1)]):
await i
t = time() - t - 2 * skew
try:
assert 0.3 * (1 - tol) < t < 0.3 * (1 + tol), t
_, err = capsys.readouterr()
assert '30/30' in err
except AssertionError:
if retry == 2:
raise
async def double(i):
return i * 2
@mark.asyncio
async def test_gather(capsys):
"""Test asyncio gather"""
res = await gather(*map(double, range(30)))
_, err = capsys.readouterr()
assert '30/30' in err
assert res == list(range(0, 30 * 2, 2))

View file

@ -1,11 +1,133 @@
"""Tests `tqdm.asyncio` on `python>=3.7`."""
import sys
"""Tests `tqdm.asyncio`."""
import asyncio
from functools import partial
from sys import platform
from time import time
if sys.version_info[:2] > (3, 6):
from .py37_asyncio import * # NOQA, pylint: disable=wildcard-import
from tqdm.asyncio import tarange, tqdm_asyncio
from .tests_tqdm import StringIO, closing, mark
tqdm = partial(tqdm_asyncio, miniters=0, mininterval=0)
trange = partial(tarange, miniters=0, mininterval=0)
as_completed = partial(tqdm_asyncio.as_completed, miniters=0, mininterval=0)
gather = partial(tqdm_asyncio.gather, miniters=0, mininterval=0)
def count(start=0, step=1):
i = start
while True:
new_start = yield i
if new_start is None:
i += step
else:
from .tests_tqdm import skip
i = new_start
async def acount(*args, **kwargs):
for i in count(*args, **kwargs):
yield i
@mark.asyncio
async def test_break():
"""Test asyncio break"""
pbar = tqdm(count())
async for _ in pbar:
break
pbar.close()
@mark.asyncio
async def test_generators(capsys):
"""Test asyncio generators"""
with tqdm(count(), desc="counter") as pbar:
async for i in pbar:
if i >= 8:
break
_, err = capsys.readouterr()
assert '9it' in err
acounter = acount()
try:
skip("async not supported", allow_module_level=True)
except TypeError:
with tqdm(acounter, desc="async_counter") as pbar:
async for i in pbar:
if i >= 8:
break
finally:
await acounter.aclose()
_, err = capsys.readouterr()
assert '9it' in err
@mark.asyncio
async def test_range():
"""Test asyncio range"""
with closing(StringIO()) as our_file:
async for _ in tqdm(range(9), desc="range", file=our_file):
pass
assert '9/9' in our_file.getvalue()
our_file.seek(0)
our_file.truncate()
async for _ in trange(9, desc="trange", file=our_file):
pass
assert '9/9' in our_file.getvalue()
@mark.asyncio
async def test_nested():
"""Test asyncio nested"""
with closing(StringIO()) as our_file:
async for _ in tqdm(trange(9, desc="inner", file=our_file),
desc="outer", file=our_file):
pass
assert 'inner: 100%' in our_file.getvalue()
assert 'outer: 100%' in our_file.getvalue()
@mark.asyncio
async def test_coroutines():
"""Test asyncio coroutine.send"""
with closing(StringIO()) as our_file:
with tqdm(count(), file=our_file) as pbar:
async for i in pbar:
if i == 9:
pbar.send(-10)
elif i < 0:
assert i == -9
break
assert '10it' in our_file.getvalue()
@mark.slow
@mark.asyncio
@mark.parametrize("tol", [0.2 if platform.startswith("darwin") else 0.1])
async def test_as_completed(capsys, tol):
"""Test asyncio as_completed"""
for retry in range(3):
t = time()
skew = time() - t
for i in as_completed([asyncio.sleep(0.01 * i) for i in range(30, 0, -1)]):
await i
t = time() - t - 2 * skew
try:
assert 0.3 * (1 - tol) < t < 0.3 * (1 + tol), t
_, err = capsys.readouterr()
assert '30/30' in err
except AssertionError:
if retry == 2:
raise
async def double(i):
return i * 2
@mark.asyncio
async def test_gather(capsys):
"""Test asyncio gather"""
res = await gather(*map(double, range(30)))
_, err = capsys.readouterr()
assert '30/30' in err
assert res == list(range(0, 30 * 2, 2))

View file

@ -1,8 +1,6 @@
"""
Tests for `tqdm.contrib`.
"""
import sys
import pytest
from tqdm import tqdm
@ -47,9 +45,6 @@ def test_zip(tqdm_kwargs):
with closing(StringIO()) as our_file:
a = range(9)
b = [i + 1 for i in a]
if sys.version_info[:1] < (3,):
assert tzip(a, b, file=our_file, **tqdm_kwargs) == zip(a, b)
else:
gen = tzip(a, b, file=our_file, **tqdm_kwargs)
assert gen != list(zip(a, b))
assert list(gen) == list(zip(a, b))
@ -61,11 +56,6 @@ def test_map(tqdm_kwargs):
with closing(StringIO()) as our_file:
a = range(9)
b = [i + 1 for i in a]
if sys.version_info[:1] < (3,):
assert tmap(lambda x: x + 1, a, file=our_file, **tqdm_kwargs) == map(
incr, a
)
else:
gen = tmap(lambda x: x + 1, a, file=our_file, **tqdm_kwargs)
assert gen != b
assert list(gen) == b

View file

@ -1,7 +1,5 @@
# pylint: disable=missing-module-docstring, missing-class-docstring
# pylint: disable=missing-function-docstring, no-self-use
from __future__ import absolute_import
import logging
import logging.handlers
import sys

View file

@ -1,5 +1,3 @@
from __future__ import division
from time import sleep
from .tests_tqdm import importorskip, mark

View file

@ -1,5 +1,3 @@
from __future__ import division
from .tests_tqdm import importorskip, mark
pytestmark = mark.slow
@ -41,8 +39,8 @@ def test_keras(capsys):
verbose=0)])
_, res = capsys.readouterr()
assert "training: " in res
assert "{epochs}/{epochs}".format(epochs=epochs) in res
assert "{batches}/{batches}".format(batches=batches) not in res
assert f"{epochs}/{epochs}" in res
assert f"{batches}/{batches}" not in res
# full (epoch and batch) progress
model.fit(
@ -60,8 +58,8 @@ def test_keras(capsys):
verbose=2)])
_, res = capsys.readouterr()
assert "training: " in res
assert "{epochs}/{epochs}".format(epochs=epochs) in res
assert "{batches}/{batches}".format(batches=batches) in res
assert f"{epochs}/{epochs}" in res
assert f"{batches}/{batches}" in res
# auto-detect epochs and batches
model.fit(
@ -73,8 +71,8 @@ def test_keras(capsys):
callbacks=[TqdmCallback(desc="training", verbose=2)])
_, res = capsys.readouterr()
assert "training: " in res
assert "{epochs}/{epochs}".format(epochs=epochs) in res
assert "{batches}/{batches}".format(batches=batches) in res
assert f"{epochs}/{epochs}" in res
assert f"{batches}/{batches}" in res
# continue training (start from epoch != 0)
initial_epoch = 3
@ -89,5 +87,5 @@ def test_keras(capsys):
miniters=1, mininterval=0, maxinterval=0)])
_, res = capsys.readouterr()
assert "training: " in res
assert "{epochs}/{epochs}".format(epochs=initial_epoch - 1) not in res
assert "{epochs}/{epochs}".format(epochs=epochs) in res
assert f"{initial_epoch - 1}/{initial_epoch - 1}" not in res
assert f"{epochs}/{epochs}" in res

View file

@ -8,17 +8,17 @@ from os import linesep
from tqdm.cli import TqdmKeyError, TqdmTypeError, main
from tqdm.utils import IS_WIN
from .tests_tqdm import BytesIO, _range, closing, mark, raises
from .tests_tqdm import BytesIO, closing, mark, raises
def restore_sys(func):
"""Decorates `func(capsysbin)` to save & restore `sys.(stdin|argv)`."""
"""Decorates `func(capsysbinary)` to save & restore `sys.(stdin|argv)`."""
@wraps(func)
def inner(capsysbin):
"""function requiring capsysbin which may alter `sys.(stdin|argv)`"""
def inner(capsysbinary):
"""function requiring capsysbinary which may alter `sys.(stdin|argv)`"""
_SYS = sys.stdin, sys.argv
try:
res = func(capsysbin)
res = func(capsysbinary)
finally:
sys.stdin, sys.argv = _SYS
return res
@ -58,7 +58,7 @@ def test_main_import():
N = 123
_SYS = sys.stdin, sys.argv
# test direct import
sys.stdin = [str(i).encode() for i in _range(N)]
sys.stdin = [str(i).encode() for i in range(N)]
sys.argv = ['', '--desc', 'Test CLI import',
'--ascii', 'True', '--unit_scale', 'True']
try:
@ -68,19 +68,19 @@ def test_main_import():
@restore_sys
def test_main_bytes(capsysbin):
def test_main_bytes(capsysbinary):
"""Test CLI --bytes"""
N = 123
# test --delim
IN_DATA = '\0'.join(map(str, _range(N))).encode()
IN_DATA = '\0'.join(map(str, range(N))).encode()
with closing(BytesIO()) as sys.stdin:
sys.stdin.write(IN_DATA)
# sys.stdin.write(b'\xff') # TODO
sys.stdin.seek(0)
main(sys.stderr, ['--desc', 'Test CLI delim', '--ascii', 'True',
'--delim', r'\0', '--buf_size', '64'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert out == IN_DATA
assert str(N) + "it" in err.decode("U8")
@ -90,27 +90,26 @@ def test_main_bytes(capsysbin):
sys.stdin.write(IN_DATA)
sys.stdin.seek(0)
main(sys.stderr, ['--ascii', '--bytes=True', '--unit_scale', 'False'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert out == IN_DATA
assert str(len(IN_DATA)) + "B" in err.decode("U8")
@mark.skipif(sys.version_info[0] == 2, reason="no caplog on py2")
def test_main_log(capsysbin, caplog):
def test_main_log(capsysbinary, caplog):
"""Test CLI --log"""
_SYS = sys.stdin, sys.argv
N = 123
sys.stdin = [(str(i) + '\n').encode() for i in _range(N)]
sys.stdin = [(str(i) + '\n').encode() for i in range(N)]
IN_DATA = b''.join(sys.stdin)
try:
with caplog.at_level(logging.INFO):
main(sys.stderr, ['--log', 'INFO'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert norm(out) == IN_DATA and b"123/123" in err
assert not caplog.record_tuples
with caplog.at_level(logging.DEBUG):
main(sys.stderr, ['--log', 'DEBUG'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert norm(out) == IN_DATA and b"123/123" in err
assert caplog.record_tuples
finally:
@ -118,39 +117,39 @@ def test_main_log(capsysbin, caplog):
@restore_sys
def test_main(capsysbin):
def test_main(capsysbinary):
"""Test misc CLI options"""
N = 123
sys.stdin = [(str(i) + '\n').encode() for i in _range(N)]
sys.stdin = [(str(i) + '\n').encode() for i in range(N)]
IN_DATA = b''.join(sys.stdin)
# test --tee
main(sys.stderr, ['--mininterval', '0', '--miniters', '1'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert norm(out) == IN_DATA and b"123/123" in err
assert N <= len(err.split(b"\r")) < N + 5
len_err = len(err)
main(sys.stderr, ['--tee', '--mininterval', '0', '--miniters', '1'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert norm(out) == IN_DATA and b"123/123" in err
# spaces to clear intermediate lines could increase length
assert len_err + len(norm(out)) <= len(err)
# test --null
main(sys.stderr, ['--null'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert not out and b"123/123" in err
# test integer --update
main(sys.stderr, ['--update'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert norm(out) == IN_DATA
assert (str(N // 2 * N) + "it").encode() in err, "expected arithmetic sum formula"
# test integer --update_to
main(sys.stderr, ['--update-to'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert norm(out) == IN_DATA
assert (str(N - 1) + "it").encode() in err
assert (str(N) + "it").encode() not in err
@ -161,23 +160,23 @@ def test_main(capsysbin):
# test integer --update --delim
sys.stdin.seek(0)
main(sys.stderr, ['--update', '--delim', 'D'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert out == IN_DATA.replace(b'\n', b'D')
assert (str(N // 2 * N) + "it").encode() in err, "expected arithmetic sum"
# test integer --update_to --delim
sys.stdin.seek(0)
main(sys.stderr, ['--update-to', '--delim', 'D'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert out == IN_DATA.replace(b'\n', b'D')
assert (str(N - 1) + "it").encode() in err
assert (str(N) + "it").encode() not in err
# test float --update_to
sys.stdin = [(str(i / 2.0) + '\n').encode() for i in _range(N)]
sys.stdin = [(str(i / 2.0) + '\n').encode() for i in range(N)]
IN_DATA = b''.join(sys.stdin)
main(sys.stderr, ['--update-to'])
out, err = capsysbin.readouterr()
out, err = capsysbinary.readouterr()
assert norm(out) == IN_DATA
assert (str((N - 1) / 2.0) + "it").encode() in err
assert (str(N / 2.0) + "it").encode() not in err
@ -213,30 +212,30 @@ def test_comppath(tmp_path):
@restore_sys
def test_exceptions(capsysbin):
def test_exceptions(capsysbinary):
"""Test CLI Exceptions"""
N = 123
sys.stdin = [str(i) + '\n' for i in _range(N)]
sys.stdin = [str(i) + '\n' for i in range(N)]
IN_DATA = ''.join(sys.stdin).encode()
with raises(TqdmKeyError, match="bad_arg_u_ment"):
main(sys.stderr, argv=['-ascii', '-unit_scale', '--bad_arg_u_ment', 'foo'])
out, _ = capsysbin.readouterr()
out, _ = capsysbinary.readouterr()
assert norm(out) == IN_DATA
with raises(TqdmTypeError, match="invalid_bool_value"):
main(sys.stderr, argv=['-ascii', '-unit_scale', 'invalid_bool_value'])
out, _ = capsysbin.readouterr()
out, _ = capsysbinary.readouterr()
assert norm(out) == IN_DATA
with raises(TqdmTypeError, match="invalid_int_value"):
main(sys.stderr, argv=['-ascii', '--total', 'invalid_int_value'])
out, _ = capsysbin.readouterr()
out, _ = capsysbinary.readouterr()
assert norm(out) == IN_DATA
with raises(TqdmKeyError, match="Can only have one of --"):
main(sys.stderr, argv=['--update', '--update_to'])
out, _ = capsysbin.readouterr()
out, _ = capsysbinary.readouterr()
assert norm(out) == IN_DATA
# test SystemExits

View file

@ -4,6 +4,7 @@ from .tests_tqdm import StringIO, closing, importorskip, mark, skip
pytestmark = mark.slow
np = importorskip('numpy')
random = importorskip('numpy.random')
rand = random.rand
randint = random.randint
@ -39,8 +40,8 @@ def test_pandas_rolling_expanding():
our_file.seek(0)
if our_file.getvalue().count(exres) < 2:
our_file.seek(0)
raise AssertionError("\nExpected:\n{0}\nIn:\n{1}\n".format(
exres + " at least twice.", our_file.read()))
raise AssertionError(
f"\nExpected:\n{exres} at least twice.\nIn:\n{our_file.read()}\n")
def test_pandas_series():
@ -62,10 +63,11 @@ def test_pandas_series():
our_file.seek(0)
if our_file.getvalue().count(exres) < 2:
our_file.seek(0)
raise AssertionError("\nExpected:\n{0}\nIn:\n{1}\n".format(
exres + " at least twice.", our_file.read()))
raise AssertionError(
f"\nExpected:\n{exres} at least twice.\nIn:\n{our_file.read()}\n")
@mark.filterwarnings("ignore:DataFrame.applymap has been deprecated:FutureWarning")
def test_pandas_data_frame():
"""Test pandas.DataFrame.progress_apply and .progress_applymap"""
with closing(StringIO()) as our_file:
@ -80,6 +82,12 @@ def test_pandas_data_frame():
res2 = df.applymap(task_func)
assert res1.equals(res2)
# map
if hasattr(df, 'map'): # pandas>=2.1.0
res1 = df.progress_map(task_func)
res2 = df.map(task_func)
assert res1.equals(res2)
# apply unhashable
res1 = []
df.progress_apply(res1.extend)
@ -94,8 +102,8 @@ def test_pandas_data_frame():
our_file.seek(0)
if our_file.read().count('100%') < 3:
our_file.seek(0)
raise AssertionError("\nExpected:\n{0}\nIn:\n{1}\n".format(
'100% at least three times', our_file.read()))
raise AssertionError(
f"\nExpected:\n100% at least three times\nIn:\n{our_file.read()}\n")
# apply_map, apply axis=0, apply axis=1
expects = ['20000/20000', '200/200', '100/100']
@ -103,10 +111,12 @@ def test_pandas_data_frame():
our_file.seek(0)
if our_file.getvalue().count(exres) < 1:
our_file.seek(0)
raise AssertionError("\nExpected:\n{0}\nIn:\n {1}\n".format(
exres + " at least once.", our_file.read()))
raise AssertionError(
f"\nExpected:\n{exres} at least once.\nIn:\n{our_file.read()}\n")
@mark.filterwarnings(
"ignore:DataFrameGroupBy.apply operated on the grouping columns:DeprecationWarning")
def test_pandas_groupby_apply():
"""Test pandas.DataFrame.groupby(...).progress_apply"""
with closing(StringIO()) as our_file:
@ -119,8 +129,8 @@ def test_pandas_groupby_apply():
dfs.groupby(['a']).progress_apply(lambda x: None)
df2 = df = pd.DataFrame({'a': randint(1, 8, 10000), 'b': rand(10000)})
res1 = df2.groupby("a").apply(max)
res2 = df2.groupby("a").progress_apply(max)
res1 = df2.groupby("a").apply(np.maximum.reduce)
res2 = df2.groupby("a").progress_apply(np.maximum.reduce)
assert res1.equals(res2)
our_file.seek(0)
@ -130,8 +140,7 @@ def test_pandas_groupby_apply():
nexres = '100%|##########|'
if nexres in our_file.read():
our_file.seek(0)
raise AssertionError("\nDid not expect:\n{0}\nIn:{1}\n".format(
nexres, our_file.read()))
raise AssertionError(f"\nDid not expect:\n{nexres}\nIn:{our_file.read()}\n")
with closing(StringIO()) as our_file:
tqdm.pandas(file=our_file, leave=True, ascii=True)
@ -140,26 +149,28 @@ def test_pandas_groupby_apply():
dfs.loc[0] = [2, 1, 1]
dfs['d'] = 100
expects = ['500/500', '1/1', '4/4', '2/2']
expects = ['500/500', '1/1', '4/4', '4/4']
dfs.groupby(dfs.index).progress_apply(lambda x: None)
dfs.groupby('d').progress_apply(lambda x: None)
dfs.groupby(dfs.columns, axis=1).progress_apply(lambda x: None)
dfs.groupby([2, 2, 1, 1], axis=1).progress_apply(lambda x: None)
dfs.T.groupby(dfs.columns).progress_apply(lambda x: None)
dfs.T.groupby([2, 2, 1, 1]).progress_apply(lambda x: None)
our_file.seek(0)
if our_file.read().count('100%') < 4:
our_file.seek(0)
raise AssertionError("\nExpected:\n{0}\nIn:\n{1}\n".format(
'100% at least four times', our_file.read()))
raise AssertionError(
f"\nExpected:\n100% at least four times\nIn:\n{our_file.read()}\n")
for exres in expects:
our_file.seek(0)
if our_file.getvalue().count(exres) < 1:
our_file.seek(0)
raise AssertionError("\nExpected:\n{0}\nIn:\n {1}\n".format(
exres + " at least once.", our_file.read()))
raise AssertionError(
f"\nExpected:\n{exres} at least once.\nIn:\n{our_file.read()}\n")
@mark.filterwarnings(
"ignore:DataFrameGroupBy.apply operated on the grouping columns:DeprecationWarning")
def test_pandas_leave():
"""Test pandas with `leave=True`"""
with closing(StringIO()) as our_file:
@ -172,8 +183,7 @@ def test_pandas_leave():
exres = '100%|##########| 100/100'
if exres not in our_file.read():
our_file.seek(0)
raise AssertionError("\nExpected:\n{0}\nIn:{1}\n".format(
exres, our_file.read()))
raise AssertionError(f"\nExpected:\n{exres}\nIn:{our_file.read()}\n")
def test_pandas_apply_args_deprecation():
@ -195,6 +205,8 @@ def test_pandas_apply_args_deprecation():
"keyword arguments instead"))
@mark.filterwarnings(
"ignore:DataFrameGroupBy.apply operated on the grouping columns:DeprecationWarning")
def test_pandas_deprecation():
"""Test bar object instance as argument deprecation"""
try:

View file

@ -1,5 +1,3 @@
from __future__ import division, print_function
import sys
from contextlib import contextmanager
from functools import wraps
@ -14,7 +12,7 @@ except ImportError:
from tqdm import tqdm, trange
from .tests_tqdm import _range, importorskip, mark, patch_lock, skip
from .tests_tqdm import importorskip, mark, patch_lock, skip
pytestmark = mark.slow
@ -98,10 +96,7 @@ def simple_progress(iterable=None, total=None, file=sys.stdout, desc='',
def format_interval(t):
mins, s = divmod(int(t), 60)
h, m = divmod(mins, 60)
if h:
return '{0:d}:{1:02d}:{2:02d}'.format(h, m, s)
else:
return '{0:02d}:{1:02d}'.format(m, s)
return f'{h:d}:{m:02d}:{s:02d}' if h else f'{m:02d}:{s:02d}'
def update_and_print(i=1):
n[0] += i
@ -143,7 +138,6 @@ def simple_progress(iterable=None, total=None, file=sys.stdout, desc='',
update_and_print(0)
if iterable is not None:
return update_and_yield()
else:
return update_and_print
@ -151,12 +145,8 @@ def assert_performance(thresh, name_left, time_left, name_right, time_right):
"""raises if time_left > thresh * time_right"""
if time_left > thresh * time_right:
raise ValueError(
('{name[0]}: {time[0]:f}, '
'{name[1]}: {time[1]:f}, '
'ratio {ratio:f} > {thresh:f}').format(
name=(name_left, name_right),
time=(time_left, time_right),
ratio=time_left / time_right, thresh=thresh))
f'{name_left}: {time_left:f}, {name_right}: {time_right:f}'
f', ratio {time_left / time_right:f} > {thresh:f}')
@retry_on_except()
@ -173,7 +163,7 @@ def test_iter_basic_overhead():
a = 0
with relative_timer() as time_bench:
for i in _range(total):
for i in range(total):
a += i
sys.stdout.write(str(a))
@ -188,13 +178,13 @@ def test_manual_basic_overhead():
with tqdm(total=total * 10, leave=True) as t:
a = 0
with relative_timer() as time_tqdm:
for i in _range(total):
for i in range(total):
a += i
t.update(10)
a = 0
with relative_timer() as time_bench:
for i in _range(total):
for i in range(total):
a += i
sys.stdout.write(str(a))
@ -249,7 +239,7 @@ def test_iter_overhead_hard():
a = 0
with relative_timer() as time_bench:
for i in _range(total):
for i in range(total):
a += i
sys.stdout.write(("%i" % a) * 40)
@ -265,13 +255,13 @@ def test_manual_overhead_hard():
mininterval=0, maxinterval=0) as t:
a = 0
with relative_timer() as time_tqdm:
for i in _range(total):
for i in range(total):
a += i
t.update(10)
a = 0
with relative_timer() as time_bench:
for i in _range(total):
for i in range(total):
a += i
sys.stdout.write(("%i" % a) * 40)
@ -292,7 +282,7 @@ def test_iter_overhead_simplebar_hard():
assert a == (total ** 2 - total) / 2.0
a = 0
s = simple_progress(_range(total), leave=True,
s = simple_progress(range(total), leave=True,
miniters=1, mininterval=0)
with relative_timer() as time_bench:
for i in s:
@ -310,7 +300,7 @@ def test_manual_overhead_simplebar_hard():
mininterval=0, maxinterval=0) as t:
a = 0
with relative_timer() as time_tqdm:
for i in _range(total):
for i in range(total):
a += i
t.update(10)
@ -318,7 +308,7 @@ def test_manual_overhead_simplebar_hard():
miniters=1, mininterval=0)
a = 0
with relative_timer() as time_bench:
for i in _range(total):
for i in range(total):
a += i
simplebar_update(10)

View file

@ -1,10 +1,7 @@
"""Test `tqdm.rich`."""
import sys
from .tests_tqdm import importorskip, mark
from .tests_tqdm import importorskip
@mark.skipif(sys.version_info[:3] < (3, 6, 1), reason="`rich` needs py>=3.6.1")
def test_rich_import():
"""Test `tqdm.rich` import"""
importorskip('tqdm.rich')

View file

@ -1,13 +1,9 @@
from __future__ import division
import sys
from functools import wraps
from threading import Event
from time import sleep, time
from tqdm import TMonitor, tqdm, trange
from .tests_perf import retry_on_except
from .tests_tqdm import StringIO, closing, importorskip, patch_lock, skip
@ -37,18 +33,13 @@ class Time(object):
sleep(0.000001) # sleep to allow interrupt (instead of pass)
def FakeEvent():
class FakeEvent(Event):
"""patched `threading.Event` where `wait()` uses `Time.fake_sleep()`"""
event = Event() # not a class in py2 so can't inherit
def wait(timeout=None):
def wait(self, timeout=None):
"""uses Time.fake_sleep"""
if timeout is not None:
Time.fake_sleep(timeout)
return event.is_set()
event.wait = wait
return event
return self.is_set()
def patch_sleep(func):
@ -206,19 +197,11 @@ def test_imap():
assert res[-1] == 100
# py2: locks won't propagate to incr_bar so may cause `AttributeError`
@retry_on_except(n=3 if sys.version_info < (3,) else 1, check_cpu_time=False)
@patch_lock(thread=True)
def test_threadpool():
"""Test concurrent.futures.ThreadPoolExecutor"""
ThreadPoolExecutor = importorskip('concurrent.futures').ThreadPoolExecutor
with ThreadPoolExecutor(8) as pool:
try:
res = list(tqdm(pool.map(incr_bar, range(100)), disable=True))
except AttributeError:
if sys.version_info < (3,):
skip("not supported on py2")
else:
raise
assert sum(res) == sum(range(1, 101))

View file

@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
# Advice: use repr(our_file.read()) to print the full output of tqdm
# (else '\r' will replace the previous lines and you'll see only the latest.
from __future__ import print_function
import csv
import os
import re
@ -37,16 +35,6 @@ if getattr(StringIO, '__exit__', False) and getattr(StringIO, '__enter__', False
else:
from contextlib import closing
try:
_range = xrange
except NameError:
_range = range
try:
_unicode = unicode
except NameError:
_unicode = str
nt_and_no_colorama = False
if os.name == 'nt':
try:
@ -119,7 +107,7 @@ def cpu_timify(t, timer=None):
class UnicodeIO(IOBase):
"""Unicode version of StringIO"""
def __init__(self, *args, **kwargs):
super(UnicodeIO, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.encoding = 'U8' # io.StringIO supports unicode, but no encoding
self.text = ''
self.cursor = 0
@ -201,6 +189,8 @@ def test_format_num():
assert float(format_num(1337)) == 1337
assert format_num(int(1e6)) == '1e+6'
assert format_num(1239876) == '1' '239' '876'
assert format_num(0.00001234) == '1.23e-5'
assert format_num(-0.1234) == '-0.123'
def test_format_meter():
@ -271,7 +261,6 @@ def test_format_meter():
20, 100, 12, ncols=14, rate=8.1,
bar_format=r'{l_bar}{bar}|{n_fmt}/{total_fmt}') == " 20%|" + unich(0x258d) + " |20/100"
# Check wide characters
if sys.version_info >= (3,):
assert format_meter(0, 1000, 13, ncols=68, prefix=': ') == (
": 0%| | 0/1000 [00:13<?, ?it/s]")
assert format_meter(0, 1000, 13, ncols=68, prefix='ニッポン [ニッポン]: ') == (
@ -328,11 +317,11 @@ def test_si_format():
def test_bar_formatspec():
"""Test Bar.__format__ spec"""
assert "{0:5a}".format(Bar(0.3)) == "#5 "
assert "{0:2}".format(Bar(0.5, charset=" .oO0")) == "0 "
assert "{0:2a}".format(Bar(0.5, charset=" .oO0")) == "# "
assert "{0:-6a}".format(Bar(0.5, 10)) == '## '
assert "{0:2b}".format(Bar(0.5, 10)) == ' '
assert f"{Bar(0.3):5a}" == "#5 "
assert f"{Bar(0.5, charset=' .oO0'):2}" == "0 "
assert f"{Bar(0.5, charset=' .oO0'):2a}" == "# "
assert f"{Bar(0.5, 10):-6a}" == '## '
assert f"{Bar(0.5, 10):2b}" == ' '
def test_all_defaults():
@ -353,7 +342,7 @@ def test_all_defaults():
class WriteTypeChecker(BytesIO):
"""File-like to assert the expected type is written"""
def __init__(self, expected_type):
super(WriteTypeChecker, self).__init__()
super().__init__()
self.expected_type = expected_type
def write(self, s):
@ -401,7 +390,7 @@ def test_iterate_over_csv_rows():
# Create a test csv pseudo file
with closing(StringIO()) as test_csv_file:
writer = csv.writer(test_csv_file)
for _ in _range(3):
for _ in range(3):
writer.writerow(['test'] * 3)
test_csv_file.seek(0)
@ -415,7 +404,7 @@ def test_iterate_over_csv_rows():
def test_file_output():
"""Test output to arbitrary file-like objects"""
with closing(StringIO()) as our_file:
for i in tqdm(_range(3), file=our_file):
for i in tqdm(range(3), file=our_file):
if i == 1:
our_file.seek(0)
assert '0/3' in our_file.read()
@ -424,14 +413,14 @@ def test_file_output():
def test_leave_option():
"""Test `leave=True` always prints info about the last iteration"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(3), file=our_file, leave=True):
for _ in tqdm(range(3), file=our_file, leave=True):
pass
res = our_file.getvalue()
assert '| 3/3 ' in res
assert '\n' == res[-1] # not '\r'
with closing(StringIO()) as our_file2:
for _ in tqdm(_range(3), file=our_file2, leave=False):
for _ in tqdm(range(3), file=our_file2, leave=False):
pass
assert '| 3/3 ' not in our_file2.getvalue()
@ -452,7 +441,7 @@ def test_trange():
def test_min_interval():
"""Test mininterval"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(3), file=our_file, mininterval=1e-10):
for _ in tqdm(range(3), file=our_file, mininterval=1e-10):
pass
assert " 0%| | 0/3 [00:00<" in our_file.getvalue()
@ -484,7 +473,7 @@ def test_max_interval():
t.update(bigstep)
t2.update(bigstep)
# The next iterations should not trigger maxinterval (step 10)
for _ in _range(4):
for _ in range(4):
t.update(smallstep)
t2.update(smallstep)
timer.sleep(1e-5)
@ -504,7 +493,7 @@ def test_max_interval():
# Increase 10 iterations at once
t.update(bigstep)
# The next iterations should trigger maxinterval (step 5)
for _ in _range(4):
for _ in range(4):
t.update(smallstep)
timer.sleep(1e-2)
@ -513,7 +502,7 @@ def test_max_interval():
# Test iteration based tqdm with maxinterval effect
timer = DiscreteTimer()
with closing(StringIO()) as our_file:
with tqdm(_range(total), file=our_file, miniters=None,
with tqdm(range(total), file=our_file, miniters=None,
mininterval=1e-5, smoothing=1, maxinterval=1e-4) as t2:
cpu_timify(t2, timer)
@ -560,9 +549,9 @@ def test_max_interval():
mininterval = 0.1
maxinterval = 10
with closing(StringIO()) as our_file:
t1 = tqdm(_range(total), file=our_file, miniters=None, smoothing=1,
t1 = tqdm(range(total), file=our_file, miniters=None, smoothing=1,
mininterval=mininterval, maxinterval=maxinterval)
t2 = tqdm(_range(total), file=our_file, miniters=None, smoothing=1,
t2 = tqdm(range(total), file=our_file, miniters=None, smoothing=1,
mininterval=0, maxinterval=maxinterval)
cpu_timify(t1, timer1)
@ -605,7 +594,7 @@ def test_delay():
def test_min_iters():
"""Test miniters"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(3), file=our_file, leave=True, mininterval=0, miniters=2):
for _ in tqdm(range(3), file=our_file, leave=True, mininterval=0, miniters=2):
pass
out = our_file.getvalue()
@ -615,7 +604,7 @@ def test_min_iters():
assert '| 3/3 ' in out
with closing(StringIO()) as our_file:
for _ in tqdm(_range(3), file=our_file, leave=True, mininterval=0, miniters=1):
for _ in tqdm(range(3), file=our_file, leave=True, mininterval=0, miniters=1):
pass
out = our_file.getvalue()
@ -669,7 +658,7 @@ def test_dynamic_min_iters():
# Check iterable based tqdm
with closing(StringIO()) as our_file:
t = tqdm(_range(10), file=our_file, miniters=None, mininterval=None,
t = tqdm(range(10), file=our_file, miniters=None, mininterval=None,
smoothing=0.5)
for _ in t:
pass
@ -677,7 +666,7 @@ def test_dynamic_min_iters():
# No smoothing
with closing(StringIO()) as our_file:
t = tqdm(_range(10), file=our_file, miniters=None, mininterval=None,
t = tqdm(range(10), file=our_file, miniters=None, mininterval=None,
smoothing=0)
for _ in t:
pass
@ -685,7 +674,7 @@ def test_dynamic_min_iters():
# No dynamic_miniters (miniters is fixed manually)
with closing(StringIO()) as our_file:
t = tqdm(_range(10), file=our_file, miniters=1, mininterval=None)
t = tqdm(range(10), file=our_file, miniters=1, mininterval=None)
for _ in t:
pass
assert not t.dynamic_miniters
@ -694,12 +683,12 @@ def test_dynamic_min_iters():
def test_big_min_interval():
"""Test large mininterval"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(2), file=our_file, mininterval=1E10):
for _ in tqdm(range(2), file=our_file, mininterval=1E10):
pass
assert '50%' not in our_file.getvalue()
with closing(StringIO()) as our_file:
with tqdm(_range(2), file=our_file, mininterval=1E10) as t:
with tqdm(range(2), file=our_file, mininterval=1E10) as t:
t.update()
t.update()
assert '50%' not in our_file.getvalue()
@ -718,10 +707,10 @@ def test_smoothed_dynamic_min_iters():
timer.sleep(1)
t.update(10)
# The next iterations should be partially skipped
for _ in _range(2):
for _ in range(2):
timer.sleep(1)
t.update(4)
for _ in _range(20):
for _ in range(20):
timer.sleep(1)
t.update()
@ -750,7 +739,7 @@ def test_smoothed_dynamic_min_iters_with_min_interval():
t.update(10)
timer.sleep(1e-2)
for _ in _range(4):
for _ in range(4):
t.update()
timer.sleep(1e-2)
out = our_file.getvalue()
@ -758,7 +747,7 @@ def test_smoothed_dynamic_min_iters_with_min_interval():
with closing(StringIO()) as our_file:
# Test iteration-based tqdm
with tqdm(_range(total), file=our_file, miniters=None,
with tqdm(range(total), file=our_file, miniters=None,
mininterval=0.01, smoothing=1, maxinterval=0) as t2:
cpu_timify(t2, timer)
@ -817,7 +806,7 @@ def _rlock_creation_target():
def test_disable():
"""Test disable"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(3), file=our_file, disable=True):
for _ in tqdm(range(3), file=our_file, disable=True):
pass
assert our_file.getvalue() == ''
@ -831,7 +820,7 @@ def test_disable():
def test_infinite_total():
"""Test treatment of infinite total"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(3), file=our_file, total=float("inf")):
for _ in tqdm(range(3), file=our_file, total=float("inf")):
pass
@ -852,7 +841,7 @@ def test_nototal():
def test_unit():
"""Test SI unit prefix"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(3), file=our_file, miniters=1, unit="bytes"):
for _ in tqdm(range(3), file=our_file, miniters=1, unit="bytes"):
pass
assert 'bytes/s' in our_file.getvalue()
@ -866,7 +855,7 @@ def test_ascii():
# Test ascii bar
with closing(StringIO()) as our_file:
for _ in tqdm(_range(3), total=15, file=our_file, miniters=1,
for _ in tqdm(range(3), total=15, file=our_file, miniters=1,
mininterval=0, ascii=True):
pass
res = our_file.getvalue().strip("\r").split("\r")
@ -877,7 +866,7 @@ def test_ascii():
# Test unicode bar
with closing(UnicodeIO()) as our_file:
with tqdm(total=15, file=our_file, ascii=False, mininterval=0) as t:
for _ in _range(3):
for _ in range(3):
t.update()
res = our_file.getvalue().strip("\r").split("\r")
assert u"7%|\u258b" in res[1]
@ -887,7 +876,7 @@ def test_ascii():
# Test custom bar
for bars in [" .oO0", " #"]:
with closing(StringIO()) as our_file:
for _ in tqdm(_range(len(bars) - 1), file=our_file, miniters=1,
for _ in tqdm(range(len(bars) - 1), file=our_file, miniters=1,
mininterval=0, ascii=bars, ncols=27):
pass
res = our_file.getvalue().strip("\r").split("\r")
@ -949,8 +938,7 @@ def test_close():
res = our_file.getvalue()
assert res[-1] == '\n'
if not res.startswith(exres):
raise AssertionError("\n<<< Expected:\n{0}\n>>> Got:\n{1}\n===".format(
exres + ', ...it/s]\n', our_file.getvalue()))
raise AssertionError(f"\n<<< Expected:\n{exres}, ...it/s]\n>>> Got:\n{res}\n===")
# Closing after the output stream has closed
with closing(StringIO()) as our_file:
@ -976,7 +964,7 @@ def test_smoothing():
# -- Test disabling smoothing
with closing(StringIO()) as our_file:
with tqdm(_range(3), file=our_file, smoothing=None, leave=True) as t:
with tqdm(range(3), file=our_file, smoothing=None, leave=True) as t:
cpu_timify(t, timer)
for _ in t:
@ -987,11 +975,11 @@ def test_smoothing():
# 1st case: no smoothing (only use average)
with closing(StringIO()) as our_file2:
with closing(StringIO()) as our_file:
t = tqdm(_range(3), file=our_file2, smoothing=None, leave=True,
t = tqdm(range(3), file=our_file2, smoothing=None, leave=True,
miniters=1, mininterval=0)
cpu_timify(t, timer)
with tqdm(_range(3), file=our_file, smoothing=None, leave=True,
with tqdm(range(3), file=our_file, smoothing=None, leave=True,
miniters=1, mininterval=0) as t2:
cpu_timify(t2, timer)
@ -1017,11 +1005,11 @@ def test_smoothing():
# 2nd case: use max smoothing (= instant rate)
with closing(StringIO()) as our_file2:
with closing(StringIO()) as our_file:
t = tqdm(_range(3), file=our_file2, smoothing=1, leave=True,
t = tqdm(range(3), file=our_file2, smoothing=1, leave=True,
miniters=1, mininterval=0)
cpu_timify(t, timer)
with tqdm(_range(3), file=our_file, smoothing=1, leave=True,
with tqdm(range(3), file=our_file, smoothing=1, leave=True,
miniters=1, mininterval=0) as t2:
cpu_timify(t2, timer)
@ -1040,11 +1028,11 @@ def test_smoothing():
# 3rd case: use medium smoothing
with closing(StringIO()) as our_file2:
with closing(StringIO()) as our_file:
t = tqdm(_range(3), file=our_file2, smoothing=0.5, leave=True,
t = tqdm(range(3), file=our_file2, smoothing=0.5, leave=True,
miniters=1, mininterval=0)
cpu_timify(t, timer)
t2 = tqdm(_range(3), file=our_file, smoothing=0.5, leave=True,
t2 = tqdm(range(3), file=our_file, smoothing=0.5, leave=True,
miniters=1, mininterval=0)
cpu_timify(t2, timer)
@ -1098,7 +1086,7 @@ def test_bar_format():
with closing(StringIO()) as our_file:
bar_format = r'hello world'
with tqdm(ascii=False, bar_format=bar_format, file=our_file) as t:
assert isinstance(t.bar_format, _unicode)
assert isinstance(t.bar_format, str)
def test_custom_format():
@ -1107,7 +1095,7 @@ def test_custom_format():
"""Provides a `total_time` format parameter"""
@property
def format_dict(self):
d = super(TqdmExtraFormat, self).format_dict
d = super().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
@ -1127,7 +1115,7 @@ def test_eta(capsys):
bar_format='{l_bar}{eta:%Y-%m-%d}'):
pass
_, err = capsys.readouterr()
assert "\r100%|{eta:%Y-%m-%d}\n".format(eta=dt.now()) in err
assert f"\r100%|{dt.now():%Y-%m-%d}\n" in err
def test_unpause():
@ -1257,7 +1245,7 @@ def test_position():
t1 = tqdm(desc='pos0 bar', position=0, **kwargs)
t2 = tqdm(desc='pos1 bar', position=1, **kwargs)
t3 = tqdm(desc='pos2 bar', position=2, **kwargs)
for _ in _range(2):
for _ in range(2):
t1.update()
t3.update()
t2.update()
@ -1360,7 +1348,7 @@ def test_deprecated_gui():
# t.close()
# len(tqdm._instances) += 1 # undo the close() decrement
t = tqdm(_range(3), gui=True, file=our_file, miniters=1, mininterval=0)
t = tqdm(range(3), gui=True, file=our_file, miniters=1, mininterval=0)
try:
for _ in t:
pass
@ -1735,7 +1723,7 @@ def test_external_write():
def test_unit_scale():
"""Test numeric `unit_scale`"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(9), unit_scale=9, file=our_file,
for _ in tqdm(range(9), unit_scale=9, file=our_file,
miniters=1, mininterval=0):
pass
out = our_file.getvalue()
@ -1937,7 +1925,7 @@ def test_screen_shape():
def test_initial():
"""Test `initial`"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(9), initial=10, total=19, file=our_file,
for _ in tqdm(range(9), initial=10, total=19, file=our_file,
miniters=1, mininterval=0):
pass
out = our_file.getvalue()
@ -1948,7 +1936,7 @@ def test_initial():
def test_colour():
"""Test `colour`"""
with closing(StringIO()) as our_file:
for _ in tqdm(_range(9), file=our_file, colour="#beefed"):
for _ in tqdm(range(9), file=our_file, colour="#beefed"):
pass
out = our_file.getvalue()
assert '\x1b[38;2;%d;%d;%dm' % (0xbe, 0xef, 0xed) in out
@ -1961,7 +1949,7 @@ def test_colour():
assert "Unknown colour" in str(w[-1].message)
with closing(StringIO()) as our_file2:
for _ in tqdm(_range(9), file=our_file2, colour="blue"):
for _ in tqdm(range(9), file=our_file2, colour="blue"):
pass
out = our_file2.getvalue()
assert '\x1b[34m' in out
@ -1977,7 +1965,7 @@ def test_closed():
def test_reversed(capsys):
"""Test reversed()"""
for _ in reversed(tqdm(_range(9))):
for _ in reversed(tqdm(range(9))):
pass
out, err = capsys.readouterr()
assert not out
@ -1989,7 +1977,7 @@ def test_contains(capsys):
"""Test __contains__ doesn't iterate"""
with tqdm(list(range(9))) as t:
assert 9 not in t
assert all(i in t for i in _range(9))
assert all(i in t for i in range(9))
out, err = capsys.readouterr()
assert not out
assert ' 0%' in err

51
tests/tests_utils.py Normal file
View file

@ -0,0 +1,51 @@
from ast import literal_eval
from collections import defaultdict
from typing import Union # py<3.10
from tqdm.utils import envwrap
def test_envwrap(monkeypatch):
"""Test @envwrap (basic)"""
monkeypatch.setenv('FUNC_A', "42")
monkeypatch.setenv('FUNC_TyPe_HiNt', "1337")
monkeypatch.setenv('FUNC_Unused', "x")
@envwrap("FUNC_")
def func(a=1, b=2, type_hint: int = None):
return a, b, type_hint
assert (42, 2, 1337) == func()
assert (99, 2, 1337) == func(a=99)
def test_envwrap_types(monkeypatch):
"""Test @envwrap(types)"""
monkeypatch.setenv('FUNC_notype', "3.14159")
@envwrap("FUNC_", types=defaultdict(lambda: literal_eval))
def func(notype=None):
return notype
assert 3.14159 == func()
monkeypatch.setenv('FUNC_number', "1")
monkeypatch.setenv('FUNC_string', "1")
@envwrap("FUNC_", types={'number': int})
def nofallback(number=None, string=None):
return number, string
assert 1, "1" == nofallback()
def test_envwrap_annotations(monkeypatch):
"""Test @envwrap with typehints"""
monkeypatch.setenv('FUNC_number', "1.1")
monkeypatch.setenv('FUNC_string', "1.1")
@envwrap("FUNC_")
def annotated(number: Union[int, float] = None, string: int = None):
return number, string
assert 1.1, "1.1" == annotated()

48
tox.ini
View file

@ -4,20 +4,17 @@
# and then run "tox" from this directory.
[tox]
# deprecation warning: py{27,py2,34,35,36}
envlist=py{27,34,35,36,37,38,39,310,py2,py3}{,-tf}{,-keras}, perf, setup.py
envlist=py{37,38,39,310,311,312,py3}{,-tf}{,-keras}, perf, check
isolated_build=True
[gh-actions]
python=
2.7: py27
3.5: py35
3.6: py36
3.7: py37
3.8: py38
3.9: py39
3.10: py310
pypy-2.7: pypy2
3.11: py311
3.12: py312
pypy-3.7: pypy3
[gh-actions:env]
PLATFORM=
@ -26,12 +23,11 @@ PLATFORM=
[core]
deps=
pytest
py3{4,5,6}: pytest<7
pytest-cov
pytest-timeout
py3{7,8,9,10}: pytest-asyncio
py3{6,7,8,9,10}: ipywidgets
py3{7,8,9,10}: git+https://github.com/casperdcl/nbval.git@master#egg=nbval
pytest-asyncio
ipywidgets
git+https://github.com/casperdcl/nbval.git@master#egg=nbval
coverage
coveralls
codecov
@ -41,7 +37,7 @@ commands=
- codacy report -l Python -r coverage.xml --partial
[testenv]
passenv=TOXENV CI GITHUB_* CODECOV_* COVERALLS_* CODACY_* HOME
passenv=TOXENV,CI,GITHUB_*,CODECOV_*,COVERALLS_*,CODACY_*,HOME
deps=
{[core]deps}
cython
@ -49,26 +45,17 @@ deps=
matplotlib
numpy
pandas
rich
tf: tensorflow!=2.5.0
!py27-keras: keras
py27-keras: keras<2.5
py35-keras: keras<2.7
py27-tf: protobuf<3.18
py3{6,7,8,9,10}: rich
keras: keras
commands=
py3{4,5,6}: pytest --cov=tqdm --cov-report=xml --cov-report=term -k "not perf" -o addopts= -v --tb=short -rxs -W=error --durations=0 --durations-min=0.1
py3{7,8,9,10}: pytest --cov=tqdm --cov-report= tests_notebook.ipynb --nbval --nbval-current-env -W=ignore --nbval-sanitize-with=setup.cfg
py3{7,8,9,10}: pytest --cov=tqdm --cov-report=xml --cov-report=term --cov-append -k "not perf"
pytest --cov=tqdm --cov-report= -W=ignore tests_notebook.ipynb --nbval --nbval-current-env --nbval-sanitize-with=.meta/nbval.ini
pytest --cov=tqdm --cov-report=xml --cov-report=term --cov-append -k "not perf"
{[core]commands}
allowlist_externals=codacy
[testenv:py{27,py2}{,-tf}{,-keras}]
commands=
pytest --cov=tqdm --cov-report=xml --cov-report=term -k "not perf" -o addopts= -v --tb=short -rxs -W=error --durations=10
{[core]commands}
# no cython/numpy/pandas
[testenv:py{34,py2,py3}]
[testenv:pypy3]
deps={[core]deps}
[testenv:perf]
@ -78,11 +65,12 @@ deps=
pytest-asyncio
commands=pytest -k perf
[testenv:setup.py]
[testenv:check]
deps=
docutils
pygments
build
twine
py-make>=0.1.0
commands=
{envpython} setup.py check --restructuredtext --metadata --strict
{envpython} setup.py make none
{envpython} -m build
{envpython} -m twine check dist/*
{envpython} -m pymake -h

File diff suppressed because it is too large Load diff

View file

@ -1,88 +0,0 @@
.pre-commit-config.yaml
.zenodo.json
CODE_OF_CONDUCT.md
CONTRIBUTING.md
DEMO.ipynb
LICENCE
Makefile
README.rst
environment.yml
logo.png
pyproject.toml
setup.cfg
setup.py
tests_notebook.ipynb
tox.ini
examples/7zx.py
examples/async_coroutines.py
examples/coroutine_pipe.py
examples/include_no_requirements.py
examples/pandas_progress_apply.py
examples/paper.bib
examples/paper.md
examples/parallel_bars.py
examples/redirect_print.py
examples/simple_examples.py
examples/tqdm_requests.py
examples/tqdm_wget.py
examples/wrapping_generators.py
tests/__init__.py
tests/conftest.py
tests/py37_asyncio.py
tests/tests_asyncio.py
tests/tests_concurrent.py
tests/tests_contrib.py
tests/tests_contrib_logging.py
tests/tests_dask.py
tests/tests_gui.py
tests/tests_itertools.py
tests/tests_keras.py
tests/tests_main.py
tests/tests_notebook.py
tests/tests_pandas.py
tests/tests_perf.py
tests/tests_rich.py
tests/tests_synchronisation.py
tests/tests_tk.py
tests/tests_tqdm.py
tests/tests_version.py
tqdm/__init__.py
tqdm/__main__.py
tqdm/_dist_ver.py
tqdm/_main.py
tqdm/_monitor.py
tqdm/_tqdm.py
tqdm/_tqdm_gui.py
tqdm/_tqdm_notebook.py
tqdm/_tqdm_pandas.py
tqdm/_utils.py
tqdm/asyncio.py
tqdm/auto.py
tqdm/autonotebook.py
tqdm/cli.py
tqdm/completion.sh
tqdm/dask.py
tqdm/gui.py
tqdm/keras.py
tqdm/notebook.py
tqdm/rich.py
tqdm/std.py
tqdm/tk.py
tqdm/tqdm.1
tqdm/utils.py
tqdm/version.py
tqdm.egg-info/PKG-INFO
tqdm.egg-info/SOURCES.txt
tqdm.egg-info/dependency_links.txt
tqdm.egg-info/entry_points.txt
tqdm.egg-info/requires.txt
tqdm.egg-info/top_level.txt
tqdm/contrib/__init__.py
tqdm/contrib/bells.py
tqdm/contrib/concurrent.py
tqdm/contrib/discord.py
tqdm/contrib/itertools.py
tqdm/contrib/logging.py
tqdm/contrib/slack.py
tqdm/contrib/telegram.py
tqdm/contrib/utils_worker.py

View file

@ -1 +0,0 @@

View file

@ -1,2 +0,0 @@
[console_scripts]
tqdm = tqdm.cli:main

View file

@ -1,20 +0,0 @@
[:platform_system == "Windows"]
colorama
[:python_version < "3.7"]
importlib_resources
[dev]
py-make>=0.1.0
twine
wheel
[notebook]
ipywidgets>=6
[slack]
slack-sdk
[telegram]
requests

View file

@ -1 +0,0 @@
tqdm

View file

@ -29,10 +29,7 @@ def tqdm_notebook(*args, **kwargs): # pragma: no cover
def tnrange(*args, **kwargs): # pragma: no cover
"""
A shortcut for `tqdm.notebook.tqdm(xrange(*args), **kwargs)`.
On Python3+, `range` is used instead of `xrange`.
"""
"""Shortcut for `tqdm.notebook.tqdm(range(*args), **kwargs)`."""
from warnings import warn
from .notebook import trange as _tnrange

View file

@ -1 +0,0 @@
__version__ = '4.64.1'

View file

@ -2,10 +2,9 @@ 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)
CUR_OS, IS_NIX, IS_WIN, RE_ANSI, Comparable, FormatReplace, SimpleTextIOWrapper,
_environ_cols_wrapper, _is_ascii, _is_utf, _screen_shape_linux, _screen_shape_tput,
_screen_shape_windows, _screen_shape_wrapper, _supports_unicode, _term_move_up, colorama)
warn("This function will be removed in tqdm==5.0.0\n"
"Please use `tqdm.utils.*` instead of `tqdm._utils.*`",

View file

@ -18,10 +18,10 @@ __all__ = ['tqdm_asyncio', 'tarange', 'tqdm', 'trange']
class tqdm_asyncio(std_tqdm):
"""
Asynchronous-friendly version of tqdm (Python 3.6+).
Asynchronous-friendly version of tqdm.
"""
def __init__(self, iterable=None, *args, **kwargs):
super(tqdm_asyncio, self).__init__(iterable, *args, **kwargs)
super().__init__(iterable, *args, **kwargs)
self.iterable_awaitable = False
if iterable is not None:
if hasattr(iterable, "__anext__"):

View file

@ -4,7 +4,7 @@ Enables multiple commonly used features.
Method resolution order:
- `tqdm.autonotebook` without import warnings
- `tqdm.asyncio` on Python3.6+
- `tqdm.asyncio`
- `tqdm.std` base class
Usage:
@ -12,7 +12,6 @@ Usage:
>>> for i in trange(10):
... ...
"""
import sys
import warnings
from .std import TqdmExperimentalWarning
@ -20,12 +19,7 @@ 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
@ -35,10 +29,12 @@ else: # Python3.6+
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"]

View file

@ -5,6 +5,7 @@ import logging
import re
import sys
from ast import literal_eval as numeric
from textwrap import indent
from .std import TqdmKeyError, TqdmTypeError, tqdm
from .version import __version__
@ -21,23 +22,34 @@ def cast(val, typ):
return cast(val, t)
except TqdmTypeError:
pass
raise TqdmTypeError(val + ' : ' + typ)
raise TqdmTypeError(f"{val} : {typ}")
# sys.stderr.write('\ndebug | `val:type`: `' + val + ':' + typ + '`.\n')
if typ == 'bool':
if (val == 'True') or (val == ''):
return True
elif val == 'False':
if 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)
if len(val) == 1:
return val.encode()
if re.match(r"^\\\w+$", val):
return eval(f'"{val}"').encode()
raise TqdmTypeError(f"{val} : {typ}")
if typ == 'str':
return val
if typ == 'int':
try:
return int(val)
except ValueError as exc:
raise TqdmTypeError(f"{val} : {typ}") from exc
if typ == 'float':
try:
return float(val)
except ValueError as exc:
raise TqdmTypeError(f"{val} : {typ}") from exc
raise TqdmTypeError(f"{val} : {typ}")
def posix_pipe(fin, fout, delim=b'\\n', buf_size=256,
@ -98,7 +110,7 @@ def posix_pipe(fin, fout, delim=b'\\n', buf_size=256,
# ((opt, type), ... )
RE_OPTS = re.compile(r'\n {8}(\S+)\s{2,}:\s*([^,]+)')
RE_OPTS = re.compile(r'\n {4}(\S+)\s{2,}:\s*([^,]+)')
# better split method assuming no positional args
RE_SHLEX = re.compile(r'\s*(?<!\S)--?([^\s=]+)(\s+|=|$)')
@ -166,7 +178,9 @@ def main(fp=sys.stderr, argv=None):
logging.basicConfig(level=getattr(logging, logLevel),
format="%(levelname)s:%(module)s:%(lineno)d:%(message)s")
d = tqdm.__init__.__doc__ + CLI_EXTRA_DOC
# py<3.13 doesn't dedent docstrings
d = (tqdm.__doc__ if sys.version_info < (3, 13)
else indent(tqdm.__doc__, " ")) + CLI_EXTRA_DOC
opt_types = dict(RE_OPTS.findall(d))
# opt_types['delim'] = 'chr'
@ -199,8 +213,7 @@ Options:
sys.stdout.write(d + '\n')
sys.exit(0)
elif argv and argv[0][:2] != '--':
sys.stderr.write(
"Error:Unknown argument:{0}\n{1}".format(argv[0], help_short))
sys.stderr.write(f"Error:Unknown argument:{argv[0]}\n{help_short}")
argv = RE_SHLEX.split(' '.join(["tqdm"] + argv))
opts = dict(zip(argv[1::3], argv[3::3]))
@ -245,25 +258,21 @@ Options:
stdout = getattr(stdout, 'buffer', stdout)
stdin = getattr(sys.stdin, 'buffer', sys.stdin)
if manpath or comppath:
from os import path
from shutil import copyfile
try: # py<3.7
try: # py<3.9
import importlib_resources as resources
except ImportError:
from importlib import resources
from pathlib import Path
def cp(name, dst):
"""copy resource `name` to `dst`"""
if hasattr(resources, 'files'):
copyfile(str(resources.files('tqdm') / name), dst)
else: # py<3.9
with resources.path('tqdm', name) as src:
copyfile(str(src), dst)
fi = resources.files('tqdm') / name
dst.write_bytes(fi.read_bytes())
log.info("written:%s", dst)
if manpath is not None:
cp('tqdm.1', path.join(manpath, 'tqdm.1'))
cp('tqdm.1', Path(manpath) / 'tqdm.1')
if comppath is not None:
cp('completion.sh', path.join(comppath, 'tqdm_completion.sh'))
cp('completion.sh', Path(comppath) / 'tqdm_completion.sh')
sys.exit(0)
if tee:
stdout_write = stdout.write

View file

@ -3,11 +3,10 @@ Thin wrappers around common functions.
Subpackages contain potentially unstable extensions.
"""
import sys
from functools import wraps
from warnings import warn
from ..auto import tqdm as tqdm_auto
from ..std import tqdm
from ..std import TqdmDeprecationWarning, tqdm
from ..utils import ObjectWrapper
__author__ = {"github.com/": ["casperdcl"]}
@ -18,7 +17,7 @@ class DummyTqdmFile(ObjectWrapper):
"""Dummy file-like that will write to tqdm"""
def __init__(self, wrapped):
super(DummyTqdmFile, self).__init__(wrapped)
super().__init__(wrapped)
self._buf = []
def write(self, x, nolock=False):
@ -42,12 +41,9 @@ class DummyTqdmFile(ObjectWrapper):
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
"""Returns `func`"""
warn("This function has no effect, and will be removed in tqdm==5.0.0",
TqdmDeprecationWarning, stacklevel=2)
return func
@ -70,7 +66,6 @@ def tenumerate(iterable, start=0, total=None, tqdm_class=tqdm_auto, **tqdm_kwarg
return enumerate(tqdm_class(iterable, total=total, **tqdm_kwargs), start)
@builtin_iterable
def tzip(iter1, *iter2plus, **tqdm_kwargs):
"""
Equivalent of builtin `zip`.
@ -85,7 +80,6 @@ def tzip(iter1, *iter2plus, **tqdm_kwargs):
yield i
@builtin_iterable
def tmap(function, *sequences, **tqdm_kwargs):
"""
Equivalent of builtin `map`.

View file

@ -1,32 +1,13 @@
"""
Thin wrappers around `concurrent.futures`.
"""
from __future__ import absolute_import
from contextlib import contextmanager
from operator import length_hint
from os import cpu_count
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']
@ -64,16 +45,10 @@ def _executor_map(PoolExecutor, fn, *iterables, **tqdm_kwargs):
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))
with PoolExecutor(max_workers=max_workers, initializer=tqdm_class.set_lock,
initargs=(lk,)) as ex:
return list(tqdm_class(ex.map(fn, *iterables, chunksize=chunksize), **kwargs))
def thread_map(fn, *iterables, **tqdm_kwargs):

View file

@ -6,54 +6,85 @@ Usage:
>>> for i in trange(10, token='{token}', channel_id='{channel_id}'):
... ...
![screenshot](https://img.tqdm.ml/screenshot-discord.png)
![screenshot](https://tqdm.github.io/img/screenshot-discord.png)
"""
from __future__ import absolute_import
import logging
from os import getenv
from warnings import warn
try:
from disco.client import Client, ClientConfig
except ImportError:
raise ImportError("Please `pip install disco-py`")
from requests import Session
from requests.utils import default_user_agent
from ..auto import tqdm as tqdm_auto
from ..utils import _range
from ..std import TqdmWarning
from ..version import __version__
from .utils_worker import MonoWorker
__author__ = {"github.com/": ["casperdcl"]}
__author__ = {"github.com/": ["casperdcl", "guigoruiz1"]}
__all__ = ['DiscordIO', 'tqdm_discord', 'tdrange', 'tqdm', 'trange']
class DiscordIO(MonoWorker):
"""Non-blocking file-like IO using a Discord Bot."""
API = "https://discord.com/api/v10"
UA = f"tqdm (https://tqdm.github.io, {__version__}) {default_user_agent()}"
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)
super().__init__()
self.token = token
self.channel_id = channel_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:
self.message = client.api.channels_messages_create(channel_id, self.text)
res = self.session.post(
f'{self.API}/channels/{self.channel_id}/messages',
headers={'Authorization': f'Bot {self.token}', 'User-Agent': self.UA},
json={'content': f"`{self.text}`"}).json()
except Exception as e:
tqdm_auto.write(str(e))
self.message = None
else:
if res.get('error_code') == 429:
warn("Creation rate limit: try increasing `mininterval`.",
TqdmWarning, stacklevel=2)
else:
self._message_id = res['id']
return self._message_id
def write(self, s):
"""Replaces internal `message`'s text with `s`."""
"""Replaces internal `message_id`'s text with `s`."""
if not s:
s = "..."
s = s.replace('\r', '').strip()
if s == self.text:
return # skip duplicate message
message = self.message
if message is None:
return # avoid duplicate message Bot error
message_id = self.message_id
if message_id is None:
return
self.text = s
try:
future = self.submit(message.edit, '`' + s + '`')
future = self.submit(
self.session.patch,
f'{self.API}/channels/{self.channel_id}/messages/{message_id}',
headers={'Authorization': f'Bot {self.token}', 'User-Agent': self.UA},
json={'content': f"`{self.text}`"})
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.delete,
f'{self.API}/channels/{self.channel_id}/messages/{self.message_id}',
headers={'Authorization': f'Bot {self.token}', 'User-Agent': self.UA})
except Exception as e:
tqdm_auto.write(str(e))
else:
@ -78,26 +109,22 @@ class tqdm_discord(tqdm_auto):
"""
Parameters
----------
token : str, required. Discord token
token : str, required. Discord bot 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)
kwargs.pop('token', getenv('TQDM_DISCORD_TOKEN')),
kwargs.pop('channel_id', getenv('TQDM_DISCORD_CHANNEL_ID')))
super().__init__(*args, **kwargs)
def display(self, **kwargs):
super(tqdm_discord, self).display(**kwargs)
super().display(**kwargs)
fmt = self.format_dict
if fmt.get('bar_format', None):
fmt['bar_format'] = fmt['bar_format'].replace(
@ -107,17 +134,21 @@ class tqdm_discord(tqdm_auto):
self.dio.write(self.format_meter(**fmt))
def clear(self, *args, **kwargs):
super(tqdm_discord, self).clear(*args, **kwargs)
super().clear(*args, **kwargs)
if not self.disable:
self.dio.write("")
def close(self):
if self.disable:
return
super().close()
if not (self.leave or (self.leave is None and self.pos == 0)):
self.dio.delete()
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)
"""Shortcut for `tqdm.contrib.discord.tqdm(range(*args), **kwargs)`."""
return tqdm_discord(range(*args), **kwargs)
# Aliases

View file

@ -1,8 +1,6 @@
"""
Thin wrappers around `itertools`.
"""
from __future__ import absolute_import
import itertools
from ..auto import tqdm as tqdm_auto

View file

@ -1,14 +1,12 @@
"""
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
from typing import Iterator, List, Optional, Type # noqa: F401
except ImportError:
pass
@ -20,7 +18,7 @@ class _TqdmLoggingHandler(logging.StreamHandler):
self,
tqdm_class=std_tqdm # type: Type[std_tqdm]
):
super(_TqdmLoggingHandler, self).__init__()
super().__init__()
self.tqdm_class = tqdm_class
def emit(self, record):

View file

@ -6,10 +6,8 @@ Usage:
>>> for i in trange(10, token='{token}', channel='{channel}'):
... ...
![screenshot](https://img.tqdm.ml/screenshot-slack.png)
![screenshot](https://tqdm.github.io/img/screenshot-slack.png)
"""
from __future__ import absolute_import
import logging
from os import getenv
@ -19,7 +17,6 @@ except ImportError:
raise ImportError("Please `pip install slack-sdk`")
from ..auto import tqdm as tqdm_auto
from ..utils import _range
from .utils_worker import MonoWorker
__author__ = {"github.com/": ["0x2b3bfa0", "casperdcl"]}
@ -30,7 +27,7 @@ class SlackIO(MonoWorker):
"""Non-blocking file-like IO using a Slack app."""
def __init__(self, token, channel):
"""Creates a new message in the given `channel`."""
super(SlackIO, self).__init__()
super().__init__()
self.client = WebClient(token=token)
self.text = self.__class__.__name__
try:
@ -91,10 +88,10 @@ class tqdm_slack(tqdm_auto):
kwargs.pop('token', getenv("TQDM_SLACK_TOKEN")),
kwargs.pop('channel', getenv("TQDM_SLACK_CHANNEL")))
kwargs['mininterval'] = max(1.5, kwargs.get('mininterval', 1.5))
super(tqdm_slack, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def display(self, **kwargs):
super(tqdm_slack, self).display(**kwargs)
super().display(**kwargs)
fmt = self.format_dict
if fmt.get('bar_format', None):
fmt['bar_format'] = fmt['bar_format'].replace(
@ -108,17 +105,14 @@ class tqdm_slack(tqdm_auto):
self.sio.write(self.format_meter(**fmt))
def clear(self, *args, **kwargs):
super(tqdm_slack, self).clear(*args, **kwargs)
super().clear(*args, **kwargs)
if not self.disable:
self.sio.write("")
def tsrange(*args, **kwargs):
"""
A shortcut for `tqdm.contrib.slack.tqdm(xrange(*args), **kwargs)`.
On Python3+, `range` is used instead of `xrange`.
"""
return tqdm_slack(_range(*args), **kwargs)
"""Shortcut for `tqdm.contrib.slack.tqdm(range(*args), **kwargs)`."""
return tqdm_slack(range(*args), **kwargs)
# Aliases

View file

@ -6,10 +6,8 @@ Usage:
>>> for i in trange(10, token='{token}', chat_id='{chat_id}'):
... ...
![screenshot](https://img.tqdm.ml/screenshot-telegram.gif)
![screenshot](https://tqdm.github.io/img/screenshot-telegram.gif)
"""
from __future__ import absolute_import
from os import getenv
from warnings import warn
@ -17,7 +15,6 @@ 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"]}
@ -30,7 +27,7 @@ class TelegramIO(MonoWorker):
def __init__(self, token, chat_id):
"""Creates a new message in the given `chat_id`."""
super(TelegramIO, self).__init__()
super().__init__()
self.token = token
self.chat_id = chat_id
self.session = Session()
@ -121,10 +118,10 @@ class tqdm_telegram(tqdm_auto):
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)
super().__init__(*args, **kwargs)
def display(self, **kwargs):
super(tqdm_telegram, self).display(**kwargs)
super().display(**kwargs)
fmt = self.format_dict
if fmt.get('bar_format', None):
fmt['bar_format'] = fmt['bar_format'].replace(
@ -134,24 +131,21 @@ class tqdm_telegram(tqdm_auto):
self.tgio.write(self.format_meter(**fmt))
def clear(self, *args, **kwargs):
super(tqdm_telegram, self).clear(*args, **kwargs)
super().clear(*args, **kwargs)
if not self.disable:
self.tgio.write("")
def close(self):
if self.disable:
return
super(tqdm_telegram, self).close()
super().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)
"""Shortcut for `tqdm.contrib.telegram.tqdm(range(*args), **kwargs)`."""
return tqdm_telegram(range(*args), **kwargs)
# Aliases

View file

@ -1,8 +1,6 @@
"""
IO/concurrency helpers for `tqdm.contrib`.
"""
from __future__ import absolute_import
from collections import deque
from concurrent.futures import ThreadPoolExecutor

View file

@ -1,5 +1,3 @@
from __future__ import absolute_import
from functools import partial
from dask.callbacks import Callback
@ -22,7 +20,7 @@ class TqdmCallback(Callback):
tqdm_kwargs : optional
Any other arguments used for all bars.
"""
super(TqdmCallback, self).__init__(start=start, pretask=pretask)
super().__init__(start=start, pretask=pretask)
if tqdm_kwargs:
tqdm_class = partial(tqdm_class, **tqdm_kwargs)
self.tqdm_class = tqdm_class

View file

@ -8,16 +8,14 @@ Usage:
"""
# 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']
@ -34,7 +32,7 @@ class tqdm_gui(std_tqdm): # pragma: no cover
kwargs = kwargs.copy()
kwargs['gui'] = True
colour = kwargs.pop('colour', 'g')
super(tqdm_gui, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if self.disable:
return
@ -124,6 +122,7 @@ class tqdm_gui(std_tqdm): # pragma: no cover
ax = self.ax
line1 = self.line1
line2 = self.line2
hspan = getattr(self, 'hspan', None)
# instantaneous rate
y = delta_it / delta_t
# overall rate
@ -150,18 +149,10 @@ class tqdm_gui(std_tqdm): # pragma: no cover
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)
if hspan:
hspan.set_xy((0, ymin))
hspan.set_height(ymax - ymin)
hspan.set_width(n / total)
else:
t_ago = [cur_t - i for i in xdata]
line1.set_data(t_ago, ydata)
@ -173,17 +164,14 @@ class tqdm_gui(std_tqdm): # pragma: no cover
"{bar}", "<bar/>")
msg = self.format_meter(**d)
if '<bar/>' in msg:
msg = "".join(re.split(r'\|?<bar/>\|?', msg, 1))
msg = "".join(re.split(r'\|?<bar/>\|?', msg, maxsplit=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)
"""Shortcut for `tqdm.gui.tqdm(range(*args), **kwargs)`."""
return tqdm_gui(range(*args), **kwargs)
# Aliases

View file

@ -1,5 +1,3 @@
from __future__ import absolute_import, division
from copy import copy
from functools import partial
@ -96,7 +94,7 @@ class TqdmCallback(keras.callbacks.Callback):
raise KeyError('Unknown verbosity')
def on_train_end(self, *_, **__):
if self.verbose:
if hasattr(self, 'batch_bar'):
self.batch_bar.close()
self.epoch_bar.close()

View file

@ -7,18 +7,14 @@ Usage:
>>> 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 html import escape
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
@ -63,12 +59,6 @@ if True: # pragma: no cover
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']
WARN_NOIPYW = ("IProgress not found. Please update jupyter and ipywidgets."
@ -90,7 +80,7 @@ class TqdmHBox(HBox):
def __repr__(self, pretty=False):
pbar = getattr(self, 'pbar', None)
if pbar is None:
return super(TqdmHBox, self).__repr__()
return super().__repr__()
return pbar.format_meter(**self._json_(pretty))
def _repr_pretty_(self, pp, *_, **__):
@ -167,9 +157,10 @@ class tqdm_notebook(std_tqdm):
pbar.value = self.n
if msg:
msg = msg.replace(' ', u'\u2007') # fix html space padding
# html escape special characters (like '&')
if '<bar/>' in msg:
left, right = map(escape, re.split(r'\|?<bar/>\|?', msg, 1))
left, right = map(escape, re.split(r'\|?<bar/>\|?', msg, maxsplit=1))
else:
left, right = '', escape(msg)
@ -229,7 +220,7 @@ class tqdm_notebook(std_tqdm):
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)
super().__init__(*args, **kwargs)
if self.disable or not kwargs['gui']:
self.disp = lambda *_, **__: None
return
@ -255,7 +246,7 @@ class tqdm_notebook(std_tqdm):
def __iter__(self):
try:
it = super(tqdm_notebook, self).__iter__()
it = super().__iter__()
for obj in it:
# return super(tqdm...) will not catch exception
yield obj
@ -268,7 +259,7 @@ class tqdm_notebook(std_tqdm):
def update(self, n=1):
try:
return super(tqdm_notebook, self).update(n=n)
return super().update(n=n)
# NB: except ... [ as ...] breaks IPython async KeyboardInterrupt
except: # NOQA
# cannot catch KeyboardInterrupt when using manual tqdm
@ -281,7 +272,7 @@ class tqdm_notebook(std_tqdm):
def close(self):
if self.disable:
return
super(tqdm_notebook, self).close()
super().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:
@ -306,22 +297,19 @@ class tqdm_notebook(std_tqdm):
total : int or float, optional. Total to use for the new bar.
"""
if self.disable:
return super(tqdm_notebook, self).reset(total=total)
return super().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)
return super().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)
"""Shortcut for `tqdm.notebook.tqdm(range(*args), **kwargs)`."""
return tqdm_notebook(range(*args), **kwargs)
# Aliases

View file

@ -6,8 +6,6 @@ Usage:
>>> for i in trange(10):
... ...
"""
from __future__ import absolute_import
from warnings import warn
from rich.progress import (
@ -15,7 +13,6 @@ from rich.progress import (
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']
@ -93,7 +90,7 @@ class tqdm_rich(std_tqdm): # pragma: no cover
kwargs['disable'] = bool(kwargs.get('disable', False))
progress = kwargs.pop('progress', None)
options = kwargs.pop('options', {}).copy()
super(tqdm_rich, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if self.disable:
return
@ -119,7 +116,8 @@ class tqdm_rich(std_tqdm): # pragma: no cover
def close(self):
if self.disable:
return
super(tqdm_rich, self).close()
self.display() # print 100%, vis #1306
super().close()
self._prog.__exit__(None, None, None)
def clear(self, *_, **__):
@ -140,15 +138,12 @@ class tqdm_rich(std_tqdm): # pragma: no cover
"""
if hasattr(self, '_prog'):
self._prog.reset(total=total)
super(tqdm_rich, self).reset(total=total)
super().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)
"""Shortcut for `tqdm.rich.tqdm(range(*args), **kwargs)`."""
return tqdm_rich(range(*args), **kwargs)
# Aliases

View file

@ -7,12 +7,10 @@ Usage:
>>> 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 datetime import datetime, timedelta, timezone
from numbers import Number
from time import time
from warnings import warn
@ -21,8 +19,8 @@ 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)
_is_ascii, _screen_shape_wrapper, _supports_unicode, _term_move_up, disp_len, disp_trim,
envwrap)
__author__ = "https://github.com/tqdm/tqdm#contributions"
__all__ = ['tqdm', 'trange',
@ -48,7 +46,7 @@ class TqdmWarning(Warning):
if fp_write is not None:
fp_write("\n" + self.__class__.__name__ + ": " + str(msg).rstrip() + '\n')
else:
super(TqdmWarning, self).__init__(msg, *a, **k)
super().__init__(msg, *a, **k)
class TqdmExperimentalWarning(TqdmWarning, FutureWarning):
@ -144,7 +142,7 @@ class Bar(object):
+ `b`: blank (`charset=" "` override)
"""
ASCII = " 123456789#"
UTF = u" " + u''.join(map(_unich, range(0x258F, 0x2587, -1)))
UTF = u" " + u''.join(map(chr, range(0x258F, 0x2587, -1)))
BLANK = " "
COLOUR_RESET = '\x1b[0m'
COLOUR_RGB = '\x1b[38;2;%d;%d;%dm'
@ -249,6 +247,120 @@ 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.
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
Whether to write bytes. If (default: False) will write 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.
"""
monitor_interval = 10 # set to 0 to disable the thread
@ -279,11 +391,11 @@ class tqdm(Comparable):
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
return f'{num:1.2f}{unit}{suffix}'
return f'{num:2.1f}{unit}{suffix}'
return f'{num:3.0f}{unit}{suffix}'
num /= divisor
return '{0:3.1f}Y'.format(num) + suffix
return f'{num:3.1f}Y{suffix}'
@staticmethod
def format_interval(t):
@ -302,10 +414,7 @@ class tqdm(Comparable):
"""
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)
return f'{h:d}:{m:02d}:{s:02d}' if h else f'{m:02d}:{s:02d}'
@staticmethod
def format_num(n):
@ -322,7 +431,7 @@ class tqdm(Comparable):
out : str
Formatted number.
"""
f = '{0:.3g}'.format(n).replace('+0', '+').replace('-0', '-')
f = f'{n:.3g}'.replace('e+0', 'e+').replace('e-0', 'e-')
n = str(n)
return f if len(f) < len(n) else n
@ -340,7 +449,7 @@ class tqdm(Comparable):
getattr(sys.stdout, 'flush', lambda: None)()
def fp_write(s):
fp.write(_unicode(s))
fp.write(str(s))
fp_flush()
last_len = [0]
@ -442,10 +551,10 @@ class tqdm(Comparable):
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_noinv_fmt = ((format_sizeof(rate) if unit_scale else f'{rate:5.2f}')
if rate else '?') + unit + '/s'
rate_inv_fmt = (
(format_sizeof(inv_rate) if unit_scale else '{0:5.2f}'.format(inv_rate))
(format_sizeof(inv_rate) if unit_scale else f'{inv_rate:5.2f}')
if inv_rate else '?') + 's/' + unit
rate_fmt = rate_inv_fmt if inv_rate and inv_rate > 1 else rate_noinv_fmt
@ -465,7 +574,7 @@ class tqdm(Comparable):
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))
if rate and total else datetime.fromtimestamp(0, timezone.utc))
except OverflowError:
eta_dt = datetime.max
@ -477,26 +586,25 @@ class tqdm(Comparable):
else:
l_bar = ''
r_bar = '| {0}/{1} [{2}<{3}, {4}{5}]'.format(
n_fmt, total_fmt, elapsed_str, remaining_str, rate_fmt, postfix)
r_bar = f'| {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(
format_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,
'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)
'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:
@ -504,7 +612,7 @@ class tqdm(Comparable):
frac = n / total
percentage = frac * 100
l_bar += '{0:3.0f}%|'.format(percentage)
l_bar += f'{percentage:3.0f}%|'
if ncols == 0:
return l_bar[:-1] + r_bar[1:]
@ -513,21 +621,16 @@ class tqdm(Comparable):
if bar_format:
format_dict.update(percentage=percentage)
# auto-remove colon for empty `desc`
# 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
return nobar # no `{bar}`; nothing else to do
# Formatting progress bar space available for bar's display
full_bar = Bar(frac,
@ -535,7 +638,7 @@ class tqdm(Comparable):
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)
bar_format = str(bar_format)
res = bar_format.format(bar=full_bar, **format_dict)
return disp_trim(res, ncols) if ncols else res
@ -554,8 +657,8 @@ class tqdm(Comparable):
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)
return (f'{(prefix + ": ") if prefix else ""}'
f'{n_fmt}{unit} [{elapsed_str}, {rate_fmt}{postfix}]')
def __new__(cls, *_, **__):
instance = object.__new__(cls)
@ -827,6 +930,8 @@ class tqdm(Comparable):
DataFrame.progress_apply = inner_generator()
DataFrameGroupBy.progress_apply = inner_generator()
DataFrame.progress_applymap = inner_generator('applymap')
DataFrame.progress_map = inner_generator('map')
DataFrameGroupBy.progress_map = inner_generator('map')
if Panel is not None:
Panel.progress_apply = inner_generator()
@ -843,133 +948,17 @@ class tqdm(Comparable):
elif _Rolling_and_Expanding is not None:
_Rolling_and_Expanding.progress_apply = inner_generator()
# override defaults via env vars
@envwrap("TQDM_", is_method=True, types={'total': float, 'ncols': int, 'miniters': float,
'position': int, 'nrows': int})
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,
position=None, postfix=None, unit_divisor=1000, write_bytes=False,
lock_args=None, nrows=None, colour=None, delay=0.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,)
"""see tqdm.tqdm for arguments"""
if file is None:
file = sys.stderr
@ -1051,7 +1040,7 @@ class tqdm(Comparable):
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)
bar_format = str(bar_format)
if smoothing is None:
smoothing = 0
@ -1120,9 +1109,6 @@ class tqdm(Comparable):
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
@ -1298,7 +1284,7 @@ class tqdm(Comparable):
# annoyingly, _supports_unicode isn't good enough
def fp_write(s):
self.fp.write(_unicode(s))
self.fp.write(str(s))
try:
fp_write('')
@ -1435,7 +1421,7 @@ class tqdm(Comparable):
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):
elif not isinstance(postfix[key], str):
postfix[key] = str(postfix[key])
# Else if it's a string, don't need to preprocess anything
# Stitch together to get the final postfix
@ -1454,7 +1440,7 @@ class tqdm(Comparable):
def moveto(self, n):
# TODO: private method
self.fp.write(_unicode('\n' * n + _term_move_up() * -n))
self.fp.write('\n' * n + _term_move_up() * -n)
getattr(self.fp, 'flush', lambda: None)()
@property
@ -1534,8 +1520,5 @@ class tqdm(Comparable):
def trange(*args, **kwargs):
"""
A shortcut for tqdm(xrange(*args), **kwargs).
On Python3+ range is used instead of xrange.
"""
return tqdm(_range(*args), **kwargs)
"""Shortcut for tqdm(range(*args), **kwargs)."""
return tqdm(range(*args), **kwargs)

View file

@ -6,22 +6,14 @@ Usage:
>>> 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 warnings import warn
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']
@ -61,7 +53,7 @@ class tqdm_tk(std_tqdm): # pragma: no cover
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)
super().__init__(*args, **kwargs)
if self.disable:
return
@ -143,7 +135,7 @@ class tqdm_tk(std_tqdm): # pragma: no cover
"{bar}", "<bar/>")
msg = self.format_meter(**d)
if '<bar/>' in msg:
msg = "".join(re.split(r'\|?<bar/>\|?', msg, 1))
msg = "".join(re.split(r'\|?<bar/>\|?', msg, maxsplit=1))
self._tk_text_var.set(msg)
if not self._tk_dispatching:
self._tk_window.update()
@ -180,7 +172,7 @@ class tqdm_tk(std_tqdm): # pragma: no cover
self._tk_pbar.configure(maximum=100, mode="indeterminate")
else:
self._tk_pbar.configure(maximum=total, mode="determinate")
super(tqdm_tk, self).reset(total=total)
super().reset(total=total)
@staticmethod
def _tk_dispatching_helper():
@ -195,11 +187,8 @@ class tqdm_tk(std_tqdm): # pragma: no cover
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)
"""Shortcut for `tqdm.tk.tqdm(range(*args), **kwargs)`."""
return tqdm_tk(range(*args), **kwargs)
# Aliases

View file

@ -204,10 +204,8 @@ float, optional.
.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.
Whether to write bytes.
If (default: False) will write unicode.
.RS
.RE
.TP

View file

@ -4,34 +4,17 @@ General helpers required for `tqdm.std`.
import os
import re
import sys
from functools import wraps
from functools import partial, partialmethod, wraps
from inspect import signature
# TODO consider using wcswidth third-party package for 0-width characters
from unicodedata import east_asian_width
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
_range, _unich, _unicode, _basestring = range, chr, str, 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'])
IS_NIX = any(CUR_OS.startswith(i) for i in ['aix', 'linux', 'darwin', 'freebsd'])
RE_ANSI = re.compile(r"\x1b\[[;\d]*[A-Za-z]")
try:
@ -48,10 +31,78 @@ else:
colorama.init()
def envwrap(prefix, types=None, is_method=False):
"""
Override parameter defaults via `os.environ[prefix + param_name]`.
Maps UPPER_CASE env vars map to lower_case param names.
camelCase isn't supported (because Windows ignores case).
Precedence (highest first):
- call (`foo(a=3)`)
- environ (`FOO_A=2`)
- signature (`def foo(a=1)`)
Parameters
----------
prefix : str
Env var prefix, e.g. "FOO_"
types : dict, optional
Fallback mappings `{'param_name': type, ...}` if types cannot be
inferred from function signature.
Consider using `types=collections.defaultdict(lambda: ast.literal_eval)`.
is_method : bool, optional
Whether to use `functools.partialmethod`. If (default: False) use `functools.partial`.
Examples
--------
```
$ cat foo.py
from tqdm.utils import envwrap
@envwrap("FOO_")
def test(a=1, b=2, c=3):
print(f"received: a={a}, b={b}, c={c}")
$ FOO_A=42 FOO_C=1337 python -c 'import foo; foo.test(c=99)'
received: a=42, b=2, c=99
```
"""
if types is None:
types = {}
i = len(prefix)
env_overrides = {k[i:].lower(): v for k, v in os.environ.items() if k.startswith(prefix)}
part = partialmethod if is_method else partial
def wrap(func):
params = signature(func).parameters
# ignore unknown env vars
overrides = {k: v for k, v in env_overrides.items() if k in params}
# infer overrides' `type`s
for k in overrides:
param = params[k]
if param.annotation is not param.empty: # typehints
for typ in getattr(param.annotation, '__args__', (param.annotation,)):
try:
overrides[k] = typ(overrides[k])
except Exception:
pass
else:
break
elif param.default is not None: # type of default value
overrides[k] = type(param.default)(overrides[k])
else:
try: # `types` fallback
overrides[k] = types[k](overrides[k])
except KeyError: # keep unconverted (`str`)
pass
return part(func, **overrides)
return wrap
class FormatReplace(object):
"""
>>> a = FormatReplace('something')
>>> "{:5d}".format(a)
>>> f"{a:5d}"
'something'
""" # NOQA: P102
def __init__(self, replace=''):
@ -116,7 +167,7 @@ class SimpleTextIOWrapper(ObjectWrapper):
"""
# pylint: disable=too-few-public-methods
def __init__(self, wrapped, encoding):
super(SimpleTextIOWrapper, self).__init__(wrapped)
super().__init__(wrapped)
self.wrapper_setattr('encoding', encoding)
def write(self, s):
@ -160,7 +211,7 @@ class DisableOnWriteError(ObjectWrapper):
return inner
def __init__(self, wrapped, tqdm_instance):
super(DisableOnWriteError, self).__init__(wrapped)
super().__init__(wrapped)
if hasattr(wrapped, 'write'):
self.wrapper_setattr(
'write', self.disable_on_exception(tqdm_instance, wrapped.write))
@ -178,7 +229,7 @@ class CallbackIOWrapper(ObjectWrapper):
Wrap a given `file`-like object's `read()` or `write()` to report
lengths to the given `callback`
"""
super(CallbackIOWrapper, self).__init__(stream)
super().__init__(stream)
func = getattr(stream, method)
if method == "write":
@wraps(func)
@ -320,14 +371,8 @@ 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))
return sum(2 if east_asian_width(ch) in 'FW' else 1 for ch in str(s))
def disp_len(data):