From bee450d951333c56194e0ed876f4d7c0a4403ff0 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Tue, 13 Oct 2015 15:15:11 +0200 Subject: [PATCH 01/21] add new commands to Makefile + updated CONTRIBUTE and RELEASE Signed-off-by: Stephen L. --- CONTRIBUTE | 12 ++++++++---- Makefile | 24 +++++++++++++++++++++++- RELEASE | 15 ++++++++------- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTE b/CONTRIBUTE index 503166e4..345c0684 100644 --- a/CONTRIBUTE +++ b/CONTRIBUTE @@ -4,6 +4,9 @@ HOW TO CONTRIBUTE TO TQDM This file describes how to contribute changes to the project, and how to upload to the pypi repository. +Most of the management commands have been directly placed inside +the Makefile, so you just have to run `make [alias]`. + HOW TO COMMIT YOUR CONTRIBUTIONS -------------------------------- @@ -34,12 +37,10 @@ To run the tests, - install `tox` - `cd` to the root of the `tqdm` directory (in the same folder as this file) -- run the following commands: +- run the following command: ``` -make test -make coverage -make flake8 +make alltests ``` Alternatively (if you can't use `make`) @@ -51,3 +52,6 @@ Alternatively (if you can't use `make`) nosetests --with-coverage --cover-package=tqdm -v tqdm/ python -m flake8 tqdm/_tqdm.py ``` + +Then wait for the tests to finish, and check your console to see if there's +any issue. diff --git a/Makefile b/Makefile index 65572c9e..cc4a19d4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ .PHONY: all flake8 test coverage -all: flake8 coverage +alltests: test coverage flake8 testsetup +all: alltests build + flake8: flake8 --max-line-length=80 --count --statistics --exit-zero tqdm/ flake8 --max-line-length=80 --count --statistics --exit-zero examples/ @@ -8,5 +10,25 @@ flake8: test: nosetests tqdm -v +testsetup: + python setup.py check --restructuredtext --strict + coverage: nosetests tqdm --with-coverage --cover-package=tqdm -v + +installdev: + python setup.py develop --uninstall + python setup.py develop + +install: + python setup.py install + +build: + python setup.py sdist --formats=gztar,zip bdist_wininst + python setup.py sdist bdist_wheel + +pypimeta: + python setup.py register + +pypi: + twine upload dist/* diff --git a/RELEASE b/RELEASE index 9084d7d3..f62a20d4 100644 --- a/RELEASE +++ b/RELEASE @@ -4,6 +4,9 @@ HOW TO MANAGE A NEW RELEASE This file is intended for the project's maintainers and it describes how to update, build and upload a new release. +Most of the management commands have been directly placed inside +the Makefile, so you just have to run `make [alias]`. + SEMANTIC VERSIONING ------------------- @@ -34,7 +37,7 @@ python setup.py check --restructuredtext --strict ``` Also, if you happen to mistakenly upload a broken release to PyPi, -you can fix the metadata by using: `python setup.py register`. +you can fix the metadata by using: `make pypimeta` or `python setup.py register` BUILDING A RELEASE AND UPLOADING TO PYPI @@ -46,15 +49,13 @@ process and info that will be uploaded to [pypi](pypi.python.org). Check the result by using the following commands: ``` -python setup.py develop --uninstall -python setup.py develop +make installdev ``` Secondly, build tqdm into a distributable python package: ``` -python setup.py sdist --formats=gztar,zip bdist_wininst --plat-name=win32 -python setup.py sdist bdist_wheel --plat-name=win32 +make build ``` This will generate several builds in the `dist/` folder. @@ -63,7 +64,7 @@ Finally, we can upload everything to pypi. Uploading to pypi can be done easily using the [twine](https://github.com/pypa/twine) module: ``` -twine upload dist/* +make pypi ``` NOTE: @@ -74,7 +75,7 @@ before the real deployment cannot re-upload another with the same version number! - in case of a mistake in the metadata on pypi (like the long description README getting garbled because of a silent error), you can use the following -command to update the metadata: `python setup.py register` +command to update the metadata: `make pypimeta` or `python setup.py register` Also, the new release can be added to the Github by creating a new release from the web interface. From e387fea4224b4785115e10c68c50a7935e437ed4 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Tue, 13 Oct 2015 15:25:12 +0200 Subject: [PATCH 02/21] add note: how to use Makefile on Windows Signed-off-by: Stephen L. --- CONTRIBUTE | 3 +++ RELEASE | 3 +++ 2 files changed, 6 insertions(+) diff --git a/CONTRIBUTE b/CONTRIBUTE index 345c0684..ec077e62 100644 --- a/CONTRIBUTE +++ b/CONTRIBUTE @@ -7,6 +7,9 @@ upload to the pypi repository. Most of the management commands have been directly placed inside the Makefile, so you just have to run `make [alias]`. +Note: to use the Makefile on Windows, you need to install make.exe, +for example by installing [MinGW MSYS](http://www.mingw.org/wiki/msys). + HOW TO COMMIT YOUR CONTRIBUTIONS -------------------------------- diff --git a/RELEASE b/RELEASE index f62a20d4..03928fd8 100644 --- a/RELEASE +++ b/RELEASE @@ -7,6 +7,9 @@ how to update, build and upload a new release. Most of the management commands have been directly placed inside the Makefile, so you just have to run `make [alias]`. +Note: to use the Makefile on Windows, you need to install make.exe, +for example by installing [MinGW MSYS](http://www.mingw.org/wiki/msys). + SEMANTIC VERSIONING ------------------- From 088d4beb7da023a30040a6fc03f44923c41f4464 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Tue, 13 Oct 2015 15:34:14 +0200 Subject: [PATCH 03/21] fix redundant test Signed-off-by: Stephen L. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cc4a19d4..99b81b4a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: all flake8 test coverage -alltests: test coverage flake8 testsetup +alltests: testcoverage flake8 testsetup all: alltests build flake8: @@ -13,7 +13,7 @@ test: testsetup: python setup.py check --restructuredtext --strict -coverage: +testcoverage: nosetests tqdm --with-coverage --cover-package=tqdm -v installdev: From 3266adcbf8d9bab67282531918878cf3718b9071 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Tue, 13 Oct 2015 22:49:20 +0200 Subject: [PATCH 04/21] Nose is the default unittest when `python setup.py test` Signed-off-by: Stephen L. --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 6d372580..d3f6e556 100755 --- a/setup.py +++ b/setup.py @@ -49,4 +49,6 @@ setup( 'Intended Audience :: Developers', ], keywords = 'progressbar progressmeter progress bar meter rate eta console terminal time', + test_suite='nose.collector', + tests_require=['nose', 'flake8', 'coverage'], ) From 405dd64bae751743da0e82ed0727e2cf573d6c3a Mon Sep 17 00:00:00 2001 From: Stephen L Date: Tue, 13 Oct 2015 22:49:38 +0200 Subject: [PATCH 05/21] Add tox infos Signed-off-by: Stephen L. --- CONTRIBUTE | 13 ++++++++++++- Makefile | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTE b/CONTRIBUTE index ec077e62..1b06d0ea 100644 --- a/CONTRIBUTE +++ b/CONTRIBUTE @@ -36,7 +36,7 @@ TESTING To test functionality on your machine (such as before submitting a Pull Request), there are a number of unit tests. -To run the tests, +To run the tests for only your Python distribution: - install `tox` - `cd` to the root of the `tqdm` directory (in the same folder as this file) @@ -56,5 +56,16 @@ nosetests --with-coverage --cover-package=tqdm -v tqdm/ python -m flake8 tqdm/_tqdm.py ``` +To run the tests for all Python distributions (better, but more time consuming): + +- install `tox` +- install all versions of the Python interpreter that are specified in +[tox.ini](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. +- `cd` to the root of the `tqdm` directory (in the same folder as this file) +- run the following command: `tox` + Then wait for the tests to finish, and check your console to see if there's any issue. diff --git a/Makefile b/Makefile index 99b81b4a..2f022455 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,8 @@ testsetup: testcoverage: nosetests tqdm --with-coverage --cover-package=tqdm -v +allenvtests: tox + installdev: python setup.py develop --uninstall python setup.py develop From f4c3b2bc1e7b34bc92216fa02c0985d57e1bae16 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Tue, 13 Oct 2015 22:49:19 +0100 Subject: [PATCH 06/21] removed travis double-check as per comment in #42 --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 75733fc8..e8bd12f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ sudo: false language: python python: 3.4 +branches: + only: + - master + - /^\d\.\d+$/ env: - TOXENV=py26 - TOXENV=py27 From ec3d315d181338c49b966b5e14a92d9fb215c315 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Wed, 14 Oct 2015 00:42:01 +0200 Subject: [PATCH 07/21] Make tox the main unit test + Added more tests in tox Signed-off-by: Stephen L. --- CONTRIBUTE | 56 ++++++++++++++++++++++++------------- Makefile | 5 ++-- examples/simple_examples.py | 24 ++++++++-------- tox.ini | 10 +++++-- 4 files changed, 60 insertions(+), 35 deletions(-) diff --git a/CONTRIBUTE b/CONTRIBUTE index 1b06d0ea..1d8e4496 100644 --- a/CONTRIBUTE +++ b/CONTRIBUTE @@ -36,36 +36,54 @@ TESTING To test functionality on your machine (such as before submitting a Pull Request), there are a number of unit tests. -To run the tests for only your Python distribution: + +Standard unit testing +~~~~~~~~~~~~~~~~ + +The standard way to run the tests: - install `tox` - `cd` to the root of the `tqdm` directory (in the same folder as this file) - run the following command: +``` +make test +``` + +or + +``` +tox --skip-missing-interpreters +``` + +This will build the module and run the tests in a virtualized environment. +Wait a bit for tests to complete, and check the console/log for any error and +also check the coverage rate. Do not care about missing interpreters errors, +this is because tox tries to run the tests on several versions of Python and you +don't have them installed. + +Note: to install all versions of the Python interpreter that are specified in +[tox.ini](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. + + +Alternative unit testing with Nose +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Alternatively, you can use `nose` to run the tests just for your Python version: + +- install `nose` and `flake8` +- run the following commands: + ``` make alltests ``` -Alternatively (if you can't use `make`) - -- install `nosetest` -- run the following commands: +Or if you don't have `make`: ``` nosetests --with-coverage --cover-package=tqdm -v tqdm/ python -m flake8 tqdm/_tqdm.py ``` - -To run the tests for all Python distributions (better, but more time consuming): - -- install `tox` -- install all versions of the Python interpreter that are specified in -[tox.ini](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. -- `cd` to the root of the `tqdm` directory (in the same folder as this file) -- run the following command: `tox` - -Then wait for the tests to finish, and check your console to see if there's -any issue. diff --git a/Makefile b/Makefile index 2f022455..ee9ea17f 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,9 @@ flake8: flake8 --max-line-length=80 --count --statistics --exit-zero examples/ test: + tox --skip-missing-interpreters + +testnose: nosetests tqdm -v testsetup: @@ -16,8 +19,6 @@ testsetup: testcoverage: nosetests tqdm --with-coverage --cover-package=tqdm -v -allenvtests: tox - installdev: python setup.py develop --uninstall python setup.py develop diff --git a/examples/simple_examples.py b/examples/simple_examples.py index a067b477..7b4dd12f 100644 --- a/examples/simple_examples.py +++ b/examples/simple_examples.py @@ -12,18 +12,18 @@ for i in trange(16, leave=True): # Profiling/overhead tests stmts = ( - # Benchmark - '[i for i in xrange(int(1e8))]', - # Basic demo - 'import tqdm; [i for i in tqdm.trange(int(1e8))]', - # Some decorations - 'import tqdm; [i for i in tqdm.trange(int(1e8), miniters=int(1e6),' - ' ascii=True, desc="cool")]', - # Experimental GUI demo - 'import tqdm; [i for i in tqdm.trange(int(1e8), gui=True)]', - # Comparison to https://code.google.com/p/python-progressbar/ - 'from progressbar.progressbar import ProgressBar;' - ' [i for i in ProgressBar()(xrange(int(1e8)))]') + # Benchmark + '[i for i in xrange(int(1e8))]', + # Basic demo + 'import tqdm; [i for i in tqdm.trange(int(1e8))]', + # Some decorations + 'import tqdm; [i for i in tqdm.trange(int(1e8), miniters=int(1e6),' + ' ascii=True, desc="cool")]', + # Experimental GUI demo + 'import tqdm; [i for i in tqdm.trange(int(1e8), gui=True)]', + # Comparison to https://code.google.com/p/python-progressbar/ + 'from progressbar.progressbar import ProgressBar;' + ' [i for i in ProgressBar()(xrange(int(1e8)))]') for s in stmts: print s print timeit(stmt=s, number=1), 'seconds' diff --git a/tox.ini b/tox.ini index cec4e905..bbe127a2 100644 --- a/tox.ini +++ b/tox.ini @@ -17,7 +17,13 @@ commands = coveralls [testenv:flake8] -basepython = python2.7 deps = flake8 commands = - flake8 --count --statistics tqdm/ + flake8 --max-line-length=80 --count --statistics --exit-zero tqdm/ + flake8 --max-line-length=80 --count --statistics --exit-zero examples/ + +[testenv:setup.py] +deps = + docutils +commands = + python setup.py check --restructuredtext --metadata --strict From 2da04c5866b5d2c152e480e5126d89d64a3461c7 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Wed, 14 Oct 2015 13:06:59 +0200 Subject: [PATCH 08/21] setup.py check in tox Signed-off-by: Stephen L. --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index bbe127a2..c9580961 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py26, py27, py32, py33, py34, pypy, pypy3, flake8 +envlist = py26, py27, py32, py33, py34, pypy, pypy3, flake8, setup.py [testenv] passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH @@ -25,5 +25,6 @@ commands = [testenv:setup.py] deps = docutils + pygments commands = python setup.py check --restructuredtext --metadata --strict From 7405a59ff2f1986922393c2bec77fced9932b28e Mon Sep 17 00:00:00 2001 From: Stephen L Date: Thu, 15 Oct 2015 15:47:02 +0200 Subject: [PATCH 09/21] Add `python setup.py make [alias]` (aka Makefile parsing in setup.py) + Tox check Signed-off-by: Stephen L. --- CONTRIBUTE | 13 ++++-- Makefile | 31 ++++++++++++-- RELEASE | 12 +++--- setup.py | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tox.ini | 1 + 5 files changed, 167 insertions(+), 11 deletions(-) diff --git a/CONTRIBUTE b/CONTRIBUTE index 1d8e4496..966a04fa 100644 --- a/CONTRIBUTE +++ b/CONTRIBUTE @@ -5,7 +5,8 @@ This file describes how to contribute changes to the project, and how to upload to the pypi repository. Most of the management commands have been directly placed inside -the Makefile, so you just have to run `make [alias]`. +the Makefile, so you just have to run `python setup.py make [alias]`, which +is equivalent to using `make [alias]` but without requiring `make`. Note: to use the Makefile on Windows, you need to install make.exe, for example by installing [MinGW MSYS](http://www.mingw.org/wiki/msys). @@ -46,6 +47,12 @@ The standard way to run the tests: - `cd` to the root of the `tqdm` directory (in the same folder as this file) - run the following command: +``` +python setup.py make test +``` + +or + ``` make test ``` @@ -78,10 +85,10 @@ Alternatively, you can use `nose` to run the tests just for your Python version: - run the following commands: ``` -make alltests +python setup.py make alltests ``` -Or if you don't have `make`: +Or if it doesn't work, you can do: ``` nosetests --with-coverage --cover-package=tqdm -v tqdm/ diff --git a/Makefile b/Makefile index ee9ea17f..f1f85fdd 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,28 @@ -.PHONY: all flake8 test coverage +# IMPORTANT: to be compatible with `python setup.py make alias`, you must make +# sure that you only put one command per line, and ALWAYS put a line return +# after an alias and before a command, eg: +# +#``` +#all: +# test +# install +#test: +# nosetest +#install: +# python setup.py install +# ``` -alltests: testcoverage flake8 testsetup -all: alltests build +.PHONY: + alltests + +alltests: + testcoverage + flake8 + testsetup + +all: + alltests + build flake8: flake8 --max-line-length=80 --count --statistics --exit-zero tqdm/ @@ -15,6 +36,7 @@ testnose: testsetup: python setup.py check --restructuredtext --strict + python setup.py make none testcoverage: nosetests tqdm --with-coverage --cover-package=tqdm -v @@ -35,3 +57,6 @@ pypimeta: pypi: twine upload dist/* + +none: + none # used for unit testing diff --git a/RELEASE b/RELEASE index 03928fd8..d02b8353 100644 --- a/RELEASE +++ b/RELEASE @@ -5,7 +5,8 @@ This file is intended for the project's maintainers and it describes how to update, build and upload a new release. Most of the management commands have been directly placed inside -the Makefile, so you just have to run `make [alias]`. +the Makefile, so you just have to run `python setup.py make [alias]`, which +is equivalent to using `make [alias]` but without requiring `make`. Note: to use the Makefile on Windows, you need to install make.exe, for example by installing [MinGW MSYS](http://www.mingw.org/wiki/msys). @@ -40,7 +41,8 @@ python setup.py check --restructuredtext --strict ``` Also, if you happen to mistakenly upload a broken release to PyPi, -you can fix the metadata by using: `make pypimeta` or `python setup.py register` +you can fix the metadata by using: `python setup.py make pypimeta` +or `python setup.py register`. BUILDING A RELEASE AND UPLOADING TO PYPI @@ -52,13 +54,13 @@ process and info that will be uploaded to [pypi](pypi.python.org). Check the result by using the following commands: ``` -make installdev +python setup.py make installdev ``` Secondly, build tqdm into a distributable python package: ``` -make build +python setup.py make build ``` This will generate several builds in the `dist/` folder. @@ -67,7 +69,7 @@ Finally, we can upload everything to pypi. Uploading to pypi can be done easily using the [twine](https://github.com/pypa/twine) module: ``` -make pypi +python setup.py make pypi ``` NOTE: diff --git a/setup.py b/setup.py index d3f6e556..008599d3 100755 --- a/setup.py +++ b/setup.py @@ -3,6 +3,112 @@ import os from setuptools import setup +# For Makefile parsing +import ConfigParser +import StringIO +import sys, subprocess + + +### Makefile auxiliary functions ### + + +def parse_makefile_aliases(filepath): + '''Parse a makefile to find commands and substitute variables. + Note that this function is not a total replacement of make, it only + parse aliases. + Expects a makefile with only aliases and ALWAYS a line return between + each command, eg: + + ``` + all: + test + install + test: + nosetest + install: + python setup.py install + ``` + + Returns a dict, with a list of commands for each alias. + ''' + + # -- Parsing the Makefile using ConfigParser + # Adding a fake section to make the Makefile a valid Ini file + ini_str = '[root]\n' + open(filepath, 'r').read() + ini_fp = StringIO.StringIO(ini_str) + # Parse it using ConfigParser + config = ConfigParser.RawConfigParser() + config.readfp(ini_fp) + # Fetch the list of aliases + aliases = config.options('root') + + # -- Extracting commands for each alias + commands = {} + for alias in aliases: + # strip the first line return, and then split by any line return + commands[alias] = config.get('root', alias).lstrip('\n').split('\n') + + # -- Commands substitution + # We loop until we can substitute all aliases by their commands + # What we do is that we check each command of each alias, and + # if there is one command that is to be substituted by an alias, + # we try to do it right away, but if it's not possible because + # this alias himself points to other aliases, then we stop + # and put the current alias back in the queue, which we + # will process again later when we have substituted the + # other aliases. + + # Create the queue of aliases to process + aliases_todo = commands.keys() + # Create the dict that will hold the substituted aliases by their full commands + commands_new = {} + # Loop until we have processed all aliases + while aliases_todo: + # Pick the first alias in the queue + alias = aliases_todo.pop(0) + # Create a new entry in the resulting dict + commands_new[alias] = [] + # For each command of this alias + for cmd in commands[alias]: + # If the alias points to itself, we pass + if cmd == alias: + pass + # If the alias points to a full command, we substitute + elif cmd in aliases and cmd in commands_new: + # Append all the commands referenced by the alias + commands_new[alias].extend(commands_new[cmd]) + # If the alias points to another alias, we delay, + # waiting for the other alias to be substituted first + elif cmd in aliases and cmd not in commands_new: + # Delete the current entry to avoid other aliases + # to reference this one wrongly (as it is empty) + del commands_new[alias] + # Put back into the queue + aliases_todo.append(alias) + # Break the loop for the current alias + break + # Else this is just a full command (no reference to an alias) + # so we just append it + else: + commands_new[alias].append(cmd) + commands = commands_new + del commands_new + # -- Prepending prefix to avoid conflicts with standard setup.py commands + #for alias in commands.keys(): + #commands['make_'+alias] = commands[alias] + #del commands[alias] + return commands + +def execute_makefile_commands(commands, alias, verbose=False): + cmds = commands[alias] + for cmd in cmds: + if verbose: print("Running command: %s" % cmd) + subprocess.check_call(cmd.split()) + + +### Main setup.py config ### + + # Get version from tqdm/_version.py __version__ = None version_file = os.path.join(os.path.dirname(__file__), 'tqdm', '_version.py') @@ -10,6 +116,21 @@ for line in open(version_file).readlines(): if (line.startswith('version_info') or line.startswith('__version__')): exec(line.strip()) +# Executing makefile commands if specified +if len(sys.argv) >= 3 and sys.argv[1].lower().strip() == 'make': + arg = sys.argv[-1] + fpath = 'Makefile' + commands = parse_makefile_aliases(fpath) + if arg == 'none': # unit testing, we do nothing (we just checked the makefile parsing) + sys.exit(0) + elif arg in commands.keys(): # else if the alias exists, we execute its commands + execute_makefile_commands(commands, arg, verbose=True) + else: # else the alias cannot be found + raise Exception("Provided argument cannot be found: make %s" % (arg)) + # Stop the processing of setup.py here + sys.exit(0) # Important to avoid setup.py to spit an error because of the command not being standard + +# Python package config setup( name='tqdm', version=__version__, diff --git a/tox.ini b/tox.ini index c9580961..58b353fe 100644 --- a/tox.ini +++ b/tox.ini @@ -28,3 +28,4 @@ deps = pygments commands = python setup.py check --restructuredtext --metadata --strict + python setup.py make none From 8a70f97464a3de1bd8df1227b14ace97e503ae69 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Thu, 15 Oct 2015 15:56:36 +0200 Subject: [PATCH 10/21] fix setup.py: Python 3 compatibility Signed-off-by: Stephen L. --- setup.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 008599d3..faa74e54 100755 --- a/setup.py +++ b/setup.py @@ -4,8 +4,13 @@ import os from setuptools import setup # For Makefile parsing -import ConfigParser -import StringIO +try: # pragma: no cover + import ConfigParser + import StringIO +except NameError: # pragma: no cover + # Python 3 compatibility + import configparser as ConfigParser + import io as StringIO import sys, subprocess From 89b2a8ca00ee246bcaa4aabe60401be15881c750 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Thu, 15 Oct 2015 15:58:00 +0200 Subject: [PATCH 11/21] fix compat again Signed-off-by: Stephen L. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index faa74e54..9b1274b3 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ from setuptools import setup try: # pragma: no cover import ConfigParser import StringIO -except NameError: # pragma: no cover +except ImportError: # pragma: no cover # Python 3 compatibility import configparser as ConfigParser import io as StringIO From 576d3a7bcb60bc6a03c9d167f44da89f25a2a1b7 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Thu, 15 Oct 2015 16:36:27 +0200 Subject: [PATCH 12/21] add travis comment Signed-off-by: Stephen L. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e8bd12f9..584ddd24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ sudo: false language: python python: 3.4 -branches: +branches: # remove travis double-check on pull requests in main repo only: - master - /^\d\.\d+$/ From 6313cc9d00c0ecb45ac6365376f00a9e3c1d9d8f Mon Sep 17 00:00:00 2001 From: Stephen L Date: Thu, 15 Oct 2015 16:49:19 +0200 Subject: [PATCH 13/21] fix flake8 notice Signed-off-by: Stephen L. --- examples/simple_examples.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/simple_examples.py b/examples/simple_examples.py index 7b4dd12f..98fcde0e 100644 --- a/examples/simple_examples.py +++ b/examples/simple_examples.py @@ -25,5 +25,5 @@ stmts = ( 'from progressbar.progressbar import ProgressBar;' ' [i for i in ProgressBar()(xrange(int(1e8)))]') for s in stmts: - print s - print timeit(stmt=s, number=1), 'seconds' + print(s) + print(timeit(stmt=s, number=1), 'seconds') From b8f0e7412afaf52d63cece75707bde5f5983550c Mon Sep 17 00:00:00 2001 From: Stephen L Date: Thu, 15 Oct 2015 16:49:42 +0200 Subject: [PATCH 14/21] fix Travis: check setup.py Signed-off-by: Stephen L. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 584ddd24..dc47ab6b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ env: - TOXENV=pypy - TOXENV=pypy3 - TOXENV=flake8 + - TOXENV=setup.py before_install: - pip install codecov install: From 45e82ef1287ce234716b9b593f69ef0f5e0b9bbf Mon Sep 17 00:00:00 2001 From: Stephen L Date: Thu, 15 Oct 2015 17:13:07 +0200 Subject: [PATCH 15/21] Fix makefile tabs Signed-off-by: Stephen L. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f1f85fdd..38488f09 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ testnose: testsetup: python setup.py check --restructuredtext --strict - python setup.py make none + python setup.py make none testcoverage: nosetests tqdm --with-coverage --cover-package=tqdm -v From 26eb76d44745fd60f5fc8aea0793ce9004c803a6 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Thu, 15 Oct 2015 17:21:04 +0200 Subject: [PATCH 16/21] Revert setup.py check in Travis Signed-off-by: Stephen L. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index dc47ab6b..584ddd24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ env: - TOXENV=pypy - TOXENV=pypy3 - TOXENV=flake8 - - TOXENV=setup.py before_install: - pip install codecov install: From 487cc2fd7d7f4703d4db5a9c757398804e4b82e5 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Thu, 15 Oct 2015 22:36:45 +0200 Subject: [PATCH 17/21] Add --help message for `python setup.py make` Signed-off-by: Stephen L. --- setup.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 9b1274b3..dfbaf4eb 100755 --- a/setup.py +++ b/setup.py @@ -122,16 +122,27 @@ for line in open(version_file).readlines(): exec(line.strip()) # Executing makefile commands if specified -if len(sys.argv) >= 3 and sys.argv[1].lower().strip() == 'make': - arg = sys.argv[-1] +if sys.argv[1].lower().strip() == 'make': + # Filename of the makefile fpath = 'Makefile' + # Parse the makefile, substitute the aliases and extract the commands commands = parse_makefile_aliases(fpath) - if arg == 'none': # unit testing, we do nothing (we just checked the makefile parsing) - sys.exit(0) - elif arg in commands.keys(): # else if the alias exists, we execute its commands - execute_makefile_commands(commands, arg, verbose=True) - else: # else the alias cannot be found - raise Exception("Provided argument cannot be found: make %s" % (arg)) + + # If no alias (only `python setup.py make`), print the list of aliases + if len(sys.argv) < 3 or sys.argv[-1] == '--help': + print("Shortcut to use commands via aliases. List of aliases:") + for alias in sorted(commands.keys()): + print("- "+alias) + + # Else process the commands for this alias + else: + arg = sys.argv[-1] + if arg == 'none': # unit testing, we do nothing (we just checked the makefile parsing) + sys.exit(0) + elif arg in commands.keys(): # else if the alias exists, we execute its commands + execute_makefile_commands(commands, arg, verbose=True) + else: # else the alias cannot be found + raise Exception("Provided alias cannot be found: make %s" % (arg)) # Stop the processing of setup.py here sys.exit(0) # Important to avoid setup.py to spit an error because of the command not being standard From 3c5707e1b39f5558d72e2f33ad84b908331bea30 Mon Sep 17 00:00:00 2001 From: Stephen L Date: Fri, 30 Oct 2015 22:17:47 +0100 Subject: [PATCH 18/21] Fix README.rst links for PyPi Signed-off-by: Stephen L. --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index aa1108fc..8f39b428 100644 --- a/README.rst +++ b/README.rst @@ -225,13 +225,14 @@ with the following command: $ make test $ make coverage -See the `CONTRIBUTE `__ file for more information. +See the `CONTRIBUTE `__ +file for more information. License ------- -`MIT LICENSE `__. +`MIT LICENSE `__. Authors From 291225c322093f1ad390983e1dcb8fd3f2fefd09 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Sat, 31 Oct 2015 11:38:53 +0000 Subject: [PATCH 19/21] Makefile phony fix --- Makefile | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index b7ef9dcd..80be0617 100644 --- a/Makefile +++ b/Makefile @@ -14,15 +14,27 @@ .PHONY: alltests + all + flake8 + test + testnose + testsetup + testcoverage + installdev + install + build + pypimeta + pypi + none alltests: - testcoverage - flake8 - testsetup + @make testcoverage + @make flake8 + @make testsetup all: - alltests - build + @make alltests + @make build flake8: flake8 --max-line-length=80 --count --statistics --exit-zero tqdm/ @@ -60,4 +72,4 @@ pypi: twine upload dist/* none: - none # used for unit testing + # used for unit testing From 76f0cd0a237d66a9a7629b53c3fa458041298602 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Sat, 31 Oct 2015 11:43:40 +0000 Subject: [PATCH 20/21] setup.py Makefile fix --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index dfbaf4eb..5e8c21b0 100755 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ def parse_makefile_aliases(filepath): # -- Parsing the Makefile using ConfigParser # Adding a fake section to make the Makefile a valid Ini file ini_str = '[root]\n' + open(filepath, 'r').read() - ini_fp = StringIO.StringIO(ini_str) + ini_fp = StringIO.StringIO(ini_str.replace('@make ','')) # Parse it using ConfigParser config = ConfigParser.RawConfigParser() config.readfp(ini_fp) From 7decf040f36c4aae6a93f544c01c14721f24dce9 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Sun, 1 Nov 2015 16:01:18 +0000 Subject: [PATCH 21/21] setup.py flake8 tests and compliance, minor typos and rewording --- CONTRIBUTE | 42 ++++++++++----------- Makefile | 25 ++++++------ RELEASE | 26 ++++++------- setup.py | 109 ++++++++++++++++++++++++++++++----------------------- tox.ini | 1 + 5 files changed, 107 insertions(+), 96 deletions(-) diff --git a/CONTRIBUTE b/CONTRIBUTE index 966a04fa..76f61e6f 100644 --- a/CONTRIBUTE +++ b/CONTRIBUTE @@ -4,9 +4,9 @@ HOW TO CONTRIBUTE TO TQDM This file describes how to contribute changes to the project, and how to upload to the pypi repository. -Most of the management commands have been directly placed inside -the Makefile, so you just have to run `python setup.py make [alias]`, which -is equivalent to using `make [alias]` but without requiring `make`. +Most of the management commands have been directly placed inside the +Makefile: `python setup.py make [alias]`, (or simply `make [alias]` in +UNIX-like environments). Note: to use the Makefile on Windows, you need to install make.exe, for example by installing [MinGW MSYS](http://www.mingw.org/wiki/msys). @@ -15,15 +15,14 @@ for example by installing [MinGW MSYS](http://www.mingw.org/wiki/msys). HOW TO COMMIT YOUR CONTRIBUTIONS -------------------------------- -Contributions to the project is made using the "Fork & Pull" model. Here's a -quickstart on how to do that (your mileage may vary depending on your git -config): +Contributions to the project are made using the "Fork & Pull" model. The +typical steps would be: - create an account on [github](https://github.com) - fork [tqdm](https://github.com/tqdm/tqdm) - make a local clone: `git clone https://github.com/your_account/tqdm.git` - make your changes on your local copy -- commit your changes `git commit -m "my message"` +- commit your changes `git commit -a -m "my message"` - TEST YOUR CHANGES (see below) - `push` to your github account: `git push origin` - finally, create a Pull Request (PR) from your github fork @@ -39,7 +38,7 @@ Request), there are a number of unit tests. Standard unit testing -~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~ The standard way to run the tests: @@ -63,32 +62,31 @@ or tox --skip-missing-interpreters ``` -This will build the module and run the tests in a virtualized environment. -Wait a bit for tests to complete, and check the console/log for any error and -also check the coverage rate. Do not care about missing interpreters errors, -this is because tox tries to run the tests on several versions of Python and you -don't have them installed. +This will build the module and run the tests in a virtual environment. +Errors and coverage rates will be output to the console/log. (Ignore missing +interpreters errors - these are due to the local machine missing certain +versions of Python.) -Note: to install all versions of the Python interpreter that are specified in -[tox.ini](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. +Note: to install all versions of the Python interpreter that are specified +in [tox.ini](https://raw.githubusercontent.com/tqdm/tqdm/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. Alternative unit testing with Nose -~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Alternatively, you can use `nose` to run the tests just for your Python version: +Alternatively, use `nose` to run the tests just for your Python version: - install `nose` and `flake8` -- run the following commands: +- run the following command: ``` python setup.py make alltests ``` -Or if it doesn't work, you can do: +or ``` nosetests --with-coverage --cover-package=tqdm -v tqdm/ diff --git a/Makefile b/Makefile index 80be0617..773f694c 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,15 @@ -# IMPORTANT: to be compatible with `python setup.py make alias`, you must make -# sure that you only put one command per line, and ALWAYS put a line return -# after an alias and before a command, eg: -# -#``` -#all: -# test -# install -#test: -# nosetest -#install: -# python setup.py install +# IMPORTANT: for compatibility with `python setup.py make [alias]`, ensure: +# 1. A line return after every alias +# 2. One command per line +# E.g.: +# ``` +# all: +# @make test +# @make install +# test: +# nosetest +# install: +# python setup.py install # ``` .PHONY: @@ -39,6 +39,7 @@ all: flake8: flake8 --max-line-length=80 --count --statistics --exit-zero tqdm/ flake8 --max-line-length=80 --count --statistics --exit-zero examples/ + flake8 --max-line-length=80 --count --statistics --exit-zero . test: tox --skip-missing-interpreters diff --git a/RELEASE b/RELEASE index d02b8353..6d61370c 100644 --- a/RELEASE +++ b/RELEASE @@ -4,9 +4,9 @@ HOW TO MANAGE A NEW RELEASE This file is intended for the project's maintainers and it describes how to update, build and upload a new release. -Most of the management commands have been directly placed inside -the Makefile, so you just have to run `python setup.py make [alias]`, which -is equivalent to using `make [alias]` but without requiring `make`. +Most of the management commands have been directly placed inside the +Makefile: `python setup.py make [alias]`, (or simply `make [alias]` in +UNIX-like environments). Note: to use the Makefile on Windows, you need to install make.exe, for example by installing [MinGW MSYS](http://www.mingw.org/wiki/msys). @@ -16,8 +16,8 @@ SEMANTIC VERSIONING ------------------- The tqdm repository managers should regularly bump the version number in the -VERSION file to follow the [Semantic Versioning](http://semver.org/) -convention. +[_version.py](https://raw.githubusercontent.com/tqdm/tqdm/master/tqdm/_version.py) +file to follow the [Semantic Versioning](http://semver.org/) convention. Tools can be used to automate this process, such as [bumpversion](https://github.com/peritus/bumpversion) or @@ -25,22 +25,20 @@ Tools can be used to automate this process, such as to automate this task. The managers should take care of this instead of users to avoid PR conflicts -solely due to the VERSION file bumping. +solely due to the version file bumping. CHECKING SETUP.PY ----------------- -To check that the setup.py is OK for PyPi (eg, version number, -reStructuredText in README.rst intelligible for PyPi, which uses a -awkward RST lib, etc.) you can use the following command to make -sure everything's ok: +To check that the `setup.py` file is compliant with PyPi requirements (e.g. +version number; reStructuredText in README.rst) use the following command: ``` python setup.py check --restructuredtext --strict ``` -Also, if you happen to mistakenly upload a broken release to PyPi, +If you happen to mistakenly upload a broken release to PyPi, you can fix the metadata by using: `python setup.py make pypimeta` or `python setup.py register`. @@ -65,8 +63,8 @@ python setup.py make build This will generate several builds in the `dist/` folder. -Finally, we can upload everything to pypi. Uploading to pypi can be done -easily using the [twine](https://github.com/pypa/twine) module: +Finally, upload everything to pypi. This can be done easily using the +[twine](https://github.com/pypa/twine) module: ``` python setup.py make pypi @@ -82,5 +80,5 @@ cannot re-upload another with the same version number! getting garbled because of a silent error), you can use the following command to update the metadata: `make pypimeta` or `python setup.py register` -Also, the new release can be added to the Github by creating a new release +Also, the new release can be added to github by creating a new release from the web interface. diff --git a/setup.py b/setup.py index 5e8c21b0..b1bea3d2 100755 --- a/setup.py +++ b/setup.py @@ -1,8 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- + import os from setuptools import setup - +import sys +import subprocess # For Makefile parsing try: # pragma: no cover import ConfigParser @@ -11,18 +13,15 @@ except ImportError: # pragma: no cover # Python 3 compatibility import configparser as ConfigParser import io as StringIO -import sys, subprocess -### Makefile auxiliary functions ### +""" Makefile auxiliary functions """ def parse_makefile_aliases(filepath): - '''Parse a makefile to find commands and substitute variables. - Note that this function is not a total replacement of make, it only - parse aliases. - Expects a makefile with only aliases and ALWAYS a line return between - each command, eg: + ''' + Parse a makefile to find commands and substitute variables. Expects a + makefile with only aliases and a line return between each command, i.e.: ``` all: @@ -39,9 +38,11 @@ def parse_makefile_aliases(filepath): # -- Parsing the Makefile using ConfigParser # Adding a fake section to make the Makefile a valid Ini file - ini_str = '[root]\n' + open(filepath, 'r').read() - ini_fp = StringIO.StringIO(ini_str.replace('@make ','')) - # Parse it using ConfigParser + ini_str = '[root]\n' + with open(filepath, 'r') as fd: + ini_str = ini_str + fd.read().replace('@make ', '') + ini_fp = StringIO.StringIO(ini_str) + # Parse using ConfigParser config = ConfigParser.RawConfigParser() config.readfp(ini_fp) # Fetch the list of aliases @@ -54,18 +55,15 @@ def parse_makefile_aliases(filepath): commands[alias] = config.get('root', alias).lstrip('\n').split('\n') # -- Commands substitution - # We loop until we can substitute all aliases by their commands - # What we do is that we check each command of each alias, and - # if there is one command that is to be substituted by an alias, - # we try to do it right away, but if it's not possible because - # this alias himself points to other aliases, then we stop - # and put the current alias back in the queue, which we - # will process again later when we have substituted the - # other aliases. + # Loop until all aliases are substituted by their commands: + # Check each command of each alias, and if there is one command that is to + # be substituted by an alias, try to do it right away. If this is not + # possible because this alias itself points to other aliases , then stop + # and put the current alias back in the queue to be processed again later. # Create the queue of aliases to process aliases_todo = commands.keys() - # Create the dict that will hold the substituted aliases by their full commands + # Create the dict that will hold the full commands commands_new = {} # Loop until we have processed all aliases while aliases_todo: @@ -75,51 +73,51 @@ def parse_makefile_aliases(filepath): commands_new[alias] = [] # For each command of this alias for cmd in commands[alias]: - # If the alias points to itself, we pass + # Ignore self-referencing (alias points to itself) if cmd == alias: pass - # If the alias points to a full command, we substitute + # Substitute full command elif cmd in aliases and cmd in commands_new: # Append all the commands referenced by the alias commands_new[alias].extend(commands_new[cmd]) - # If the alias points to another alias, we delay, - # waiting for the other alias to be substituted first + # Delay substituting another alias, waiting for the other alias to + # be substituted first elif cmd in aliases and cmd not in commands_new: # Delete the current entry to avoid other aliases # to reference this one wrongly (as it is empty) del commands_new[alias] - # Put back into the queue aliases_todo.append(alias) - # Break the loop for the current alias break - # Else this is just a full command (no reference to an alias) - # so we just append it + # Full command (no aliases) else: commands_new[alias].append(cmd) commands = commands_new del commands_new + # -- Prepending prefix to avoid conflicts with standard setup.py commands - #for alias in commands.keys(): - #commands['make_'+alias] = commands[alias] - #del commands[alias] + # for alias in commands.keys(): + # commands['make_'+alias] = commands[alias] + # del commands[alias] + return commands + def execute_makefile_commands(commands, alias, verbose=False): cmds = commands[alias] for cmd in cmds: - if verbose: print("Running command: %s" % cmd) + if verbose: + print("Running command: " + cmd) subprocess.check_call(cmd.split()) -### Main setup.py config ### +""" Main setup.py config """ # Get version from tqdm/_version.py __version__ = None version_file = os.path.join(os.path.dirname(__file__), 'tqdm', '_version.py') -for line in open(version_file).readlines(): - if (line.startswith('version_info') or line.startswith('__version__')): - exec(line.strip()) +with open(version_file) as fd: + exec(fd.read()) # Executing makefile commands if specified if sys.argv[1].lower().strip() == 'make': @@ -132,21 +130,33 @@ if sys.argv[1].lower().strip() == 'make': if len(sys.argv) < 3 or sys.argv[-1] == '--help': print("Shortcut to use commands via aliases. List of aliases:") for alias in sorted(commands.keys()): - print("- "+alias) + print("- " + alias) # Else process the commands for this alias else: arg = sys.argv[-1] - if arg == 'none': # unit testing, we do nothing (we just checked the makefile parsing) + # if unit testing, we do nothing (we just checked the makefile parsing) + if arg == 'none': sys.exit(0) - elif arg in commands.keys(): # else if the alias exists, we execute its commands + # else if the alias exists, we execute its commands + elif arg in commands.keys(): execute_makefile_commands(commands, arg, verbose=True) - else: # else the alias cannot be found - raise Exception("Provided alias cannot be found: make %s" % (arg)) - # Stop the processing of setup.py here - sys.exit(0) # Important to avoid setup.py to spit an error because of the command not being standard + # else the alias cannot be found + else: + raise Exception("Provided alias cannot be found: make " + arg) + # Stop the processing of setup.py here: + # It's important to avoid setup.py raising an error because of the command + # not being standard + sys.exit(0) + + +""" Python package config """ + + +README_rst = '' +with open('README.rst', 'r') as fd: + README_rst = fd.read() -# Python package config setup( name='tqdm', version=__version__, @@ -157,10 +167,12 @@ setup( url='https://github.com/tqdm/tqdm', maintainer='tqdm developers', maintainer_email='python.tqdm@gmail.com', - platforms = ["any"], + platforms=['any'], packages=['tqdm'], - long_description = open("README.rst", "r").read(), - classifiers=[ # Trove classifiers, see https://pypi.python.org/pypi?%3Aaction=list_classifiers + long_description=README_rst, + classifiers=[ + # Trove classifiers + # (https://pypi.python.org/pypi?%3Aaction=list_classifiers) 'Development Status :: 5 - Production/Stable', 'License :: OSI Approved :: MIT License', 'Environment :: Console', @@ -185,7 +197,8 @@ setup( 'Topic :: Utilities', 'Intended Audience :: Developers', ], - keywords = 'progressbar progressmeter progress bar meter rate eta console terminal time', + keywords='progressbar progressmeter progress bar meter' + ' rate eta console terminal time', test_suite='nose.collector', tests_require=['nose', 'flake8', 'coverage'], ) diff --git a/tox.ini b/tox.ini index 58b353fe..16b54349 100644 --- a/tox.ini +++ b/tox.ini @@ -21,6 +21,7 @@ deps = flake8 commands = flake8 --max-line-length=80 --count --statistics --exit-zero tqdm/ flake8 --max-line-length=80 --count --statistics --exit-zero examples/ + flake8 --max-line-length=80 --count --statistics --exit-zero . [testenv:setup.py] deps =