From 53b7c05b0734b40e8b3067d7c0ad2f4cf8940d6a Mon Sep 17 00:00:00 2001 From: Jack Hadrill Date: Wed, 31 Aug 2022 00:54:17 +0100 Subject: [PATCH] Initial commit --- .drone.yml | 49 ++++++++++++++++ .flake8 | 2 + .gitignore | 126 +++++++++++++++++++++++++++++++++++++++++ .pylintrc | 2 + LICENSE | 23 ++++++++ README.md | 111 ++++++++++++++++++++++++++++++++++++ pyproject.toml | 26 +++++++++ setup.cfg | 3 + setup.py | 10 ++++ src/foobar/__init__.py | 0 src/foobar/__main__.py | 13 +++++ src/foobar/example.py | 11 ++++ tests/test_example.py | 17 ++++++ 13 files changed, 393 insertions(+) create mode 100644 .drone.yml create mode 100644 .flake8 create mode 100644 .gitignore create mode 100644 .pylintrc create mode 100644 LICENSE create mode 100644 README.md create mode 100644 pyproject.toml create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 src/foobar/__init__.py create mode 100644 src/foobar/__main__.py create mode 100644 src/foobar/example.py create mode 100644 tests/test_example.py diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..46e1eab --- /dev/null +++ b/.drone.yml @@ -0,0 +1,49 @@ +kind: pipeline +type: docker +name: lint-test +steps: + - name: lint + image: python:3-slim + commands: + - echo "Installing lint dependencies..." + - pip install --no-cache-dir '.[lint]' > /dev/null + - echo "Running flake8..." + - flake8 src + - echo "Running pylint..." + - pylint src + - name: test + image: python:3-slim + commands: + - echo "Installing test dependencies..." + - pip install --no-cache-dir '.[test]' > /dev/null + - echo "Running tests..." + - pytest +--- +kind: pipeline +type: docker +name: build-deploy +trigger: + branch: + - main +depends_on: + - lint-test +steps: + - name: build + image: python:3-slim + commands: + - pip install --no-cache-dir build + - python -m build --wheel + - name: publish + image: plugins/pypi + when: + branch: + - main + event: + - push + settings: + username: + from_secret: username + password: + from_secret: password + repository: https://git.jacknet.io/api/packages/jackhadrill/pypi + skip_build: true diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..6deafc2 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 120 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3227e2a --- /dev/null +++ b/.gitignore @@ -0,0 +1,126 @@ +# ---> VisualStudioCode +.vscode +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +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 +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# 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 + +# celery beat schedule file +celerybeat-schedule + +# 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/ + +# pycharm +.idea + +.vscode/launch.json diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..7615b86 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,2 @@ +[FORMAT] +max-line-length=120 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8e09124 --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +Butlersaurus License (Extends ISC License) + +Copyright (c) 2017-2022 by Butlersaurus + +Definitions: + * This software - All source files, issues, comments and intellectual + propety contained within this repository. + * Butlersarus - Members of Discord Guild <506852356281991208>, + hereby known as Butlersaurus. + * Employer - Any company, subsidiary or affiliated organisation which + directly or indirectly employs a Butlersaurus member. + +Permission to use, copy, modify, and /or distribute this software for any +purpose with or without fee is hereby granted to all except the employer of +each contributor to this software, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND BUTLERSAURUS DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL BUTLERSAURUS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, +OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA +OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..323be92 --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +# Python Template + +This is a basic Python template which uses the new `pyproject.toml` in +conjunction with `setup.cfg` (and legacy support for older Python versions with +`setup.py`). + +It contains pylint and flake8 rules for an increased line length of 120 +characters, in addition to support for unit tests and CI via Drone. + +## Development + +The package should be located in a subdirectory within `src/`. For example, +`src/foobar/`. + +This directory should contain an `__init__.py` and a `__main__.py`, the latter +of which allows this package to be called as a Python module. + +To install an editable version (such that you don't need to keep +re-installing), create a new virtual environment and use pip's editable flag. + +```bash +$ python -m venv venv +$ . venv/bin/activate +(venv)$ pip install -e . +``` + +### Lint + +Pylint and flake8 rules can be found in `.pylintrc` and `.flake8` respectively. +By default, the default rulesets are followed with overrides specified in these +files. + +To install, use the following command: +```bash +(venv)$ pip install -e '.[lint]' +``` + +To run, use the following commands: +```bash +(venv)$ flake8 src +(venv)$ pylint src +``` + +It should be noted that flake8 is much quicker than pylint, so should run first +when used in a CI pipeline. + +### Test + +This package is setup to support Python unittest and pytest, although in +practice I've only really used it with pytest. + +To install the test dependencies, issue the following command: +```bash +(venv)$ pip install -e '.[test]' +``` + +To run the tests, run the following command: +```bash +(venv)$ pytest +``` + +Tests should be stored in the `test/` directory. + +### Build + +To build a wheel for this package, use the following commands: +```bash +(venv)$ pip install --no-cache-dir build +(venv)$ python -m build --wheel +``` + +This will output a wheel to the `dist/` directory. + +## Installation + +Installation can be performed from source or using the previously built wheel. + +### Source + +To install from source, navigate to the root directory and run the following +command: +```bash +(venv)$ pip install . +``` + +### Wheel + +To install using the wheel, run the following command: +```bash +(venv)$ pip install dist/foobar*.whl +``` + +## Running + +The `[project.scripts]` directive in `pyproject.toml` lists the commands which +should be installed as part of this package. The included example runs the +`main()` function in `__main__.py`, and allows for the user to run the package +with the following command: +```bash +(venv)$ foobar +Hello, World! +42 +``` + +Alternatively, because `__main__.py` was used, the user can achieve the same by +using the following: +```bash +(venv)$ python -m foobar +Hello, World! +42 +``` diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..947c40e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,26 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "foobar" +description = "A boilerplate template for Python projects." +readme = "README.md" +requires-python = ">=3.9" +license = {text = "Butlersaurus License"} +dynamic = ["version"] +dependencies = [ + # "dependency>=0.0.1" +] + +[project.optional-dependencies] +lint = [ + "pylint>=2.14.5", + "flake8>=5.0.4" +] +test = [ + "pytest>=7.1.2" +] + +[project.scripts] +foobar = "foobar.__main__:main" diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..41a0ee7 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[metadata] +name = foobar +version = 0.0.1 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..430fb1f --- /dev/null +++ b/setup.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 + +# N.B. This is here for legacy support in order to support editable installs. Please see: +# https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#pep660-status +# https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#setupcfg-caveats + +from setuptools import setup + + +setup() diff --git a/src/foobar/__init__.py b/src/foobar/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/foobar/__main__.py b/src/foobar/__main__.py new file mode 100644 index 0000000..f69dd22 --- /dev/null +++ b/src/foobar/__main__.py @@ -0,0 +1,13 @@ +"""Entrypoint for application.""" + +from foobar.example import add_numbers + + +def main() -> None: + """Prints example strings to stdout.""" + print("Hello, World!") + print(add_numbers(40, 2)) + + +if __name__ == "__main__": + main() diff --git a/src/foobar/example.py b/src/foobar/example.py new file mode 100644 index 0000000..10ffa15 --- /dev/null +++ b/src/foobar/example.py @@ -0,0 +1,11 @@ +"""Contains some example functions.""" + + +def add_numbers(first: int, second: int) -> int: + """Adds two integers. + + :param first: The first integer. + :param second: The second integer. + :returns: The sum of the first and second integer. + """ + return first + second diff --git a/tests/test_example.py b/tests/test_example.py new file mode 100644 index 0000000..52f999d --- /dev/null +++ b/tests/test_example.py @@ -0,0 +1,17 @@ +"""Tests for example.py.""" + +from foobar.example import add_numbers + + +def test_add() -> None: + """Assert that two integers add together correctly.""" + # Arrange + first = 40 + second = 2 + expected = 42 + + # Act + ret = add_numbers(first, second) + + # Assert + assert ret == expected