From 508a51e99b8e8cfadf09e9523adafedda406bcbc Mon Sep 17 00:00:00 2001 From: Rohit Sanjay Date: Sat, 3 Aug 2024 01:04:51 -0700 Subject: [PATCH] Modernize setuptools packaging and automate releases --- .bumpversion.cfg | 2 +- .github/workflows/main.yml | 2 +- .github/workflows/publish.yml | 117 ++++++++++++++++++++++++++++++ README.md | 8 +-- RELEASING.md | 4 +- docs/requirements-doc.txt | 3 - pyproject.toml | 129 ++++++++++++++++++++++++++++++---- pytest.ini | 3 - requirements-dev.txt | 18 ----- requirements.txt | 2 - setup.cfg | 44 ------------ setup.py | 78 -------------------- testbook/__init__.py | 1 - testbook/_version.py | 1 - tox.ini | 6 +- 15 files changed, 244 insertions(+), 174 deletions(-) create mode 100644 .github/workflows/publish.yml delete mode 100644 docs/requirements-doc.txt delete mode 100644 pytest.ini delete mode 100644 requirements-dev.txt delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 testbook/_version.py diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 6f4d1e7..de48645 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -4,4 +4,4 @@ commit = True tag = True tag_name = {new_version} -[bumpversion:file:testbook/_version.py] +[bumpversion:file:pyproject.toml] diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0a09d68..bc2b873 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.6, 3.7, 3.8, 3.9, "3.10.0-rc.2"] + python-version: [3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12] env: OS: ubuntu-latest PYTHON: "3.8" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..059e18c --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,117 @@ +name: Publish testbook + +on: push + +jobs: + build: + name: Build distribution 📦 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Install pypa/build + run: >- + python3 -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: python3 -m build + - name: Store the distribution packages + uses: actions/upload-artifact@v3 + with: + name: python-package-distributions + path: dist/ + + publish-to-pypi: + name: >- + Publish Python 🐍 distribution 📦 to PyPI + if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes + needs: + - build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/testbook + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + + steps: + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + github-release: + name: >- + Sign the Python 🐍 distribution 📦 with Sigstore + and upload them to GitHub Release + needs: + - publish-to-pypi + runs-on: ubuntu-latest + + permissions: + contents: write # IMPORTANT: mandatory for making GitHub Releases + id-token: write # IMPORTANT: mandatory for sigstore + + steps: + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Sign the dists with Sigstore + uses: sigstore/gh-action-sigstore-python@v2.1.1 + with: + inputs: >- + ./dist/*.tar.gz + ./dist/*.whl + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ github.token }} + run: >- + gh release create + '${{ github.ref_name }}' + --repo '${{ github.repository }}' + --notes "" + - name: Upload artifact signatures to GitHub Release + env: + GITHUB_TOKEN: ${{ github.token }} + # Upload to GitHub Release using the `gh` CLI. + # `dist/` contains the built packages, and the + # sigstore-produced signatures and certificates. + run: >- + gh release upload + '${{ github.ref_name }}' dist/** + --repo '${{ github.repository }}' + + publish-to-testpypi: + name: Publish Python 🐍 distribution 📦 to TestPyPI + needs: + - build + runs-on: ubuntu-latest + + environment: + name: testpypi + url: https://test.pypi.org/p/testbook + + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + + steps: + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution 📦 to TestPyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ diff --git a/README.md b/README.md index f0d2e07..2df2ce1 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,9 @@ [![Build Status](https://github.com/nteract/testbook/workflows/CI/badge.svg)](https://github.com/nteract/testbook/actions) [![image](https://codecov.io/github/nteract/testbook/coverage.svg?branch=master)](https://codecov.io/github/nteract/testbook?branch=master) [![Documentation Status](https://readthedocs.org/projects/testbook/badge/?version=latest)](https://testbook.readthedocs.io/en/latest/?badge=latest) -[![PyPI](https://img.shields.io/pypi/v/testbook.svg)](https://pypi.org/project/testbook/) -[![Python 3.6](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/downloads/release/python-360/) -[![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/downloads/release/python-370/) -[![Python 3.8](https://img.shields.io/badge/python-3.8-blue.svg)](https://www.python.org/downloads/release/python-380/) -[![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/) +[![image](https://img.shields.io/pypi/v/testbook.svg)](https://pypi.python.org/pypi/testbook) +[![image](https://img.shields.io/pypi/l/testbook.svg)](https://github.com/astral-sh/testbook/blob/main/LICENSE) +[![image](https://img.shields.io/pypi/pyversions/testbook.svg)](https://pypi.python.org/pypi/testbook) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) # testbook diff --git a/RELEASING.md b/RELEASING.md index 79db022..a991b5b 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -3,7 +3,7 @@ ## Prerequisites - First check that the CHANGELOG is up to date for the next release version -- Ensure dev requirements are installed `pip install -r requirements-dev.txt` +- Ensure dev requirements are installed `pip install ".[dev]"` ## Push to GitHub @@ -19,6 +19,6 @@ git push upstream && git push upstream --tags ```bash rm -rf dist/* rm -rf build/* -python setup.py bdist_wheel +python -m build twine upload dist/* ``` diff --git a/docs/requirements-doc.txt b/docs/requirements-doc.txt deleted file mode 100644 index 7ee0a03..0000000 --- a/docs/requirements-doc.txt +++ /dev/null @@ -1,3 +0,0 @@ -Sphinx>=1.7,<3.0 -sphinx_book_theme==0.0.35 -myst-parser==0.9.1 diff --git a/pyproject.toml b/pyproject.toml index 8bfffb8..36496e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,29 +1,132 @@ -# Example configuration for Black. +[build-system] +build-backend = "setuptools.build_meta" -# NOTE: you have to use single-quoted strings in TOML for regular expressions. -# It's the equivalent of r-strings in Python. Multiline strings are treated as -# verbose regular expressions by Black. Use [ ] to denote a significant space -# character. +requires = [ "setuptools" ] + +[project] +name = "testbook_rohitsanjay" +version = "0.4.2" +description = "A unit testing framework for Jupyter Notebooks" +readme = "README.md" +keywords = [ "jupyter", "notebook", "nteract", "unit-testing" ] +license = { file = "LICENSE" } +maintainers = [ + { name = "Nteract Contributors", email = "nteract@googlegroups.com" }, + { name = "Rohit Sanjay", email = "sanjay.rohit2@gmail.com" }, + { name = "Matthew Seal", email = "mseal007@gmail.com" }, +] +authors = [ + { name = "Nteract Contributors", email = "nteract@googlegroups.com" }, + { name = "Rohit Sanjay", email = "sanjay.rohit2@gmail.com" }, + { name = "Matthew Seal", email = "mseal007@gmail.com" }, +] +requires-python = ">=3.6" + +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Software Development :: Testing", + "Topic :: Software Development :: Testing :: Mocking", + "Topic :: Software Development :: Testing :: Unit", +] +dependencies = [ + "nbclient>=0.4", + "nbformat>=5.0.4", +] +optional-dependencies.dev = [ + "black; python_version>='3.6'", + "bumpversion", + "check-manifest", + "codecov", + "coverage", + "flake8", + "ipykernel", + "ipython", + "ipywidgets", + "pandas", + "pip>=18.1", + "pytest>=4.1", + "pytest-cov>=2.6.1", + "setuptools>=38.6", + "tox", + "build", + "twine>=1.11", + "xmltodict", +] +optional-dependencies.test = [ + "myst-parser==0.9.1", + "sphinx>=1.7,<3", + "sphinx-book-theme==0.0.35", +] +urls.Documentation = "https://testbook.readthedocs.io" +urls.Funding = "https://nteract.io" +urls.Issues = "https://github.com/nteract/testbook/issues" +urls.Repository = "https://github.com/nteract/testbook/" [tool.black] line-length = 100 -include = '\.pyi?$' exclude = ''' /( \.git - | \.hg | \.mypy_cache | \.tox | \.venv | _build - | buck-out | build | dist - - # The following are specific to Black, you probably don't want those. - | blib2to3 - | tests/data - | profiling )/ ''' skip-string-normalization = true + +[tool.flake8] +exclude = "__init__.py" +ignore = [ + "E20", # Extra space in brackets + "E231", + "E241", # Multiple spaces around "," + "E26", # Comments + "E4", # Import formatting + "E721", # Comparing types instead of isinstance + "E731", # Assigning lambda expression +] +max-line-length = 120 + +# Not sure I need this? +# [tool.bdist_wheel] +# universal = 0 + +[tool.pytest.ini_options] +filterwarnings = "always" +testpaths = [ + "testbook/tests/", +] + +[tool.coverage.run] +branch = false +omit = [ + "testbook/tests/*", + "testbook/_version.py", +] + +[tool.coverage.report] +exclude_lines = [ + "if self\\.debug:", + "pragma: no cover", + "raise AssertionError", + "raise NotImplementedError", + "if __name__ == '__main__':", +] +ignore_errors = true +omit = [ + "testbook/tests/*", + "testbook/_version.py", +] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 805610b..0000000 --- a/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -testpaths = - testbook/tests/ diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index d3b9874..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,18 +0,0 @@ -codecov -coverage -ipython -ipykernel -ipywidgets -pandas -pytest>=4.1 -pytest-cov>=2.6.1 -check-manifest -flake8 -tox -bumpversion -xmltodict -black; python_version >= '3.6' -pip>=18.1 -wheel>=0.31.0 -setuptools>=38.6.0 -twine>=1.11.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 0f9ff69..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -nbformat>=5.0.4 -nbclient>=0.4.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 58ca2c3..0000000 --- a/setup.cfg +++ /dev/null @@ -1,44 +0,0 @@ - -[flake8] -# References: -# https://flake8.readthedocs.io/en/latest/user/configuration.html -# https://flake8.readthedocs.io/en/latest/user/error-codes.html - -# Note: there cannot be spaces after comma's here -exclude = __init__.py -ignore = - # Extra space in brackets - E20, - # Multiple spaces around "," - E231,E241, - # Comments - E26, - # Import formatting - E4, - # Comparing types instead of isinstance - E721, - # Assigning lambda expression - E731 -max-line-length = 120 - -[bdist_wheel] -universal=0 - -[coverage:run] -branch = False -omit = - testbook/tests/* - testbook/_version.py - -[coverage:report] -exclude_lines = - if self\.debug: - pragma: no cover - raise AssertionError - raise NotImplementedError - if __name__ == .__main__.: -ignore_errors = True -omit = testbook/tests/*,testbook/_version.py - -[tool:pytest] -filterwarnings = always diff --git a/setup.py b/setup.py deleted file mode 100644 index 4b47e06..0000000 --- a/setup.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -"""" -setup.py - -See: -https://packaging.python.org/tutorials/packaging-projects/ -https://packaging.python.org/en/latest/distributing.html -https://github.com/pypa/sampleproject - -""" -import os -from setuptools import setup - - -local_path = os.path.dirname(__file__) -# Fix for tox which manipulates execution pathing -if not local_path: - local_path = '.' -here = os.path.abspath(local_path) - - -def version(): - with open(here + '/testbook/_version.py', 'r') as ver: - for line in ver.readlines(): - if line.startswith('version ='): - return line.split(' = ')[-1].strip()[1:-1] - raise ValueError('No version found in testbook/version.py') - - -def read(fname): - with open(fname, 'r') as fhandle: - return fhandle.read() - - -def read_reqs(fname): - req_path = os.path.join(here, fname) - return [req.strip() for req in read(req_path).splitlines() if req.strip()] - - -long_description = read(os.path.join(os.path.dirname(__file__), "README.md")) -requirements = read(os.path.join(os.path.dirname(__file__), "requirements.txt")) -dev_reqs = read_reqs(os.path.join(os.path.dirname(__file__), 'requirements-dev.txt')) -doc_reqs = read_reqs(os.path.join(os.path.dirname(__file__), 'docs/requirements-doc.txt')) -extras_require = {"test": dev_reqs, "dev": dev_reqs, "sphinx": doc_reqs} - -setup( - name='testbook', - version=version(), - description='A unit testing framework for Jupyter Notebooks', - author='nteract contributors', - author_email='nteract@googlegroups.com', - license='BSD', - # Note that this is a string of words separated by whitespace, not a list. - keywords='jupyter mapreduce nteract pipeline notebook', - long_description=long_description, - long_description_content_type='text/markdown', - url='https://github.com/nteract/testbook', - packages=['testbook'], - python_requires='>=3.6', - install_requires=requirements, - extras_require=extras_require, - project_urls={ - 'Documentation': 'https://testbook.readthedocs.io', - 'Funding': 'https://nteract.io', - 'Source': 'https://github.com/nteract/testbook/', - 'Tracker': 'https://github.com/nteract/testbook/issues', - }, - classifiers=[ - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - ], -) diff --git a/testbook/__init__.py b/testbook/__init__.py index e8f1368..3276cff 100644 --- a/testbook/__init__.py +++ b/testbook/__init__.py @@ -1,2 +1 @@ -from ._version import version as __version__ from .testbook import testbook diff --git a/testbook/_version.py b/testbook/_version.py deleted file mode 100644 index 678d2fe..0000000 --- a/testbook/_version.py +++ /dev/null @@ -1 +0,0 @@ -version = '0.4.2' diff --git a/tox.ini b/tox.ini index 8650731..b124bda 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] skipsdist = true -envlist = py{36,37,38,39,310}, flake8, dist, manifest, docs +envlist = py{36,37,38,39,310,311,312}, flake8, dist, manifest, docs [gh-actions] python = @@ -9,6 +9,8 @@ python = 3.8: py38, flake8, dist, manifest 3.9: py39 3.10: py310 + 3.11: py311 + 3.12: py312 # Linters [testenv:flake8] @@ -45,7 +47,7 @@ commands = # Black [testenv:black] description = apply black linter with desired rules -basepython = python3.6 +basepython = python3.11 deps = black commands = black .