Add nox as the task runner

- set up skeletons for all planned nox sessions
- provide a base configuration for all nox sessions
- create two utility functions:
  + _begin() => run commands common to all sessions
  + _install_packages() => install dependencies in nox sessions
                           respecting the versions pinned in poetry.lock
- add the following file:
  + noxfile.py
This commit is contained in:
Alexander Hess 2020-08-03 21:24:06 +02:00
parent de8afa6335
commit 6754f04fcd
Signed by: alexander
GPG key ID: 344EA5AB10D868E0
4 changed files with 263 additions and 2 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
.cache/
*.egg-info/
.python-version
.venv/

114
noxfile.py Normal file
View file

@ -0,0 +1,114 @@
"""Configure nox for the isolated test and lint environments."""
import os
import tempfile
from typing import Any
import nox
from nox.sessions import Session
MAIN_PYTHON = '3.8'
# Keep the project is forward compatible.
NEXT_PYTHON = '3.9'
# Paths with *.py files.
SRC_LOCATIONS = 'noxfile.py', 'src/'
# Use a unified .cache/ folder for all tools.
nox.options.envdir = '.cache/nox'
# All tools except git and poetry are project dependencies.
# Avoid accidental successes if the environment is not set up properly.
nox.options.error_on_external_run = True
# Run only CI related checks by default.
nox.options.sessions = (
'format',
'lint',
f'test-{MAIN_PYTHON}',
f'test-{NEXT_PYTHON}',
)
@nox.session(name='format', python=MAIN_PYTHON)
def format_(session: Session):
"""Format source files."""
_begin(session)
@nox.session(python=MAIN_PYTHON)
def lint(session: Session):
"""Lint source files."""
_begin(session)
@nox.session(python=[MAIN_PYTHON, NEXT_PYTHON])
def test(session: Session):
"""Test the code base."""
_begin(session)
@nox.session(name='pre-commit', python=MAIN_PYTHON, venv_backend='none')
def pre_commit(session: Session):
"""Source files must be well-formed before they enter git."""
_begin(session)
session.notify('format')
session.notify('lint')
@nox.session(name='pre-merge', python=MAIN_PYTHON, venv_backend='none')
def pre_merge(session: Session):
"""The test suite must pass before merges are made."""
_begin(session)
session.notify('test')
def _begin(session: Session) -> None:
"""Show generic info about a session."""
if session.posargs:
print('extra arguments:', *session.posargs)
session.run('python', '--version')
# Fake GNU's pwd.
session.log('pwd')
print(os.getcwd())
def _install_packages(
session: Session, *packages_or_pip_args: str, **kwargs: Any
) -> None:
"""Install packages respecting the poetry.lock file.
This function wraps nox.sessions.Session.install() such that it installs
packages respecting the pinnned versions specified in poetry's lock file.
This makes nox sessions even more deterministic.
Args:
session: the Session object
*packages_or_pip_args: the packages to be installed or pip options
**kwargs: passed on to nox.sessions.Session.install()
"""
if session.virtualenv.reuse_existing:
session.log(
'No dependencies are installed as an existing environment is re-used',
)
return
session.log('Dependencies are installed respecting the poetry.lock file')
with tempfile.NamedTemporaryFile() as requirements_txt:
session.run(
'poetry',
'export',
'--dev',
'--format=requirements.txt',
f'--output={requirements_txt.name}',
external=True,
)
session.install(
f'--constraint={requirements_txt.name}', *packages_or_pip_args, **kwargs,
)

148
poetry.lock generated
View file

