From d18987775b07c06771760d139f3ae1ee733250f3 Mon Sep 17 00:00:00 2001 From: ken-morel Date: Wed, 1 May 2024 23:56:15 +0100 Subject: [PATCH] Initial commit --- .dockerignore | 5 ++ .github/workflows/python-publish.yml | 45 ++++++++++++ .github/workflows/test.yml | 64 ++++++++++++++++ .gitignore | 10 +++ LICENSE | 7 ++ Makefile | 25 +++++++ README.md | 47 ++++++++++++ docker-compose.yml | 43 +++++++++++ dockerfiles/dev.dockerfile | 9 +++ src/.coveragerc | 2 + src/.flake8 | 2 + src/pip_package_template_docker/__init__.py | 1 + src/setup.py | 81 +++++++++++++++++++++ src/tests/__init__.py | 0 src/tests/test_placeholder.py | 10 +++ 15 files changed, 351 insertions(+) create mode 100644 .dockerignore create mode 100644 .github/workflows/python-publish.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 dockerfiles/dev.dockerfile create mode 100644 src/.coveragerc create mode 100644 src/.flake8 create mode 100644 src/pip_package_template_docker/__init__.py create mode 100644 src/setup.py create mode 100644 src/tests/__init__.py create mode 100644 src/tests/test_placeholder.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..57ebe20 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +**/.* +!**/.flake8 +!**/.coveragerc + +**/__pycache__ diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..d0e2a91 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,45 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [ published ] + +permissions: + contents: read + +defaults: + run: + working-directory: src + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.11' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: | + cp ../README.md ../LICENSE ./ + python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} + packages_dir: src/dist diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..2a30a98 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,64 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Test + +on: + - push + - pull_request + +defaults: + run: + working-directory: src + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - "3.7" + - "3.8" + - "3.9" + - "3.10" + - "3.11" + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + cp ../README.md ../LICENSE ./ + python -m pip install --upgrade pip setuptools + pip install -e .[ci] + - name: Lint with flake8 + run: | + flake8 + - name: Test with pytest + run: | + pytest --cov --cov-report term-missing:skip-covered + - name: Upload to Coveralls + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_FLAG_NAME: ${{ matrix.python-version }} + COVERALLS_PARALLEL: true + run: | + coveralls --service=github + + coveralls: + name: Indicate completion to coveralls.io + needs: test + runs-on: ubuntu-latest + container: python:3-slim + steps: + - name: Finished + run: | + python -m pip install --upgrade coveralls + coveralls --service=github --finish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + working-directory: '' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a15290d --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.idea + +__pycache__ + +.coverage +.pytest_cache +*.egg-info +/src/dist +/src/README.md +/src/LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c20bc5c --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright 2023 Zheng Jin + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2a9db81 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +build: + docker-compose build --pull + +lint: + docker-compose run --rm dev flake8 + +test: + docker-compose run --rm dev pytest --cov --cov-report term-missing:skip-covered + +test37: + docker-compose run --rm test37 + +test38: + docker-compose run --rm test38 + +test39: + docker-compose run --rm test39 + +test310: + docker-compose run --rm test310 + +ci: build lint test test37 test38 test38 test39 test310 + +sdist: + docker-compose run --rm dev python setup.py sdist diff --git a/README.md b/README.md new file mode 100644 index 0000000..84a62ed --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# pip-package-template-docker + +[![Release Status](https://github.com/MichaelKim0407/pip-package-template-docker/actions/workflows/python-publish.yml/badge.svg)](https://github.com/MichaelKim0407/pip-package-template-docker/releases) +[![PyPI package](https://badge.fury.io/py/pip-package-template-docker.svg)](https://pypi.org/project/pip-package-template-docker) +[![Supported Python versions](https://img.shields.io/pypi/pyversions/pip-package-template-docker)](https://pypi.org/project/pip-package-template-docker) +[![Build Status](https://github.com/MichaelKim0407/pip-package-template-docker/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/MichaelKim0407/pip-package-template-docker/tree/main) +[![Coverage Status](https://coveralls.io/repos/github/MichaelKim0407/pip-package-template-docker/badge.svg?branch=main)](https://coveralls.io/github/MichaelKim0407/pip-package-template-docker?branch=main) + +Project template for Dockerized pip package development. + +## Overview + +1. This project is fully Dockerized. For convenience, a [`Makefile`](Makefile) is provided to build/test during development. +2. Python 3.11 is the primary version for development, while 3.7 - 3.10 are included for compatibility. You may want to change them in the future. + See [`docker-compose.yml`](docker-compose.yml) and [`Makefile`](Makefile). + Refer to [this page](https://devguide.python.org/versions/) for Python versions you may want to support. +3. Linting is done using `flake8` and testing is done using `pytest`. +4. CI is designed for GitHub Actions. See [`.github`](.github). Coverage is reported to [Coveralls](https://coveralls.io/). +5. An automatic release to Pypi is made through GitHub Actions whenever you publish a new release on GitHub. +6. `LICENSE` in the template is MIT. + +## How to use + +1. Please familiarize yourself with all the concept involved. I am not responsible for things breaking if you use this template. + * Python and different Python versions + * Creating pip packages. I made a tutorial a few years ago, which you can see [here](https://github.com/MichaelKim0407/tutorial-pip-package). + * Docker and docker-compose + * Linting and flake8 + * Unit testing and pytest + * CI and GitHub Actions + * Code coverage +2. Find all instances of `pip-package-template-docker` and replace them with your desired package name. + This is the **name** of your package known to Pypi and `pip install`. +3. Rename the [`src/pip_package_template_docker`](src/pip_package_template_docker) folder. + Find all instances of `pip_package_template_docker` and replace them accordingly. + This is what your `import` statement would use in Python code. +4. Go through [`src/setup.py`](src/setup.py) and make necessary changes. Please do not link your project to my name, email, or GitHub. +5. Replace [`README.md`](README.md) with your own. If you would like to use the badges, please change the links to point to your project. +6. Replace [`LICENSE`](LICENSE) with your own. Please do not license your project under my name. +7. Project version is found in the [`__init__.py`](src/pip_package_template_docker/__init__.py) file in your package. + Update it accordingly as you develop your package. +8. Put unittests under [`src/tests`](src/tests). +9. Sign up for necessary accounts, such as [Pypi](https://pypi.org/) and [Coveralls](https://coveralls.io/). +10. Acquire a Pypi token and put it under your project as `PYPI_API_TOKEN`. + On Pypi it is found under Account settings -> API tokens -> Add API token. + On GitHub it is located in your project settings -> Security -> Secrets and variables -> Repository secrets. + You may need to manually update once before a project-specific token can be acquired. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..db7343c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,43 @@ +version: '3.8' + +services: + dev: + build: + context: . + dockerfile: dockerfiles/dev.dockerfile + volumes: + - ./src:/src + - ./README.md:/src/README.md + - ./LICENSE:/src/LICENSE + + test37: + build: + context: . + dockerfile: dockerfiles/dev.dockerfile + args: + PYTHON_VERSION: '3.7' + command: pytest + + test38: + build: + context: . + dockerfile: dockerfiles/dev.dockerfile + args: + PYTHON_VERSION: '3.8' + command: pytest + + test39: + build: + context: . + dockerfile: dockerfiles/dev.dockerfile + args: + PYTHON_VERSION: '3.9' + command: pytest + + test310: + build: + context: . + dockerfile: dockerfiles/dev.dockerfile + args: + PYTHON_VERSION: '3.10' + command: pytest diff --git a/dockerfiles/dev.dockerfile b/dockerfiles/dev.dockerfile new file mode 100644 index 0000000..39c54ba --- /dev/null +++ b/dockerfiles/dev.dockerfile @@ -0,0 +1,9 @@ +ARG PYTHON_VERSION=3.11 +FROM python:${PYTHON_VERSION} + +WORKDIR /src +COPY src/setup.py README.md LICENSE ./ +COPY src/pip_package_template_docker/__init__.py ./pip_package_template_docker/__init__.py +RUN pip install -e .[dev] + +COPY src . diff --git a/src/.coveragerc b/src/.coveragerc new file mode 100644 index 0000000..54a9140 --- /dev/null +++ b/src/.coveragerc @@ -0,0 +1,2 @@ +[run] +source = pip_package_template_docker diff --git a/src/.flake8 b/src/.flake8 new file mode 100644 index 0000000..6deafc2 --- /dev/null +++ b/src/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 120 diff --git a/src/pip_package_template_docker/__init__.py b/src/pip_package_template_docker/__init__.py new file mode 100644 index 0000000..12c4bf4 --- /dev/null +++ b/src/pip_package_template_docker/__init__.py @@ -0,0 +1 @@ +__version__ = '2023.04.23.post1' diff --git a/src/setup.py b/src/setup.py new file mode 100644 index 0000000..80001f2 --- /dev/null +++ b/src/setup.py @@ -0,0 +1,81 @@ +from pathlib import Path + +from setuptools import setup, find_packages + +from pip_package_template_docker import __version__ + +project_dir = Path(__file__).parent +try: + long_description = (project_dir / 'README.md').read_text() +except FileNotFoundError: + long_description = '' + +deps = () + +extra_flake8 = ( + 'flake8', + 'flake8-commas', + 'flake8-quotes', + 'flake8-multiline-containers', +) + +extra_test = ( + 'pytest', + 'pytest-cov', +) + +extra_dev = ( + *extra_flake8, + *extra_test, +) + +extra_ci = ( + *extra_flake8, + *extra_test, + 'coveralls', +) + +setup( + name='pip-package-template-docker', + version=__version__, + packages=find_packages(exclude=['tests', 'tests.*']), + url='https://github.com/MichaelKim0407/pip-package-template-docker', + license='MIT', + author='Zheng Jin', + author_email='mkim0407@gmail.com', + description='Project template for Dockerized pip package development.', + long_description=long_description, + long_description_content_type='text/markdown', + + install_requires=deps, + extras_require={ + 'dev': extra_dev, + 'ci': extra_ci, + }, + + classifiers=[ + # See https://pypi.org/classifiers/ + + 'Intended Audience :: Developers', + + # 'Development Status :: 1 - Planning', + # 'Development Status :: 2 - Pre-Alpha', + # 'Development Status :: 3 - Alpha', + # 'Development Status :: 4 - Beta', + # 'Development Status :: 5 - Production/Stable', + # 'Development Status :: 6 - Mature', + # 'Development Status :: 7 - Inactive', + + 'License :: OSI Approved :: MIT License', + + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + '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', + + 'Topic :: Software Development :: Libraries :: Python Modules', + ], +) diff --git a/src/tests/__init__.py b/src/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/test_placeholder.py b/src/tests/test_placeholder.py new file mode 100644 index 0000000..a35995c --- /dev/null +++ b/src/tests/test_placeholder.py @@ -0,0 +1,10 @@ +from pip_package_template_docker import __version__ + + +def test_placeholder(): + """ + A placeholder test. Remove when there are actual tests. + + This is to ensure pytest can pass because it will report an error if it cannot find any test. + """ + assert isinstance(__version__, str)