diff --git a/.gitignore b/.gitignore index c060b42a6a8..850d5aba786 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ pip-log.txt # Coverage artifacts .coverage coverage.xml +pip-wheel-metadata diff --git a/.travis.yml b/.travis.yml index 87aacd71f27..9fcfdfd92b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -150,3 +150,9 @@ install: script: - tox -v +# test that install and uninstall from source works +- pip install . && pip uninstall ansible-lint +# test that install and uninstall as editable also works +- pip install -e . && pip uninstall ansible-lint +# test that use as a pre-commit hook still works +- pip install pre-commit && pre-commit try-repo . \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000000..c95e6d1e453 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ +[build-system] +requires = [ + "pip>=19.1.1", + "setuptools >= 41.0.0", + "setuptools_scm >= 1.15.0", + "setuptools_scm_git_archive >= 1.0", + "wheel", +] +build-backend = "setuptools.build_meta" diff --git a/setup.cfg b/setup.cfg index b432821538f..dbf144ccb49 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,6 +20,7 @@ project_urls = Source Code = https://github.com/ansible/ansible-lint description = Checks playbooks for practices and behaviour that could potentially be improved long_description = file: README.rst +long_description_content_type = text/x-rst author = Will Thames author_email = will@thames.id.au maintainer = Ansible by Red Hat diff --git a/setup.py b/setup.py index 25cc9e80d09..8d30120d295 100644 --- a/setup.py +++ b/setup.py @@ -1,150 +1,5 @@ -#! /usr/bin/env python -"""Ansible-lint distribution package setuptools installer.""" - +#!/usr/bin/env python import setuptools - -try: - from setuptools.config import read_configuration, ConfigOptionsHandler - import setuptools.config - import setuptools.dist - - # Set default value for 'use_scm_version' - setattr(setuptools.dist.Distribution, 'use_scm_version', False) - - # Attach bool parser to 'use_scm_version' option - class ShimConfigOptionsHandler(ConfigOptionsHandler): - """Extension class for ConfigOptionsHandler.""" - - @property - def parsers(self): - """Return an option mapping with default data type parsers.""" - _orig_parsers = super(ShimConfigOptionsHandler, self).parsers - return dict(use_scm_version=self._parse_bool, **_orig_parsers) - - setuptools.config.ConfigOptionsHandler = ShimConfigOptionsHandler -except ImportError: - """This is a shim for setuptools<30.3.""" - import io - import json - - try: - from configparser import ConfigParser, NoSectionError - except ImportError: - from ConfigParser import ConfigParser, NoSectionError - ConfigParser.read_file = ConfigParser.readfp - - def maybe_read_files(d): - """Read files if the string starts with `file:` marker.""" - d = d.strip() - if not d.startswith('file:'): - return d - descs = [] - for fname in map(str.strip, str(d[5:]).split(',')): - with io.open(fname, encoding='utf-8') as f: - descs.append(f.read()) - return ''.join(descs) - - def cfg_val_to_list(v): - """Turn config val to list and filter out empty lines.""" - return list(filter(bool, map(str.strip, str(v).strip().splitlines()))) - - def cfg_val_to_dict(v): - """Turn config val to dict and filter out empty lines.""" - return dict( - map(lambda l: list(map(str.strip, l.split('=', 1))), - filter(bool, map(str.strip, str(v).strip().splitlines()))) - ) - - def cfg_val_to_primitive(v): - """Parse primitive config val to appropriate data type.""" - return json.loads(v.strip().lower()) - - def read_configuration(filepath): - """Read metadata and options from setup.cfg located at filepath.""" - cfg = ConfigParser() - with io.open(filepath, encoding='utf-8') as f: - cfg.read_file(f) - - md = dict(cfg.items('metadata')) - for list_key in 'classifiers', 'keywords': - try: - md[list_key] = cfg_val_to_list(md[list_key]) - except KeyError: - pass - try: - md['long_description'] = maybe_read_files(md['long_description']) - except KeyError: - pass - opt = dict(cfg.items('options')) - for list_key in 'use_scm_version', 'zip_safe': - try: - opt[list_key] = cfg_val_to_primitive(opt[list_key]) - except KeyError: - pass - for list_key in 'scripts', 'install_requires', 'setup_requires': - try: - opt[list_key] = cfg_val_to_list(opt[list_key]) - except KeyError: - pass - try: - opt['package_dir'] = cfg_val_to_dict(opt['package_dir']) - except KeyError: - pass - try: - opt_package_data = dict(cfg.items('options.package_data')) - if not opt_package_data.get('', '').strip(): - opt_package_data[''] = opt_package_data['*'] - del opt_package_data['*'] - except (KeyError, NoSectionError): - opt_package_data = {} - try: - opt_extras_require = dict(cfg.items('options.extras_require')) - opt['extras_require'] = {} - for k, v in opt_extras_require.items(): - opt['extras_require'][k] = cfg_val_to_list(v) - except NoSectionError: - pass - opt['package_data'] = {} - for k, v in opt_package_data.items(): - opt['package_data'][k] = cfg_val_to_list(v) - cur_pkgs = opt.get('packages', '').strip() - if '\n' in cur_pkgs: - opt['packages'] = cfg_val_to_list(opt['packages']) - elif cur_pkgs.startswith('find:'): - opt_packages_find = dict(cfg.items('options.packages.find')) - opt['packages'] = setuptools.find_packages(**opt_packages_find) - return {'metadata': md, 'options': opt} - - -setup_params = {} -declarative_setup_params = read_configuration('setup.cfg') - -# Patch incorrectly decoded package_dir option -# ``egg_info`` demands native strings failing with unicode under Python 2 -# Ref https://github.com/pypa/setuptools/issues/1136 -declarative_setup_params['options']['package_dir'] = { - str(k): str(v) - for k, v in declarative_setup_params['options']['package_dir'].items() -} - -setup_params = dict(setup_params, **declarative_setup_params['metadata']) -setup_params = dict(setup_params, **declarative_setup_params['options']) - - -def cut_local_version_on_upload(version): - import os - import setuptools_scm.version # only present during setup time - IS_PYPI_UPLOAD = os.getenv('PYPI_UPLOAD') == 'true' - return ( - '' if IS_PYPI_UPLOAD - else setuptools_scm.version.get_local_node_and_date(version) - ) - - -setup_params['use_scm_version'] = { - 'local_scheme': cut_local_version_on_upload, -} - - -__name__ == '__main__' and setuptools.setup(**setup_params) +if __name__ == "__main__": + setuptools.setup(use_scm_version=True) diff --git a/tox.ini b/tox.ini index 0b4aa6c2fee..8698d9d9128 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,11 @@ deps = pep8-naming wheel commands = nosetests [] -passenv = HOME +passenv = + CURL_CA_BUNDLE + HOME + REQUESTS_CA_BUNDLE + SSL_CERT_FILE # recreate = True [testenv:flake8] @@ -31,10 +35,21 @@ usedevelop = True [testenv:metadata-validation] deps = - collective.checkdocs - twine + collective.checkdocs>=0.2 + pep517 >= 0.5.0 + pip>=19.1.1 + setuptools>=39.0 + twine>=1.13.0 + wheel>=0.31.0 + usedevelop = False # Ref: https://twitter.com/di_codes/status/1044358639081975813 commands = - python -m setup checkdocs check --metadata --restructuredtext --strict --verbose - twine check .tox/dist/* + rm -rf {toxinidir}/dist + python -m pep517.build \ + --source \ + --binary \ + --out-dir {toxinidir}/dist/ \ + {toxinidir} + python -m twine check {toxinidir}/dist/* +whitelist_externals = rm \ No newline at end of file