@ -1,8 +1,152 @@
package = []
[[package]]
category = "dev"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
name = "appdirs"
optional = false
python-versions = "*"
version = "1.4.4"
[[package]]
category = "dev"
description = "Bash tab completion for argparse"
name = "argcomplete"
optional = false
python-versions = "*"
version = "1.12.0"
[package.extras]
test = ["coverage", "flake8", "pexpect", "wheel"]
[[package]]
category = "dev"
description = "Cross-platform colored terminal text."
marker = "sys_platform == \"win32\""
name = "colorama"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.4.3"
[[package]]
category = "dev"
description = "Log formatting with colors!"
name = "colorlog"
optional = false
python-versions = "*"
version = "4.2.1"
[package.dependencies]
colorama = "*"
[[package]]
category = "dev"
description = "Distribution utilities"
name = "distlib"
optional = false
python-versions = "*"
version = "0.3.1"
[[package]]
category = "dev"
description = "A platform independent file lock."
name = "filelock"
optional = false
python-versions = "*"
version = "3.0.12"
[[package]]
category = "dev"
description = "Flexible test automation."
name = "nox"
optional = false
python-versions = ">=3.5"
version = "2020.5.24"
[package.dependencies]
argcomplete = ">=1.9.4,<2.0"
colorlog = ">=2.6.1,<5.0.0"
py = ">=1.4.0,<2.0.0"
virtualenv = ">=14.0.0"
[package.extras]
tox_to_nox = ["jinja2", "tox"]
[[package]]
category = "dev"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
name = "py"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.9.0"
[[package]]
category = "dev"
description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "1.15.0"
[[package]]
category = "dev"
description = "Virtual Python Environment builder"
name = "virtualenv"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "20.0.29"
[package.dependencies]
appdirs = ">=1.4.3,<2"
distlib = ">=0.3.1,<1"
filelock = ">=3.0.0,<4"
six = ">=1.9.0,<2"
[package.extras]
docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"]
testing = ["coverage (>=5)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "pytest-xdist (>=1.31.0)", "packaging (>=20.0)", "xonsh (>=0.9.16)"]
[metadata]
content-hash = "fafb334cb038533f851c23d0b63254223abf72ce4f02987e7064b0c95566699a"
content-hash = "4ff12f695975572453949608224e06fb36641151ee69668f8603f7bc3435a51f"
lock-version = "1.0"
python-versions = "^3.8"
[metadata.files]
appdirs = [
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
]
argcomplete = [
{file = "argcomplete-1.12.0-py2.py3-none-any.whl", hash = "sha256:91dc7f9c7f6281d5a0dce5e73d2e33283aaef083495c13974a7dd197a1cdc949"},
{file = "argcomplete-1.12.0.tar.gz", hash = "sha256:2fbe5ed09fd2c1d727d4199feca96569a5b50d44c71b16da9c742201f7cc295c"},
]
colorama = [
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
]
colorlog = [
{file = "colorlog-4.2.1-py2.py3-none-any.whl", hash = "sha256:43597fd822ce705190fc997519342fdaaf44b9b47f896ece7aa153ed4b909c74"},
{file = "colorlog-4.2.1.tar.gz", hash = "sha256:75e55822c3a3387d721579241e776de2cf089c9ef9528b1f09e8b04d403ad118"},
]
distlib = [
{file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"},
{file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"},
]
filelock = [
{file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
]
nox = [
{file = "nox-2020.5.24-py3-none-any.whl", hash = "sha256:c4509621fead99473a1401870e680b0aadadce5c88440f0532863595176d64c1"},
{file = "nox-2020.5.24.tar.gz", hash = "sha256:61a55705736a1a73efbd18d5b262a43d55a1176546e0eb28b29064cfcffe26c0"},
]
py = [
{file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"},
{file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"},
]
six = [
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
]
virtualenv = [
{file = "virtualenv-20.0.29-py2.py3-none-any.whl", hash = "sha256:8aa9c37b082664dbce2236fa420759c02d64109d8e6013593ad13914718a30fd"},
{file = "virtualenv-20.0.29.tar.gz", hash = "sha256:f14a0a98ea4397f0d926cff950361766b6a73cd5975ae7eb259d12919f819a25"},
]

View file

@ -23,3 +23,5 @@ repository = "https://github.com/webartifex/urban-meal-delivery"
python = "^3.8"
[tool.poetry.dev-dependencies]
# Task Runners
nox = "^2020.5.24"