diff --git a/.travis.yml b/.travis.yml index b5097753..3694df63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,16 @@ language: python -python: 2.7 -env: -- TOXENV=py26 -- TOXENV=py27 -- TOXENV=py32 -- TOXENV=py33 -- TOXENV=py34 -- TOXENV=pypy -- TOXENV=pypy3 + +python: + - "2.7" + - "3.4" + install: -- pip install tox + - pip install nose flake8 coverage python-coveralls + - pip install . + script: -- tox + - make flake8 + - make coverage + +after_success: + - coveralls diff --git a/MANIFEST b/MANIFEST deleted file mode 100644 index 7cd0a5d2..00000000 --- a/MANIFEST +++ /dev/null @@ -1,3 +0,0 @@ -# file GENERATED by distutils, do NOT edit -setup.py -tqdm.py diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..a1cca4a2 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +.PHONY: test flake8 coverage clean + +help: + @echo "Please use make where is one of" + @echo " test : run tests" + @echo " flake8 : run flake8 to check PEP8" + @echo " coverage : run tests and check code coverage" + @echo " clean : clean current repository" + +test: + nosetests tqdm/ -v + +flake8: + flake8 --exclude "test_*" --max-line-length=100 --count --statistics --exit-zero tqdm/ + +coverage: + nosetests --with-coverage --cover-package=tqdm -v tqdm/ + +clean: + find . -name "*.so" -exec rm -rf {} \; + find . -name "*.pyc" -exec rm -rf {} \; + find . -depth -name "__pycache__" -type d -exec rm -rf '{}' \; + rm -rf build/ dist/ tqdm.egg-info/ diff --git a/README.md b/README.md index b749ccf6..c0055983 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,49 @@ -tqdm -==== +# tqdm -[![Build Status](https://img.shields.io/travis/kmike/tqdm.svg?branch=all-fixes)](https://travis-ci.org/kmike/tqdm) +[![Build Status](https://travis-ci.org/tqdm/tqdm.svg?branch=master)](https://travis-ci.org/tqdm/tqdm) +[![Coverage Status](https://coveralls.io/repos/tqdm/tqdm/badge.svg)](https://coveralls.io/r/tqdm/tqdm) -Instantly make your loops show a progress meter - just wrap any iterable with "tqdm(iterable)", and you're done! - -![ScreenShot](https://i.imgur.com/he9Aw5C.gif) +Instantly make your loops show a progress meter - just wrap any iterable with "tqdm(iterable)", and you're done ! tqdm (read taqadum, تقدّم) means "progress" in arabic. +![ScreenShot](tqdm.gif) + You can also use trange(N) as a shortcut for tqdm(xrange(N)) -Here's the doc: +## Installation + +```sh +pip install tqdm +# or +pip install -e git+https://github.com/tqdm/tqdm.git#egg=master +``` + +## Documentation ```python -def tqdm(iterable, desc='', total=None, leave=False, mininterval=0.5, miniters=1): - """ - Get an iterable object, and return an iterator which acts exactly like the +def tqdm(iterable, desc='', total=None, + leave=False, file=sys.stderr, + min_interval=0.5, miniters=1): + + """Get an iterable object, and return an iterator which acts exactly like the iterable, but prints a progress meter and updates it every time a value is requested. - 'desc' can contain a short string, describing the progress, that is added - in the beginning of the line. - 'total' can give the number of expected iterations. If not given, - len(iterable) is used if it is defined. - If leave is False, tqdm deletes its traces from screen after it has finished - iterating over all elements. - If less than mininterval seconds or miniters iterations have passed since - the last progress meter update, it is not updated again. + + Parameters + ---------- + desc: str + A short string, describing the progress, that is added in the beginning of the line. + total : int + The number of expected iterations. If not given, len(iterable) is used if it is defined. + file : `io.TextIOWrapper` or `io.StringIO` + A file-like object to output the progress message to. + leave : bool + If it is False, tqdm deletes its traces from screen after it has finished iterating over + all elements. + min_interval : float + If less than min_interval seconds or miniters iterations have passed since the last + progress meter update, it is not updated again. """ def trange(*args, **kwargs): @@ -34,8 +51,24 @@ def trange(*args, **kwargs): return tqdm(xrange(*args), **kwargs) ``` -Running tests -------------- +## Contributions -Please make sure tox (http://tox.testrun.org/) is installed and type -`tox` from the command line. +During development you may want to use these commands : + +```sh +$ make help +Please use make where is one of + test : run tests + flake8 : run flake8 to check PEP8 + coverage : run tests and check code coverage + clean : clean current repository +``` + +## License + +[MIT LICENSE](LICENSE). + + +## Authors + +- noamraph (original author) diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 87226211..00000000 --- a/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -python_files = test*.py diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 2a9acf13..00000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[bdist_wheel] -universal = 1 diff --git a/setup.py b/setup.py index 2b9a035f..a3f8f146 100644 --- a/setup.py +++ b/setup.py @@ -4,12 +4,12 @@ from setuptools import setup setup( name='tqdm', - version='1.0', + version='2.0', description='A Simple Python Progress Meter', license='MIT License', author='Noam Yorav-Raphael', author_email='noamraph@gmail.com', - url='https://github.com/noamraph/tqdm', + url='https://github.com/tqdm/tqdm', py_modules=['tqdm'], classifiers=[ 'Development Status :: 5 - Production/Stable', diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 00fd9477..00000000 --- a/tox.ini +++ /dev/null @@ -1,13 +0,0 @@ -# Tox (http://tox.testrun.org/) is a tool for running tests -# in multiple virtualenvs. This configuration file will run the -# test suite on all supported python versions. To use it, "pip install tox" -# and then run "tox" from this directory. - -[tox] -envlist = py26, py27, py32, py33, py34, pypy, pypy3 - -[testenv] -commands = py.test -deps = - six - pytest diff --git a/tqdm.gif b/tqdm.gif new file mode 100644 index 00000000..a5c13275 Binary files /dev/null and b/tqdm.gif differ diff --git a/tqdm/__init__.py b/tqdm/__init__.py new file mode 100644 index 00000000..f8953cd4 --- /dev/null +++ b/tqdm/__init__.py @@ -0,0 +1,6 @@ +from ._tqdm import tqdm +from ._tqdm import trange +from ._tqdm import format_interval +from ._tqdm import format_meter + +__all__ = ['tqdm', 'trange', 'format_interval', 'format_meter'] diff --git a/tqdm.py b/tqdm/_tqdm.py similarity index 72% rename from tqdm.py rename to tqdm/_tqdm.py index 14fcbe5c..10fe4873 100644 --- a/tqdm.py +++ b/tqdm/_tqdm.py @@ -4,7 +4,7 @@ import sys import time -__all__ = ['tqdm', 'trange'] +__all__ = ['tqdm', 'trange', 'format_interval', 'format_meter'] def format_interval(t): @@ -22,24 +22,24 @@ def format_meter(n, total, elapsed): # elapsed - number of seconds passed since start if total and n > total: total = None - + elapsed_str = format_interval(elapsed) rate = '%5.2f' % (n / elapsed) if elapsed else '?' - + if total: frac = float(n) / total - + N_BARS = 10 bar_length = int(frac*N_BARS) bar = '#'*bar_length + '-'*(N_BARS-bar_length) - + percentage = '%3d%%' % (frac * 100) - + left_str = format_interval(elapsed / n * (total-n)) if n else '?' - + return '|%s| %d/%d %s [elapsed: %s left: %s, %s iters/sec]' % ( bar, n, total, percentage, elapsed_str, left_str, rate) - + else: return '%d [elapsed: %s, %s iters/sec]' % (n, elapsed_str, rate) @@ -48,40 +48,46 @@ class StatusPrinter(object): def __init__(self, file): self.file = file self.last_printed_len = 0 - + def print_status(self, s): self.file.write('\r'+s+' '*max(self.last_printed_len-len(s), 0)) self.file.flush() self.last_printed_len = len(s) -def tqdm(iterable, desc='', total=None, leave=False, file=sys.stderr, - mininterval=0.5, miniters=1): - """ - Get an iterable object, and return an iterator which acts exactly like the +def tqdm(iterable, desc='', total=None, + leave=False, file=sys.stderr, + min_interval=0.5, miniters=1): + """Get an iterable object, and return an iterator which acts exactly like the iterable, but prints a progress meter and updates it every time a value is requested. - 'desc' can contain a short string, describing the progress, that is added - in the beginning of the line. - 'total' can give the number of expected iterations. If not given, - len(iterable) is used if it is defined. - 'file' can be a file-like object to output the progress message to. - If leave is False, tqdm deletes its traces from screen after it has - finished iterating over all elements. - If less than mininterval seconds or miniters iterations have passed since - the last progress meter update, it is not updated again. + + Parameters + ---------- + desc: str + A short string, describing the progress, that is added in the beginning of the line. + total : int + The number of expected iterations. If not given, len(iterable) is used if it is defined. + file : `io.TextIOWrapper` or `io.StringIO` + A file-like object to output the progress message to. + leave : bool + If it is False, tqdm deletes its traces from screen after it has finished iterating over + all elements. + min_interval : float + If less than min_interval seconds or miniters iterations have passed since the last + progress meter update, it is not updated again. """ if total is None: try: total = len(iterable) except (TypeError, AttributeError): total = None - + prefix = desc+': ' if desc else '' - + sp = StatusPrinter(file) sp.print_status(prefix + format_meter(0, total, 0)) - + start_t = last_print_t = time.time() last_print_n = 0 n = 0 @@ -92,11 +98,11 @@ def tqdm(iterable, desc='', total=None, leave=False, file=sys.stderr, if n - last_print_n >= miniters: # We check the counter first, to reduce the overhead of time.time() cur_t = time.time() - if cur_t - last_print_t >= mininterval: + if cur_t - last_print_t >= min_interval: sp.print_status(prefix + format_meter(n, total, cur_t-start_t)) last_print_n = n last_print_t = cur_t - + if not leave: sp.print_status('') sys.stdout.write('\r') @@ -113,5 +119,5 @@ def trange(*args, **kwargs): f = xrange except NameError: f = range - + return tqdm(f(*args), **kwargs) diff --git a/tests.py b/tqdm/tests/tests_tqdm.py similarity index 67% rename from tests.py rename to tqdm/tests/tests_tqdm.py index c377bf14..25f7aaba 100644 --- a/tests.py +++ b/tqdm/tests/tests_tqdm.py @@ -1,8 +1,16 @@ from __future__ import unicode_literals import csv -from six import StringIO -from tqdm import format_interval, format_meter, tqdm + +try: + from StringIO import StringIO +except: + from io import StringIO + +from tqdm import format_interval +from tqdm import format_meter +from tqdm import tqdm +from tqdm import trange def test_format_interval(): @@ -18,6 +26,8 @@ def test_format_meter(): assert format_meter(231, 1000, 392) == \ "|##--------| 231/1000 23% [elapsed: " \ "06:32 left: 21:44, 0.59 iters/sec]" + assert format_meter(10000, 1000, 13) == \ + "10000 [elapsed: 00:13, 769.23 iters/sec]" def test_nothing_fails(): @@ -67,3 +77,27 @@ def test_leave_option(): our_file2.seek(0) assert '3/3 100%' not in our_file2.read() our_file2.close() + + +def test_trange(): + our_file = StringIO() + for i in trange(3, file=our_file, leave=True): + pass + our_file.seek(0) + assert '3/3 100%' in our_file.read() + our_file.close() + + our_file2 = StringIO() + for i in trange(3, file=our_file2, leave=False): + pass + our_file2.seek(0) + assert '3/3 100%' not in our_file2.read() + our_file2.close() + + +def test_min_interval(): + our_file = StringIO() + for i in tqdm(range(3), file=our_file, min_interval=1e-10): + pass + our_file.seek(0) + assert "|----------| 0/3 0% [elapsed: 00:00 left" in our_file.read()