mirror of https://github.com/tqdm/tqdm.git
245 lines
9.1 KiB
Python
Executable File
245 lines
9.1 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
try:
|
|
from setuptools import setup, find_packages
|
|
except ImportError:
|
|
from distutils.core import setup
|
|
|
|
def find_packages(where='.'):
|
|
# os.walk -> list[(dirname, list[subdirs], list[files])]
|
|
return [folder.replace("/", ".").lstrip(".")
|
|
for (folder, _, fils) in os.walk(where)
|
|
if "__init__.py" in fils]
|
|
import sys
|
|
from subprocess import check_call
|
|
from io import open as io_open
|
|
|
|
# For Makefile parsing
|
|
import shlex
|
|
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
|
|
|
|
# Get version from tqdm/_version.py
|
|
__version__ = None
|
|
src_dir = os.path.abspath(os.path.dirname(__file__))
|
|
version_file = os.path.join(src_dir, 'tqdm', '_version.py')
|
|
with io_open(version_file, mode='r') as fd:
|
|
exec(fd.read())
|
|
|
|
# Makefile auxiliary functions #
|
|
|
|
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.
|
|
"""
|
|
|
|
# -- Parsing the Makefile using ConfigParser
|
|
# Adding a fake section to make the Makefile a valid Ini file
|
|
ini_str = '[root]\n'
|
|
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)
|
|
# Parse 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:
|
|
if alias.lower() in ['.phony']:
|
|
continue
|
|
# strip the first line return, and then split by any line return
|
|
commands[alias] = config.get('root', alias).lstrip('\n').split('\n')
|
|
|
|
# -- Commands substitution
|
|
# 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 = list(commands.keys())
|
|
# Create the dict that will hold the 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]:
|
|
# Ignore self-referencing (alias points to itself)
|
|
if cmd == alias:
|
|
pass
|
|
# 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])
|
|
# 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]
|
|
aliases_todo.append(alias)
|
|
break
|
|
# 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]
|
|
|
|
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 (ie, not just a comment)
|
|
if parsed_cmd:
|
|
if verbose:
|
|
print("Running command: " + cmd)
|
|
# Launch the command and wait to finish (synchronized call)
|
|
check_call(parsed_cmd, cwd=src_dir)
|
|
|
|
|
|
# Main setup.py config #
|
|
|
|
|
|
# Executing makefile commands if specified
|
|
if sys.argv[1].lower().strip() == 'make':
|
|
# 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
|
|
if len(sys.argv) < 3 or sys.argv[-1] == '--help':
|
|
print("Shortcut to use commands via aliases. List of aliases:")
|
|
print('\n'.join(alias for alias in sorted(commands.keys())))
|
|
|
|
# Else process the commands for this alias
|
|
else:
|
|
arg = sys.argv[-1]
|
|
# if unit testing, we do nothing (we just checked the makefile parsing)
|
|
if arg == 'none':
|
|
sys.exit(0)
|
|
# else if the alias exists, we execute its commands
|
|
elif arg in commands.keys():
|
|
execute_makefile_commands(commands, arg, verbose=True)
|
|
# 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 = ''
|
|
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',
|
|
license='MPLv2.0, MIT Licences',
|
|
author='Noam Yorav-Raphael',
|
|
author_email='noamraph@gmail.com',
|
|
url='https://github.com/tqdm/tqdm',
|
|
maintainer='tqdm developers',
|
|
maintainer_email='python.tqdm@gmail.com',
|
|
platforms=['any'],
|
|
packages=['tqdm'] + ['tqdm.' + i for i in find_packages('tqdm')],
|
|
entry_points={'console_scripts': ['tqdm=tqdm._main:main'], },
|
|
data_files=[('man/man1', ['tqdm.1'])],
|
|
package_data={'': ['CONTRIBUTING.md', 'LICENCE', 'examples/*.py']},
|
|
long_description=README_rst,
|
|
python_requires='>=2.6, !=3.0.*, !=3.1.*',
|
|
classifiers=[
|
|
# Trove classifiers
|
|
# (https://pypi.python.org/pypi?%3Aaction=list_classifiers)
|
|
'Development Status :: 5 - Production/Stable',
|
|
'Environment :: Console',
|
|
'Environment :: MacOS X',
|
|
'Environment :: Other Environment',
|
|
'Environment :: Win32 (MS Windows)',
|
|
'Environment :: X11 Applications',
|
|
'Framework :: IPython',
|
|
'Intended Audience :: Developers',
|
|
'Intended Audience :: Education',
|
|
'Intended Audience :: End Users/Desktop',
|
|
'Intended Audience :: Other Audience',
|
|
'Intended Audience :: System Administrators',
|
|
'License :: OSI Approved :: MIT License',
|
|
'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
|
|
'Operating System :: MacOS :: MacOS X',
|
|
'Operating System :: Microsoft :: Windows',
|
|
'Operating System :: POSIX',
|
|
'Operating System :: POSIX :: BSD',
|
|
'Operating System :: POSIX :: BSD :: FreeBSD',
|
|
'Operating System :: POSIX :: Linux',
|
|
'Operating System :: POSIX :: SunOS/Solaris',
|
|
'Programming Language :: Python',
|
|
'Programming Language :: Python :: 2',
|
|
'Programming Language :: Python :: 2.6',
|
|
'Programming Language :: Python :: 2.7',
|
|
'Programming Language :: Python :: 3',
|
|
'Programming Language :: Python :: 3.2',
|
|
'Programming Language :: Python :: 3.3',
|
|
'Programming Language :: Python :: 3.4',
|
|
'Programming Language :: Python :: 3.5',
|
|
'Programming Language :: Python :: 3.6',
|
|
'Programming Language :: Python :: 3.7',
|
|
'Programming Language :: Python :: Implementation',
|
|
'Programming Language :: Python :: Implementation :: IronPython',
|
|
'Programming Language :: Python :: Implementation :: PyPy',
|
|
'Topic :: Desktop Environment',
|
|
'Topic :: Education :: Testing',
|
|
'Topic :: Office/Business',
|
|
'Topic :: Other/Nonlisted Topic',
|
|
'Topic :: Software Development :: Libraries',
|
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
|
'Topic :: Software Development :: User Interfaces',
|
|
'Topic :: System :: Logging',
|
|
'Topic :: System :: Monitoring',
|
|
'Topic :: System :: Shells',
|
|
'Topic :: Terminals',
|
|
'Topic :: Utilities'
|
|
],
|
|
keywords='progressbar progressmeter progress bar meter'
|
|
' rate eta console terminal time',
|
|
test_suite='nose.collector',
|
|
tests_require=['nose', 'flake8', 'coverage'],
|
|
)
|