diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 733b79998..000000000 --- a/.coveragerc +++ /dev/null @@ -1,11 +0,0 @@ -[run] -branch = True -include = tqdm/* -omit = - tqdm/contrib/bells.py - tqdm/contrib/discord.py - tqdm/contrib/telegram.py - tqdm/contrib/utils_worker.py -relative_files = True -[report] -show_missing = True diff --git a/.gitattributes b/.gitattributes index 1002564bc..0d1f379d9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,4 +7,3 @@ images/ export-ignore benchmarks/ export-ignore asv.conf.json export-ignore -.tqdm.1.md export-ignore diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6788a783a..70f9cc42b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -66,7 +66,11 @@ jobs: shell: bash env: PYVER: ${{ matrix.python }} - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + COVERALLS_FLAG_NAME: py${{ matrix.python }}-${{ matrix.os }} + COVERALLS_PARALLEL: true + COVERALLS_SERVICE_NAME: github + # coveralls needs explicit token + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} test: if: github.event_name != 'pull_request' || github.head_ref != 'devel' @@ -102,12 +106,12 @@ jobs: fi env: PYVER: ${{ matrix.python }} - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + COVERALLS_FLAG_NAME: py${{ matrix.python }} + COVERALLS_PARALLEL: true + COVERALLS_SERVICE_NAME: github + # coveralls needs explicit token + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} - - name: Coveralls Parallel - uses: AndreMiras/coveralls-python-action@develop - with: - parallel: true finish: if: github.event_name != 'pull_request' || github.head_ref != 'devel' name: pytest cov @@ -115,10 +119,19 @@ jobs: needs: [test, test-os] runs-on: ubuntu-latest steps: + - uses: actions/setup-python@v2 - name: Coveralls Finished - uses: AndreMiras/coveralls-python-action@develop - with: - parallel-finished: true + run: | + pip install -U coveralls + coveralls --finish || : + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Codacy Finished + run: | + curl -sfL https://coverage.codacy.com/get.sh > codacy + bash codacy final || : + env: + CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }} deploy: if: github.event_name != 'pull_request' || github.head_ref != 'devel' needs: [check, test, test-os] diff --git a/.meta/.readme.rst b/.meta/.readme.rst index 420908887..26347ef32 100644 --- a/.meta/.readme.rst +++ b/.meta/.readme.rst @@ -658,6 +658,7 @@ Here's an example with ``urllib``: import urllib, os from tqdm import tqdm + urllib = getattr(urllib, 'request', urllib) class TqdmUpTo(tqdm): """Provides `update_to(n)` which uses `tqdm.update(delta_n)`.""" @@ -719,12 +720,14 @@ down to: from tqdm import tqdm eg_link = "https://caspersci.uk.to/matryoshka.zip" + response = getattr(urllib, 'request', urllib).urlopen(eg_link) with tqdm.wrapattr(open(os.devnull, "wb"), "write", - miniters=1, desc=eg_link.split('/')[-1]) as fout: - for chunk in urllib.urlopen(eg_link): + miniters=1, desc=eg_link.split('/')[-1], + total=getattr(response, 'length', None)) as fout: + for chunk in response: fout.write(chunk) -The ``requests`` equivalent is nearly identical, albeit with a ``total``: +The ``requests`` equivalent is nearly identical: .. code:: python diff --git a/.meta/mksnap.py b/.meta/mksnap.py index e06c17613..1b70416f5 100644 --- a/.meta/mksnap.py +++ b/.meta/mksnap.py @@ -5,7 +5,7 @@ import sys from io import open as io_open from os import path -from subprocess import check_output +from subprocess import check_output # nosec sys.path.insert(1, path.dirname(path.dirname(__file__))) import tqdm # NOQA @@ -65,7 +65,7 @@ command: bin/tqdm completer: completion.sh """.format(version=tqdm.__version__, commit=check_output([ - 'git', 'describe', '--always']).decode('U8').strip()) + 'git', 'describe', '--always']).decode('U8').strip()) # nosec fname = path.join(path.dirname(src_dir), 'snapcraft.yaml') if __name__ == "__main__": diff --git a/DEMO.ipynb b/DEMO.ipynb index 9b7ad0895..feaab9389 100644 --- a/DEMO.ipynb +++ b/DEMO.ipynb @@ -10,10 +10,10 @@ "[![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://api.codacy.com/project/badge/Grade/3f965571598f44549c7818f29cdcf177)](https://www.codacy.com/app/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://pypi.org/project/tqdm)\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://pypi.org/project/tqdm)\n", "-|-|-|-|-|-\n", "\n", - "[![DOI](https://img.shields.io/badge/DOI-10.21105/joss.01277-green.svg)](https://doi.org/10.21105/joss.01277)|[![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", + "[![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", "-|-|-|-|-\n", "\n", "`tqdm` derives from the Arabic word *taqaddum* (تقدّم) which can mean\n", @@ -428,7 +428,6 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", " Extra CLI Options\n", " -----------------\n", " delim : chr, optional\n", @@ -440,13 +439,24 @@ " bytes : bool, optional\n", " If true, will count bytes, ignore `delim`, and default\n", " `unit_scale` to True, `unit_divisor` to 1024, and `unit` to 'B'.\n", + " tee : bool, optional\n", + " If true, passes `stdin` to both `stderr` and `stdout`.\n", + " update : bool, optional\n", + " If true, will treat input as newly elapsed iterations,\n", + " i.e. numbers to pass to `update()`. Note that this is slow\n", + " (~2e5 it/s) since every input must be decoded as a number.\n", + " update_to : bool, optional\n", + " If true, will treat input as total elapsed iterations,\n", + " i.e. numbers to assign to `self.n`. Note that this is slow\n", + " (~2e5 it/s) since every input must be decoded as a number.\n", + " null : bool, optional\n", + " If true, will discard input (no stdout).\n", " manpath : str, optional\n", " Directory in which to install tqdm man pages.\n", " comppath : str, optional\n", " Directory in which to place tqdm completion.\n", " log : str, optional\n", - " CRITICAL|FATAL|ERROR|WARN(ING)|[default: 'INFO']|DEBUG|NOTSET.\n", - "\n" + " CRITICAL|FATAL|ERROR|WARN(ING)|[default: 'INFO']|DEBUG|NOTSET.\n" ] } ], @@ -533,7 +543,15 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "00:00 in total: 44%|0000. | 4/9 [00:00<00:00, 29799.67it/s]\n" + ] + } + ], "source": [ "from tqdm import tqdm\n", "from time import sleep\n", @@ -690,6 +708,7 @@ "source": [ "import urllib, os\n", "from tqdm import tqdm\n", + "urllib = getattr(urllib, 'request', urllib)\n", "\n", "class TqdmUpTo(tqdm):\n", " \"\"\"Provides `update_to(n)` which uses `tqdm.update(delta_n)`.\"\"\"\n", @@ -760,7 +779,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "matryoshka.zip: 254kB [00:00, 334kB/s] \n" + "matryoshka.zip: 100%|██████████| 254k/254k [00:00<00:00, 602kB/s] \n" ] } ], @@ -769,9 +788,11 @@ "from tqdm import tqdm\n", "\n", "eg_link = \"https://caspersci.uk.to/matryoshka.zip\"\n", + "response = getattr(urllib, 'request', urllib).urlopen(eg_link)\n", "with tqdm.wrapattr(open(os.devnull, \"wb\"), \"write\",\n", - " miniters=1, desc=eg_link.split('/')[-1]) as fout:\n", - " for chunk in urllib.urlopen(eg_link):\n", + " miniters=1, desc=eg_link.split('/')[-1],\n", + " total=getattr(response, 'length', None)) as fout:\n", + " for chunk in response:\n", " fout.write(chunk)" ] }, @@ -779,7 +800,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The `requests` equivalent is nearly identical, albeit with a `total`:" + "The `requests` equivalent is nearly identical:" ] }, { @@ -1659,11 +1680,6 @@ "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", - "---\n", - "\n", - "[![sourcerer-0](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/images/0)](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/links/0)|[![sourcerer-1](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/images/1)](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/links/1)|[![sourcerer-2](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/images/2)](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/links/2)|[![sourcerer-3](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/images/3)](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/links/3)|[![sourcerer-4](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/images/4)](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/links/4)|[![sourcerer-5](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/images/5)](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/links/5)|[![sourcerer-7](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/images/7)](https://sourcerer.io/fame/casperdcl/tqdm/tqdm/links/7)\n", - "-|-|-|-|-|-|-\n", - "\n", "[![README-Hits](https://caspersci.uk.to/cgi-bin/hits.cgi?q=tqdm&style=social&r=https://github.com/tqdm/tqdm&l=https://caspersci.uk.to/images/tqdm.png&f=https://raw.githubusercontent.com/tqdm/tqdm/master/images/logo.gif)](https://caspersci.uk.to/cgi-bin/hits.cgi?q=tqdm&a=plot&r=https://github.com/tqdm/tqdm&l=https://caspersci.uk.to/images/tqdm.png&f=https://raw.githubusercontent.com/tqdm/tqdm/master/images/logo.gif&style=social)|(Since 19 May 2016)\n", "-|-" ] @@ -1692,21 +1708,21 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.15" + "pygments_lexer": "ipython3", + "version": "3.7.8" } }, "nbformat": 4, diff --git a/examples/7zx.py b/examples/7zx.py index 892dcf764..c5bc28b7e 100644 --- a/examples/7zx.py +++ b/examples/7zx.py @@ -25,7 +25,7 @@ import os import pty import re -import subprocess +import subprocess # nosec from argopt import argopt @@ -51,7 +51,7 @@ def main(): # Get compressed sizes zips = {} for fn in args.zipfiles: - info = subprocess.check_output(["7z", "l", fn]).strip() + info = subprocess.check_output(["7z", "l", fn]).strip() # nosec finfo = RE_SCN.findall(info) # size|compressed|name # builtin test: last line should be total sizes @@ -81,7 +81,7 @@ def main(): cmd7zx + [fn], bufsize=1, stdout=md, # subprocess.PIPE, - stderr=subprocess.STDOUT) + stderr=subprocess.STDOUT) # nosec os.close(sd) with io.open(md, mode="rU", buffering=1) as m: with tqdm(total=sum(fcomp.values()), disable=len(zips) < 2, diff --git a/examples/parallel_bars.py b/examples/parallel_bars.py index 2e8a9c3b8..498fd61df 100644 --- a/examples/parallel_bars.py +++ b/examples/parallel_bars.py @@ -16,7 +16,7 @@ def progresser(n, auto_position=True, write_safe=False, blocking=True, progress=False): - interval = random() * 0.002 / (NUM_SUBITERS - n + 2) + interval = random() * 0.002 / (NUM_SUBITERS - n + 2) # nosec total = 5000 text = "#{0}, est. {1:<04.2}s".format(n, interval * total) for _ in trange(total, desc=text, disable=not progress, diff --git a/examples/tqdm_wget.py b/examples/tqdm_wget.py index 695e5e5a1..8663e5a39 100644 --- a/examples/tqdm_wget.py +++ b/examples/tqdm_wget.py @@ -20,7 +20,10 @@ The local file path in which to save the url [default: /dev/null]. """ -import urllib +try: + from urllib import request as urllib +except ImportError: # py2 + import urllib from os import devnull from docopt import docopt @@ -97,12 +100,14 @@ def update_to(self, b=1, bsize=1, tsize=None): # reporthook=my_hook(t), data=None) with TqdmUpTo(unit='B', unit_scale=True, unit_divisor=1024, miniters=1, desc=eg_file) as t: # all optional kwargs - urllib.urlretrieve(eg_link, filename=eg_out, reporthook=t.update_to, - data=None) + urllib.urlretrieve( # nosec + eg_link, filename=eg_out, reporthook=t.update_to, data=None) t.total = t.n # Even simpler progress by wrapping the output file's `write()` +response = urllib.urlopen(eg_link) # nosec with tqdm.wrapattr(open(eg_out, "wb"), "write", - miniters=1, desc=eg_file) as fout: - for chunk in urllib.urlopen(eg_link): + miniters=1, desc=eg_file, + total=getattr(response, 'length', None)) as fout: + for chunk in response: fout.write(chunk) diff --git a/setup.cfg b/setup.cfg index a59700ddb..9994cb1f4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -118,3 +118,15 @@ markers= python_files=tests_*.py testpaths=tests addopts=-v --tb=short -rxs -W=error --durations=0 --durations-min=0.1 + +[coverage:run] +branch=True +include=tqdm/* +omit= + tqdm/contrib/bells.py + tqdm/contrib/discord.py + tqdm/contrib/telegram.py + tqdm/contrib/utils_worker.py +relative_files=True +[coverage:report] +show_missing=True diff --git a/setup.py b/setup.py index ba21964b7..89dadf581 100755 --- a/setup.py +++ b/setup.py @@ -1,14 +1,14 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import os import sys +from os import path from setuptools import setup -src_dir = os.path.abspath(os.path.dirname(__file__)) +src_dir = path.abspath(path.dirname(__file__)) if sys.argv[1].lower().strip() == 'make': # exec Makefile commands import pymake - fpath = os.path.join(src_dir, 'Makefile') + 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) diff --git a/tests/tests_main.py b/tests/tests_main.py index 44d0b7878..aa477e5b5 100644 --- a/tests/tests_main.py +++ b/tests/tests_main.py @@ -1,6 +1,6 @@ """Test CLI usage.""" import logging -import subprocess +import subprocess # nosec import sys from functools import wraps from os import linesep @@ -34,11 +34,11 @@ def norm(bytestr): @mark.slow def test_pipes(): """Test command line pipes""" - ls_out = subprocess.check_output(['ls']) - ls = subprocess.Popen(['ls'], stdout=subprocess.PIPE) + ls_out = subprocess.check_output(['ls']) # nosec + ls = subprocess.Popen(['ls'], stdout=subprocess.PIPE) # nosec res = subprocess.Popen( [sys.executable, '-c', 'from tqdm.cli import main; main()'], - stdin=ls.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdin=ls.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # nosec out, err = res.communicate() assert ls.poll() == 0 diff --git a/tests/tests_tqdm.py b/tests/tests_tqdm.py index dd33cc502..56033fef9 100644 --- a/tests/tests_tqdm.py +++ b/tests/tests_tqdm.py @@ -1,6 +1,7 @@ # -*- 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 @@ -1722,8 +1723,14 @@ def test_file_redirection(): with closing(StringIO()) as our_file: # Redirect stdout to tqdm.write() with std_out_err_redirect_tqdm(tqdm_file=our_file): - for _ in trange(3): + with tqdm(total=3) as pbar: print("Such fun") + pbar.update(1) + print("Such", "fun") + pbar.update(1) + print("Such ", end="") + print("fun") + pbar.update(1) res = our_file.getvalue() assert res.count("Such fun\n") == 3 assert "0/3" in res diff --git a/tox.ini b/tox.ini index dfce1650e..99a7c6dad 100644 --- a/tox.ini +++ b/tox.ini @@ -5,14 +5,14 @@ [tox] # deprecation warning: py{34} -envlist=py{27,34,35,36,37,38,39,py2,py3}{,-tf}{,-keras}, perf, flake8, setup.py +envlist=py{27,34,35,36,37,38,39,py2,py3}{,-tf}{,-keras}, perf, setup.py isolated_build=True [coverage] commands= - coveralls - codecov - - codacy report -r coverage.xml + codecov -X pycov -e TOXENV + - codacy report -l Python -r coverage.xml --partial [extra] deps= @@ -29,7 +29,7 @@ commands= allowlist_externals=codacy [testenv] -passenv=CI TOXENV CODECOV_* COVERALLS_* CODACY_* HOME +passenv=CI GITHUB_* TOXENV CODECOV_* COVERALLS_* CODACY_* HOME deps= {[extra]deps} cython diff --git a/tqdm/auto.py b/tqdm/auto.py index 370c180d6..28bc722da 100644 --- a/tqdm/auto.py +++ b/tqdm/auto.py @@ -30,7 +30,7 @@ from .std import tqdm as std_tqdm if notebook_tqdm != std_tqdm: - class tqdm(notebook_tqdm, asyncio_tqdm): + class tqdm(notebook_tqdm, asyncio_tqdm): # pylint: disable=inconsistent-mro pass else: tqdm = asyncio_tqdm diff --git a/tqdm/cli.py b/tqdm/cli.py index 7b7338458..b5a16142b 100644 --- a/tqdm/cli.py +++ b/tqdm/cli.py @@ -263,7 +263,7 @@ def cp(src, dst): stdout_write = stdout.write fp_write = getattr(fp, 'buffer', fp).write - class stdout(object): + class stdout(object): # pylint: disable=function-redefined @staticmethod def write(x): with tqdm.external_write_mode(file=fp): diff --git a/tqdm/contrib/__init__.py b/tqdm/contrib/__init__.py index f9dfa1713..8a6d2474c 100644 --- a/tqdm/contrib/__init__.py +++ b/tqdm/contrib/__init__.py @@ -16,10 +16,28 @@ class DummyTqdmFile(ObjectWrapper): """Dummy file-like that will write to tqdm""" + def __init__(self, wrapped): + super(DummyTqdmFile, self).__init__(wrapped) + self._buf = [] + def write(self, x, nolock=False): - # Avoid print() second call (useless \n) - if len(x.rstrip()) > 0: - tqdm.write(x, file=self._wrapped, nolock=nolock) + nl = b"\n" if isinstance(x, bytes) else "\n" + pre, sep, post = x.rpartition(nl) + if sep: + blank = type(nl)() + tqdm.write(blank.join(self._buf + [pre, sep]), + end=blank, file=self._wrapped, nolock=nolock) + self._buf = [post] + else: + self._buf.append(x) + + def __del__(self): + if self._buf: + blank = type(self._buf[0])() + try: + tqdm.write(blank.join(self._buf), end=blank, file=self._wrapped) + except (OSError, ValueError): + pass def builtin_iterable(func): diff --git a/tqdm/std.py b/tqdm/std.py index 17bc5c6ff..e73f4ab67 100644 --- a/tqdm/std.py +++ b/tqdm/std.py @@ -696,11 +696,15 @@ def pandas(cls, **tqdm_kwargs): """ + from warnings import catch_warnings, simplefilter + from pandas.core.frame import DataFrame from pandas.core.series import Series try: - from pandas import Panel - except ImportError: # TODO: pandas>0.25.2 + with catch_warnings(): + simplefilter("ignore", category=FutureWarning) + from pandas import Panel + except ImportError: # pandas>=1.2.0 Panel = None Rolling, Expanding = None, None try: # pandas>=1.0.0 @@ -718,14 +722,14 @@ def pandas(cls, **tqdm_kwargs): try: # pandas>=0.25.0 from pandas.core.groupby.generic import SeriesGroupBy # , NDFrameGroupBy from pandas.core.groupby.generic import DataFrameGroupBy - except ImportError: + except ImportError: # pragma: no cover try: # pandas>=0.23.0 from pandas.core.groupby.groupby import DataFrameGroupBy, SeriesGroupBy except ImportError: from pandas.core.groupby import DataFrameGroupBy, SeriesGroupBy try: # pandas>=0.23.0 from pandas.core.groupby.groupby import GroupBy - except ImportError: + except ImportError: # pragma: no cover from pandas.core.groupby import GroupBy try: # pandas>=0.23.0 diff --git a/tqdm/utils.py b/tqdm/utils.py index 96c710f86..aae87e454 100644 --- a/tqdm/utils.py +++ b/tqdm/utils.py @@ -3,7 +3,6 @@ """ import os import re -import subprocess import sys from functools import wraps from warnings import warn @@ -254,7 +253,7 @@ def _screen_shape_windows(fp): # pragma: no cover (_bufx, _bufy, _curx, _cury, _wattr, left, top, right, bottom, _maxx, _maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw) return right - left, bottom - top # +1 - except Exception: + except Exception: # nosec pass return None, None @@ -263,9 +262,10 @@ def _screen_shape_tput(*_): # pragma: no cover """cygwin xterm (windows)""" try: import shlex - return [int(subprocess.check_call(shlex.split('tput ' + i))) - 1 + from subprocess import check_call # nosec + return [int(check_call(shlex.split('tput ' + i))) - 1 for i in ('cols', 'lines')] - except Exception: + except Exception: # nosec pass return None, None