framework overhaul

- replace setup.py make -> py-make>=0.1.9
  + fixes #290
- add requirements-dev.txt and extras_require[dev]
- misc documentation & Travis CI updates
This commit is contained in:
Casper da Costa-Luis 2019-01-21 00:01:17 +00:00
parent bcf3cca298
commit 5b7816d53a
No known key found for this signature in database
GPG Key ID: 986B408043AE090D
11 changed files with 64 additions and 151 deletions

11
.gitignore vendored
View File

@ -1,8 +1,7 @@
*.py[cod]
# C extensions
*.so
/wiki/
/docs/
/feedstock/
# Packages
tqdm.egg-info
@ -13,6 +12,7 @@ dist/
.tox/
.coverage
__pycache__
nosetests.xml
# Translations
*.mo
@ -31,3 +31,8 @@ __pycache__
# asv
.asv/
benchmarks/*.py[co]
# Sumbodules
/wiki/
/docs/
/feedstock/

View File

@ -1,6 +1,6 @@
% TQDM(1) tqdm User Manuals
% tqdm developers <https://github.com/tqdm>
% 2015-2018
% 2015-2019
# NAME

View File

@ -1,5 +1,3 @@
# sudo: required
# dist: trusty
language: python
matrix:
include:
@ -46,10 +44,7 @@ before_install:
# - sudo ln -s /run/shm /dev/shm
- git fetch --tags
install:
# Install tox first, before dependencies (to get per-env deps)
- pip install tox
# install this package (tqdm) into the environment
- pip install .
# run tests
script:
- tox

View File

@ -82,7 +82,7 @@ how to build and upload a new release. Once again,
`[python setup.py] make [<alias>]` will help.
## SEMANTIC VERSIONING
## Semantic Versioning
The tqdm repository managers should:
@ -97,7 +97,7 @@ Note: tools can be used to automate this process, such as
[python-semanticversion](https://github.com/rbarrois/python-semanticversion/).
## CHECKING SETUP.PY
## Checking setup.py
To check that the `setup.py` file is compliant with PyPi requirements (e.g.
version number; reStructuredText in README.rst) use:
@ -114,7 +114,7 @@ to PyPi, use:
```
## MERGING PULL REQUESTS
## Merging Pull Requests
This section describes how to cleanly merge PRs.
@ -164,7 +164,7 @@ git merge --no-ff pr-branch-name
### 5 Version
Modify tqdm/_version.py and amend the last (merge) commit:
Modify `tqdm/_version.py` and amend the last (merge) commit:
```
git add tqdm/_version.py
@ -178,7 +178,7 @@ git push origin master
```
## BUILDING A RELEASE AND UPLOADING TO PYPI
## Building a Release and Uploading to PyPI
Formally publishing requires additional steps: testing and tagging.
@ -199,7 +199,7 @@ display as `v{major}.{minor}.{patch}-{commit_hash}`.
### Upload
Build tqdm into a distributable python package:
Build `tqdm` into a distributable python package:
```
[python setup.py] make build
@ -233,21 +233,20 @@ cannot re-upload another with the same version number
updating just the metadata is possible: `[python setup.py] make pypimeta`
## UPDATING GH-PAGES
## Updating Websites
The most important file is README.rst, which sould always be kept up-to-date
The most important file is `README.rst`, which sould always be kept up-to-date
and in sync with the in-line source documentation. This will affect all of the
following:
- The [main repository site](https://github.com/tqdm/tqdm) which automatically
serves the latest README.rst as well as links to all of github's features.
This is the preferred online referral link for tqdm.
serves the latest `README.rst` as well as links to all of github's features.
This is the preferred online referral link for `tqdm`.
- The [PyPi mirror](https://pypi.org/project/tqdm) which automatically
serves the latest release built from README.rst as well as links to past
serves the latest release built from `README.rst` as well as links to past
releases.
- Many external web crawlers.
Additionally (less maintained), there exists:
- A [wiki] which is publicly editable.
@ -276,7 +275,7 @@ For experienced devs, once happy with local master:
b) `twine upload -s -i $(git config user.signingkey) dist/tqdm-*`
10. create new release on https://github.com/tqdm/tqdm/releases
a) add helpful release notes
b) attach dist/tqdm-* binaries (usually only *.whl*)
b) attach `dist/tqdm-*` binaries (usually only `*.whl*`)
11. run `make` in the `wiki` submodule to update release notes
12. run `make deploy` in the `docs` submodule to update website
13. accept the automated PR in the `feedstock` submodule to update conda

View File

@ -7,7 +7,7 @@ Exceptions or notable authors are listed below
in reverse chronological order:
* files: *
MPLv2.0 2015-2018 (c) Casper da Costa-Luis
MPLv2.0 2015-2019 (c) Casper da Costa-Luis
[casperdcl](https://github.com/casperdcl).
* files: tqdm/_tqdm.py
MIT 2016 (c) [PR #96] on behalf of Google Inc.
@ -20,8 +20,10 @@ in reverse chronological order:
Mozilla Public Licence (MPL) v. 2.0 - Exhibit A
-----------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
This Source Code Form is subject to the terms of the
Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,
You can obtain one at https://mozilla.org/MPL/2.0/.
MIT License (MIT)

View File

@ -9,6 +9,7 @@ include tox.ini
# Test suite
recursive-include tqdm/tests *.py
include requirements-dev.txt
# Sub-packages
recursive-include tqdm/autonotebook *.py

View File

@ -1,18 +1,7 @@
# IMPORTANT: for compatibility with `python setup.py make [alias]`, ensure:
# 1. Every alias is preceded by @[+]make (eg: @make alias)
# 2. A maximum of one @make alias or command per line
#
# Sample makefile compatible with `python setup.py make`:
#```
#all:
# @make test
# @make install
#test:
# nosetest
#install:
# python setup.py \
# install
#```
# see: https://github.com/tqdm/py-make/issues/1
.PHONY:
alltests
@ -28,14 +17,17 @@
coverclean
prebuildclean
clean
toxclean
installdev
install
build
buildupload
pypi
help
none
help:
@python setup.py make
@python setup.py make -p
alltests:
@+make testcoverage
@ -48,7 +40,7 @@ all:
@+make build
flake8:
@+flake8 --max-line-length=80 --exclude .asv,.tox,.ipynb_checkpoints \
@+flake8 --max-line-length=80 --exclude .asv,.tox,.ipynb_checkpoints,build \
-j 8 --count --statistics --exit-zero .
test:

View File

@ -870,7 +870,7 @@ There are also many |GitHub-Contributions| which we are grateful for.
.. |Branch-Coverage-Status| image:: https://codecov.io/gh/tqdm/tqdm/branch/master/graph/badge.svg
:target: https://codecov.io/gh/tqdm/tqdm
.. |Codacy-Grade| image:: https://api.codacy.com/project/badge/Grade/3f965571598f44549c7818f29cdcf177
:target: https://www.codacy.com/app/tqdm/tqdm?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=tqdm/tqdm&amp;utm_campaign=Badge_Grade
:target: https://www.codacy.com/app/tqdm/tqdm/dashboard
.. |GitHub-Status| image:: https://img.shields.io/github/tag/tqdm/tqdm.svg?maxAge=86400&logo=github&logoColor=white
:target: https://github.com/tqdm/tqdm/releases
.. |GitHub-Forks| image:: https://img.shields.io/github/forks/tqdm/tqdm.svg?logo=github&logoColor=white
@ -905,8 +905,8 @@ There are also many |GitHub-Contributions| which we are grateful for.
:target: https://www.openhub.net/p/tqdm?ref=Thin+badge
.. |LICENCE| image:: https://img.shields.io/pypi/l/tqdm.svg
:target: https://raw.githubusercontent.com/tqdm/tqdm/master/LICENCE
.. |DOI-URI| image:: https://zenodo.org/badge/21637/tqdm/tqdm.svg
:target: https://zenodo.org/badge/latestdoi/21637/tqdm/tqdm
.. |DOI-URI| image:: https://img.shields.io/badge/DOI-10.5281/zenodo.595120-blue.svg
:target: https://doi.org/10.5281/zenodo.595120
.. |interactive-demo| image:: https://img.shields.io/badge/demo-interactive-orange.svg?logo=jupyter
:target: https://notebooks.rmotr.com/demo/gh/tqdm/tqdm
.. |Screenshot-Jupyter1| image:: https://raw.githubusercontent.com/tqdm/tqdm/master/images/tqdm-jupyter-1.gif

4
requirements-dev.txt Normal file
View File

@ -0,0 +1,4 @@
py-make>=0.1.0 # setup.py make/pymake
twine # pymake pypi
argopt # cd wiki && pymake
pydoc-markdown # cd docs && pymake

116
setup.py
View File

@ -1,6 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
try:
from setuptools import setup, find_packages
@ -24,116 +23,28 @@ with io_open(version_file, mode='r') as fd:
# Executing makefile commands if specified
if sys.argv[1].lower().strip() == 'make':
import shlex
from subprocess import check_call
try: # pragma: no cover
import ConfigParser
import StringIO
except ImportError: # pragma: no cover
# Python 3 compatibility
import configparser as ConfigParser
import io as StringIO
import re
RE_MAKE_CMD = re.compile('^\t(@\+?)(make)?', flags=re.M)
def parse_makefile_aliases(filepath):
"""
Parse a makefile to find commands and substitute variables. Expects a
makefile with only aliases and a line return between each command.
Returns a dict, with a list of commands for each alias.
"""
# Parse Makefile using ConfigParser
ini_str = '[root]\n' # fake section to resemble valid *.ini
with io_open(filepath, mode='r') as fd:
ini_str = ini_str + RE_MAKE_CMD.sub('\t', fd.read())
ini_fp = StringIO.StringIO(ini_str)
config = ConfigParser.RawConfigParser()
config.readfp(ini_fp)
aliases = config.options('root')
# Extract commands for each alias
commands = {}
for alias in aliases:
if alias.lower() in ['.phony']:
continue
commands[alias] = config.get('root', alias)\
.lstrip('\n').replace('\\\n', '').split('\n')
# Command substitution (depth-first).
# If this is not possible because an alias points to another alias,
# then stop and put the current alias back in the queue to be
# processed again later (bottom-up).
aliases_todo = list(commands.keys())
commands_new = {}
while aliases_todo:
alias = aliases_todo.pop()
commands_new[alias] = []
for cmd in commands[alias]:
# Ignore self-referencing (alias points to itself)
if cmd == alias:
pass
elif cmd in aliases:
# Append substituted full commands
if cmd in commands_new:
commands_new[alias].extend(commands_new[cmd])
# Delay substituting another alias until it is substituted
else:
del commands_new[alias]
aliases_todo.insert(0, alias)
break
# Full command (no aliases)
else:
commands_new[alias].append(cmd)
commands = commands_new
# Prepending prefix to avoid conflicts with standard setup.py commands
# for alias in list(commands.keys()):
# commands['make_'+alias] = commands.pop(alias)
return commands
def execute_makefile_commands(commands, alias, verbose=False):
cmds = commands[alias]
for cmd in cmds:
# Parse string in a shell-like fashion
# (incl quoted strings and comments)
parsed_cmd = shlex.split(cmd, comments=True)
# Execute command if not empty/comment
if parsed_cmd:
if verbose:
print("Running command: " + cmd)
check_call(parsed_cmd, cwd=src_dir)
import pymake
# Filename of the makefile
fpath = os.path.join(src_dir, 'Makefile')
# Parse the makefile, substitute the aliases and extract the commands
commands = parse_makefile_aliases(fpath)
# If no alias (only `python setup.py make`), print the list of aliases
args = sys.argv[2:]
invalid = set(args).difference(commands.keys())
if not args or '--help' in args or invalid:
print("Shortcut to use commands via aliases. List of aliases:")
print(' '.join(alias for alias in sorted(commands.keys())))
if invalid:
raise Exception("Cannot find: " + ' '.join(invalid))
# Else process the commands for this alias
else:
for arg in args:
execute_makefile_commands(commands, arg, verbose=True)
pymake.main(['-f', fpath] + sys.argv[2:])
# Stop to avoid setup.py raising non-standard command error
sys.exit(0)
extras_require = {}
requirements_dev = os.path.join(src_dir, 'requirements-dev.txt')
with io_open(requirements_dev, mode='r') as fd:
extras_require['dev'] = [i.strip().split('#', 1)[0].strip()
for i in fd.read().strip().split('\n')]
README_rst = ''
fndoc = os.path.join(src_dir, 'README.rst')
with io_open(fndoc, mode='r', encoding='utf-8') as fd:
README_rst = fd.read()
setup(
name='tqdm',
version=__version__,
description='Fast, Extensible Progress Meter',
long_description=README_rst,
license='MPLv2.0, MIT Licences',
author='Noam Yorav-Raphael',
author_email='noamraph@gmail.com',
@ -142,10 +53,11 @@ setup(
maintainer_email='python.tqdm@gmail.com',
platforms=['any'],
packages=['tqdm'] + ['tqdm.' + i for i in find_packages('tqdm')],
provides=['tqdm'],
extras_require=extras_require,
entry_points={'console_scripts': ['tqdm=tqdm._main:main'], },
package_data={'tqdm': ['CONTRIBUTING.md', 'LICENCE', 'examples/*.py',
'tqdm.1']},
long_description=README_rst,
'tqdm.1', 'requirements-dev.txt']},
python_requires='>=2.6, !=3.0.*, !=3.1.*',
classifiers=[
# Trove classifiers
@ -186,12 +98,16 @@ setup(
'Programming Language :: Python :: Implementation :: IronPython',
'Programming Language :: Python :: Implementation :: PyPy',
'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',

17
tox.ini
View File

@ -13,7 +13,7 @@ deps =
coverage
coveralls
commands =
nosetests --with-coverage --cover-package=tqdm --ignore-files="tests_p(erf|andas)\.py" -d -v tqdm/
nosetests --with-coverage --cover-package=tqdm --ignore-files="tests_perf\.py" -d -v tqdm/
- coveralls
[extra]
@ -22,22 +22,18 @@ deps =
nose-timer
codecov
commands =
nosetests --with-coverage --with-timer --cover-package=tqdm --ignore-files="tests_p(erf|andas)\.py" -d -v tqdm/
nosetests --with-coverage --with-timer --cover-package=tqdm --ignore-files="tests_perf\.py" -d -v tqdm/
- coveralls
codecov
[testenv]
# default tests (most things)
passenv = CI TRAVIS TRAVIS_*
passenv = CI TRAVIS TRAVIS_* TOXENV CODECOV_*
deps =
{[extra]deps}
cython
numpy
pandas
commands =
nosetests --with-coverage --with-timer --cover-package=tqdm --ignore-files="tests_perf\.py" -d -v tqdm/
- coveralls
codecov
commands = {[extra]commands}
# no cython/numpy/pandas for py{py,py3,26,33,34}
@ -47,9 +43,12 @@ deps =
nose
coverage
coveralls==1.2.0
codecov
pycparser==2.18
idna==2.7
commands = {[coverage]commands}
commands =
{[coverage]commands}
codecov
[testenv:pypy]
deps = {[extra]deps}