From 9b1a024ef655928739292e49598619869afe1705 Mon Sep 17 00:00:00 2001 From: Bruno Rocha Date: Sat, 14 Aug 2021 02:17:28 +0100 Subject: [PATCH] first commit --- .github/release_message.sh | 3 + .github/workflows/main.yml | 90 ++++++++++++++++++++++++ .github/workflows/release.yml | 48 +++++++++++++ .gitignore | 129 ++++++++++++++++++++++++++++++++++ Containerfile | 5 ++ HISTORY.md | 0 LICENSE | 24 +++++++ Makefile | 70 ++++++++++++++++++ README.md | 56 +++++++++++++++ project_name/__init__.py | 3 + project_name/__main__.py | 16 +++++ project_name/base.py | 21 ++++++ setup.py | 32 +++++++++ tests/__init__.py | 0 tests/conftest.py | 0 tests/test_base.py | 18 +++++ 16 files changed, 515 insertions(+) create mode 100755 .github/release_message.sh create mode 100644 .github/workflows/main.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 Containerfile create mode 100644 HISTORY.md create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 project_name/__init__.py create mode 100644 project_name/__main__.py create mode 100644 project_name/base.py create mode 100644 setup.py create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_base.py diff --git a/.github/release_message.sh b/.github/release_message.sh new file mode 100755 index 0000000..f5a9062 --- /dev/null +++ b/.github/release_message.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +previous_tag=$(git tag --sort=-creatordate | sed -n 2p) +git shortlog "${previous_tag}.." | sed 's/^./ &/' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..d2a2e09 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,90 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ main ] + pull_request: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + linter: + strategy: + fail-fast: false + matrix: + python-version: [3.9] + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install project + run: make install + - name: Run linter + run: make lint + + tests_linux: + needs: linter + strategy: + fail-fast: false + matrix: + python-version: [3.9] + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install project + run: make install + - name: Run tests + run: make test + - name: "Upload coverage to Codecov" + uses: codecov/codecov-action@v1 + # with: + # fail_ci_if_error: true + + tests_mac: + needs: linter + strategy: + fail-fast: false + matrix: + python-version: [3.9] + os: [macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install project + run: make install + - name: Run tests + run: make test + + tests_win: + needs: linter + strategy: + fail-fast: false + matrix: + python-version: [3.9] + os: [windows-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install project + run: pip install -e .[test] + - name: run tests + run: pytest -s -vvvv -l --tb=long tests diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..d3033aa --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,48 @@ +name: Upload Python Package + +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - '*' # Push events to matching v*, i.e. v1.0, v20.15.10 + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + release: + name: Create Release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + # by default, it uses a depth of 1 + # this fetches all history so that we can read each commit + fetch-depth: 0 + - name: Generate Changelog + run: .github/release_message.sh > release_message.md + - name: Release + uses: softprops/action-gh-release@v1 + with: + body_path: release_message.md + + deploy: + needs: release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6e4761 --- /dev/null +++ b/.gitignore @@ -0,0 +1,129 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/Containerfile b/Containerfile new file mode 100644 index 0000000..c78f074 --- /dev/null +++ b/Containerfile @@ -0,0 +1,5 @@ +FROM python:3.7-alpine +COPY . /app +WORKDIR /app +RUN pip install . +CMD ["project_name"] diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bbdb566 --- /dev/null +++ b/Makefile @@ -0,0 +1,70 @@ +.ONESHELL: + +.PHONY: help +help: ## Show the help. + @echo "Usage: make " + @echo "" + @echo "Targets:" + @fgrep "##" Makefile | fgrep -v fgrep + +.PHONY: install +install: ## Install the project in dev mode. + pip install -e .[test] + +.PHONY: fmt +fmt: ## Format code using black & isort. + isort project_name/ + black -l 79 project_name/ + +.PHONY: lint +lint: ## Run pep8, black, mypy linters. + flake8 project_name/ + black -l 79 --check project_name/ + mypy project_name/ + +.PHONY: test +test: lint ## Run tests and generate coverage report. + pytest -v --cov-config .coveragerc --cov=project_name -l --tb=short --maxfail=1 tests/ + coverage xml + coverage html + +.PHONY: watch +watch: ## Run tests on every change. + ls **/**.py | entr pytest -s -vvv -l --tb=long --maxfail=1 tests/ + +.PHONY: clean +clean: ## Clean unused files. + @find ./ -name '*.pyc' -exec rm -f {} \; + @find ./ -name '__pycache__' -exec rm -rf {} \; + @find ./ -name 'Thumbs.db' -exec rm -f {} \; + @find ./ -name '*~' -exec rm -f {} \; + rm -rf .cache + rm -rf build + rm -rf dist + rm -rf *.egg-info + rm -rf htmlcov + rm -rf .tox/ + rm -rf docs/_build + +.PHONY: virtualenv +virtualenv: ## Create a virtual environment. + @echo "creating virtualenv ..." + @rm -rf .venv + @python3 -m venv .venv + @./.venv/bin/pip install -U pip + @./.venv/bin/pip install -e .[test] + @echo + @echo "!!! Please run 'source .venv/bin/activate' to enable the environment !!!" + +.PHONY: release +release: ## Create a new tag for release. + @echo "creating new release ...\n" + @echo "What is the version?: "; \ + read VERSION; \ + echo "creating tag for ", $$(VERSION); \ + git tag $$(VERSION); \ + gitchangelog > HISTORY.md; \ + git add HISTORY.md; \ + git commit -m "release: version $$(VERSION)"; \ + git push --tags; \ + echo "Github Actions will detect the new tag and release the new version." diff --git a/README.md b/README.md new file mode 100644 index 0000000..fcbc1c0 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +```md +# HOW TO USE THIS TEMPLATE + +- From github repository creation page select the template +- If you want coverage reports and release to PiPy + On repository settings->secrets add your PIPY_API_TOKEN and CODECOV_TOKEN +- Then clone your new project and adjust for your needs +- Replace `project_name` with the name of your project +- Replace `yourname` with your github username +- Edit setup.py to adjust your project information +``` + +# ProjectName + +[![codecov](https://codecov.io/gh/yourname/project_name/branch/main/graph/badge.svg?token=I9ZGCFTQT9)](https://codecov.io/gh/yourname/project_name) +[![CI](https://github.com/yourname/project_name/actions/workflows/main.yml/badge.svg)](https://github.com/yourname/project_name/actions/workflows/main.yml) + +This is an awesome project. + +## Install it from PyPI + +```bash +pip install project_name +``` + +## Usage + +```py +from project_name import BaseClass +from project_name import base_function + +BaseClass().base_method() +base_function() +``` + +```bash +$ python -m project_name +#or +$ project_name +``` + +## Development + +```bash +❯ make +Usage: make + +Targets: +help: ## Show the help. +install: ## Install the project in dev mode. +fmt: ## Format code using black & isort. +lint: ## Run pep8, black, mypy linters. +test: lint ## Run tests and generate coverage report. +watch: ## Run tests on every change. +clean: ## Clean unused files. +``` diff --git a/project_name/__init__.py b/project_name/__init__.py new file mode 100644 index 0000000..36e201d --- /dev/null +++ b/project_name/__init__.py @@ -0,0 +1,3 @@ +from .base import BaseClass, base_function + +__all__ = ["BaseClass", "base_function"] diff --git a/project_name/__main__.py b/project_name/__main__.py new file mode 100644 index 0000000..a0a0e66 --- /dev/null +++ b/project_name/__main__.py @@ -0,0 +1,16 @@ +from . import BaseClass, base_function # pragma: no cover + + +def main() -> None: # pragma: no cover + """ + The main function executes on `python -m project_name` + """ + print("Executing main function") + base = BaseClass() + print(base.base_method()) + print(base_function()) + print("End of main function") + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/project_name/base.py b/project_name/base.py new file mode 100644 index 0000000..4314967 --- /dev/null +++ b/project_name/base.py @@ -0,0 +1,21 @@ +""" +Project name base module. +""" + + +class BaseClass: + def base_method(self) -> str: + """ + Base method. + """ + return "hello from BaseClass" + + def __call__(self) -> str: + return self.base_method() + + +def base_function() -> str: + """ + Base function. + """ + return "hello from base function" diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..9363112 --- /dev/null +++ b/setup.py @@ -0,0 +1,32 @@ +"""Python setup.py for project_name package""" +from pathlib import Path + +from setuptools import find_packages, setup + +setup( + name="project_name", + version="0.1.0", + description="Some objects could be project_name", + url="https://github.com/yourname/project_name/", + long_description=Path("README.md").read_text(), + long_description_content_type="text/markdown", + author="Your Name", + packages=find_packages(exclude=["tests"]), + install_requires=[], + entry_points={ + "console_scripts": ["project_name = project_name.__main__:main"] + }, + extras_require={ + "test": [ + "pytest", + "coverage", + "flake8", + "black", + "isort", + "pytest-cov", + "codecov", + "mypy", + "gitchangelog", + ], + }, +) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_base.py b/tests/test_base.py new file mode 100644 index 0000000..af774dc --- /dev/null +++ b/tests/test_base.py @@ -0,0 +1,18 @@ +import pytest + +from project_name import BaseClass, base_function + +given = pytest.mark.parametrize + + +@given("fn", [BaseClass(), base_function]) +def test_parameterized(fn): + assert "hello from" in fn() + + +def test_base_function(): + assert base_function() == "hello from base function" + + +def test_base_class(): + assert BaseClass().base_method() == "hello from BaseClass"