mirror of https://github.com/tqdm/tqdm.git
Add `python setup.py make [alias]` (aka Makefile parsing in setup.py)
+ Tox check Signed-off-by: Stephen L. <lrq3000@gmail.com>
This commit is contained in:
parent
2da04c5866
commit
7405a59ff2
13
CONTRIBUTE
13
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/
|
||||
|
|
31
Makefile
31
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
|
||||
|
|
12
RELEASE
12
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:
|
||||
|
|
121
setup.py
121
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__,
|
||||
|
|
Loading…
Reference in New Issue