From f6714a399003e660d310172391dfb762ea306b00 Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Tue, 9 Jun 2020 01:07:31 +0000 Subject: Convert build system to tox This is the current modern way to build, package, and test python code. --- .github/workflows/build.yml | 6 +- .github/workflows/release.yml | 23 +++++ .gitignore | 3 +- CONTRIBUTING.rst | 2 +- pandora/__init__.py | 1 + setup.cfg | 82 +++++++++++++++++ setup.py | 206 +----------------------------------------- 7 files changed, 114 insertions(+), 209 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 setup.cfg diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f63125..f3833be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,6 +13,7 @@ jobs: os: - ubuntu-latest - macos-latest + python-version: - 3.5 - 3.6 @@ -26,5 +27,6 @@ jobs: with: python-version: ${{ matrix.python-version }} - - run: pip install -U pip setuptools wheel mock nose pytest - - run: python setup.py release + - run: | + pip install tox + tox -e tests,release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..f47c613 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,23 @@ +name: release + +on: + push: + tags: + - 'release-*' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - env: + TWINE_PASSWORD: ${{ secrets.PYPI_API_KEY }} + run: | + pip install tox + tox -e tests,release,upload diff --git a/.gitignore b/.gitignore index 720ed08..8e383bc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,8 @@ .coverage/ .eggs/ .py3/ -.sandbox_name +.tox/ build/ -coverage.xml dist/ htmlcov/ pydora.egg-info/ diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 7e95437..2671c63 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -16,5 +16,5 @@ your changes. To have the best experience contributing, please: All code is reviewed before acceptance and changes may be requested to better follow the conventions of the existing API. -The build system runs ``python setup.py release`` on all supported Python +The build system runs ``tox -e tests,release`` on all supported Python versions. You can, and should, run this on your pull request before submitting. diff --git a/pandora/__init__.py b/pandora/__init__.py index e69de29..159d48b 100644 --- a/pandora/__init__.py +++ b/pandora/__init__.py @@ -0,0 +1 @@ +__version__ = "2.0.1" diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..a6c5c6d --- /dev/null +++ b/setup.cfg @@ -0,0 +1,82 @@ +[metadata] +name = pydora +version = attr: pandora.__version__ +description = Python wrapper for Pandora API +long_description = file: README.rst +author = Mike Crute +author_email = mike@crute.us +url = https://github.com/mcrute/pydora +classifiers = + Development Status :: 5 - Production/Stable + Environment :: Console + Intended Audience :: Developers + Intended Audience :: End Users/Desktop + License :: OSI Approved :: MIT License + Operating System :: OS Independent + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.5 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3 :: Only + Topic :: Internet :: WWW/HTTP + Topic :: Multimedia :: Sound/Audio :: Players + +[options] +packages = find: +python_requires = >=3.5 + +install_requires = + requests >=2, <3 + blowfish >=0.6.1, <1.0 + +[options.packages.find] +exclude = + tests + tests.* + +[options.entry_points] +distutils.commands = + pydora = pydora.player:main + pydora-configure = pydora.configure:main + +[testenv:format] +deps = + black + +commands = + black -l 79 -t py35 pandora/ pydora/ tests/ setup.py + +[testenv:tests] +deps = + pytest + black + flake8 >=3.3 + coverage >=4.1, <5 + +commands = + black --check -l 79 -t py35 pandora/ pydora/ tests/ setup.py + flake8 --statistics --ignore=E231 pandora/ pydora/ tests/ setup.py + coverage run --source='pandora/,pydora/' -m pytest + coverage report --fail-under 100 -m --include='pandora/*' + coverage report -m --include='pydora/*' + coverage html --include='pandora/*,pydora/*' + +[testenv:release] +deps = + wheel + +commands = + python setup.py sdist bdist_wheel + +[testenv:upload] +skip_install = true + +deps = + twine + +passenv = + TWINE_PASSWORD + +commands = + twine upload -u __token__ --non-interactive --skip-existing dist/* diff --git a/setup.py b/setup.py index d7344c5..f5a3845 100755 --- a/setup.py +++ b/setup.py @@ -1,208 +1,6 @@ #!/usr/bin/env python -import os -import math -import shutil -import subprocess -from distutils import log -from distutils.core import Command -from setuptools.command.test import test -from distutils.errors import DistutilsError -from setuptools import setup, find_packages +import setuptools -class Release(Command): - - user_options = [] - description = "build and test package with linting" - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - self.run_command("test") - - # Flake8 should examine tests too - self.distribution.packages = find_packages() - self.run_command("flake8") - - -class TestsWithCoverage(test): - - description = "run unit tests with coverage" - - coverage_goal = 100 - missed_branches_goal = 0 - partial_branches_goal = 0 - - def initialize_options(self): - super().initialize_options() - self.missed_coverage_goals = False - - def enforce_coverage_goals(self, rel_path, analysis): - # There is no coverage goal for the player package, just the API - if os.path.split(rel_path)[0] == "pydora": - return - - coverage_percent = math.ceil(analysis.numbers.pc_covered) - if coverage_percent != self.coverage_goal: - self.missed_coverage_goals = True - self.announce( - "Coverage: {!r} coverage is {}%, goal is {}%".format( - rel_path, coverage_percent, self.coverage_goal - ), - log.ERROR, - ) - - missed_branches = analysis.numbers.n_missing_branches - if missed_branches != self.missed_branches_goal: - self.missed_coverage_goals = True - self.announce( - "Coverage: {!r} missed branch count is {}, goal is {}".format( - rel_path, missed_branches, self.missed_branches_goal - ), - log.ERROR, - ) - - partially_covered_branches = analysis.numbers.n_partial_branches - if partially_covered_branches != self.partial_branches_goal: - self.missed_coverage_goals = True - self.announce( - "Coverage: {!r} partial branch count is {}, goal is {}".format( - rel_path, - partially_covered_branches, - self.partial_branches_goal, - ), - log.ERROR, - ) - - def run(self): - from coverage import Coverage - - cov = Coverage(source=self.distribution.packages, branch=True) - - cov.start() - super().run() - cov.stop() - - # Save HTML report for debugging missed coverage - cov.html_report() - - # Print coverage report to console for CI log - cov.report() - - for rep in cov._get_file_reporters(): - self.enforce_coverage_goals(rep.relname, cov._analyze(rep)) - - if self.missed_coverage_goals: - raise DistutilsError("Project missed coverage goals") - - -class PyPiReleaseCommand(Command): - - user_options = [] - description = "build and release artifacts to pypi" - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def venv_run(self, cmd, *args): - subprocess.check_call((os.path.join(".release/py3/bin", cmd),) + args) - - def make_release_tree(self): - if not os.path.exists(".release"): - log.info("Creating temp release tree") - os.mkdir(".release") - - def configure_environment(self): - log.info("Configuring release environment") - subprocess.check_call(["python3", "-m", "venv", ".release/py3"]) - self.venv_run( - "pip", "install", "-U", "pip", "setuptools", "virtualenv", "twine" - ) - - def build_py3_artifact(self): - log.info("Building Python 3 Artifact") - self.venv_run( - "python", - "setup.py", - "release", - "bdist_wheel", - "--python-tag", - "py3", - ) - - def build_sdist_artifact(self): - log.info("Building Source Dist Artifact") - self.venv_run("python", "setup.py", "sdist") - - def upload_artifacts(self): - log.info("Uploading artifacts to PyPi") - self.venv_run("twine", "upload", "dist/*") - - def cleanup(self): - log.info("Cleaning up temp release tree") - shutil.rmtree(".release") - - def run(self): - try: - self.make_release_tree() - self.configure_environment() - self.build_py3_artifact() - self.build_sdist_artifact() - self.upload_artifacts() - finally: - self.cleanup() - - -setup( - name="pydora", - version="2.0.0", - description="Python wrapper for Pandora API", - long_description=open("README.rst", "r").read(), - author="Mike Crute", - author_email="mike@crute.us", - url="https://github.com/mcrute/pydora", - test_suite="tests.discover_suite", - packages=find_packages(exclude=["tests", "tests.*"]), - cmdclass={ - "test": TestsWithCoverage, - "pypi_release": PyPiReleaseCommand, - "release": Release, - }, - entry_points={ - "console_scripts": [ - "pydora = pydora.player:main", - "pydora-configure = pydora.configure:main", - ], - }, - setup_requires=[ - "wheel", - "flake8>=3.3", - "setuptools>=36.0.1", - "coverage>=4.1,<5", - ], - install_requires=["requests>=2,<3", "blowfish>=0.6.1,<1.0",], - python_requires=">=3.5", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Intended Audience :: Developers", - "Intended Audience :: End Users/Desktop", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3 :: Only", - "Topic :: Internet :: WWW/HTTP", - "Topic :: Multimedia :: Sound/Audio :: Players", - ], -) +setuptools.setup() -- cgit v1.2.3