From 6cbe4e51974de0d36ec72abc2e188d12a938ccf0 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 13 Nov 2023 15:51:53 -0500 Subject: [PATCH] fix: support hatch, tox (pyproject), and spin for PY007 Signed-off-by: Henry Schreiner --- docs/pages/guides/tasks.md | 62 +++++++++++++++------------- src/sp_repo_review/checks/general.py | 24 ++++++++--- 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/docs/pages/guides/tasks.md b/docs/pages/guides/tasks.md index 50b0f7bb..696d179a 100644 --- a/docs/pages/guides/tasks.md +++ b/docs/pages/guides/tasks.md @@ -18,37 +18,43 @@ with render_cookie() as package: A task runner, like [make][] (fully general), [rake][] (Ruby general), -[invoke][] (Python general), [tox][] (Python packages), or [nox][] (Python -semi-general), is a tool that lets you specify a set of tasks via a common -interface. These have been discouraged by some community projects in the past, -since they can be a crutch, allowing poor packaging practices to be employed -behind a custom script, and they can hide what is actually happening. - -We are carefully allowing an exception: [nox][]. Nox has two strong points that -help with the above concerns. First, it is very explicit, and even prints what -it is doing as it operates. Unlike the older tox, it does not have any implicit -assumptions built-in. Second, it has very elegant built-in support for both -virtual and Conda environments. This can greatly reduce new contributor friction -with your codebase. +[invoke][] (Python general), [hatch][] (Python packages), [tox][] (Python +packages), or [nox][] (Python semi-general), is a tool that lets you specify a +set of tasks via a common interface. These have been discouraged by some +community projects in the past, since they can be a crutch, allowing poor +packaging practices to be employed behind a custom script, and they can hide +what is actually happening. + +As long as you don't rely on it to hide packaging issues, a great choice for +many packages is [nox][]. Nox has two strong points that help with the above +concerns. First, it is very explicit, and even prints what it is doing as it +operates. Unlike the older tox, it does not have any implicit assumptions +built-in. Second, it has very elegant built-in support for both virtual and +Conda environments. This can greatly reduce new contributor friction with your +codebase. A daily developer is _not_ expected to use nox for simple tasks, like running tests or linting. You should _not_ rely on nox to make a task that should be -made simple and standard (like building a package) complicated. You are not -expected to use nox for linting on CI, or often even for testing on CI, even if -those tasks are provided for users. Nox is a few seconds slower than running -directly in a custom environment - but for new users, and rarely run tasks, it -is _much_ faster than explaining how to get setup or manually messing with -virtual environments. It is also highly reproducible, creating and destroying -the temporary environment each time. - -{% rr PY007 %} You _should_ use nox to make it easy and simple for new -contributors to run things. You _should_ use nox to make specialized developer -tasks easy. You _should_ use nox to avoid making single-use virtual environments -for docs and other rarely run tasks. +made simple and standard (like building a package) complicated. You do not need +to use nox for linting on CI, or often even for testing on CI, even if those +tasks are provided for users. Nox is a few seconds slower than running directly +in a custom environment - but for new users, and rarely run tasks, it is _much_ +faster than explaining how to get setup or manually messing with virtual +environments. It is also highly reproducible, creating and destroying the +temporary environment each time. And, if you pass `-R` when rerunning it, you +can skip the setup and install steps, making it nearly as fast as directly +running the commands! + +{% rr PY007 %} You _should_ use a task runner to make it easy and simple for new +contributors to run things. You _should_ use a task runner to make specialized +developer tasks easy. You _should_ use a task runner to avoid making single-use +virtual environments for docs and other rarely run tasks. Nox is recommended, +but tox and hatch both are also acceptable. Nox doesn't handle binary builds very well, so for compiled projects, it might be best left to just specialized tasks. +[hatch]: https://hatch.pypi.io [nox]: https://nox.thea.codes [tox]: https://tox.readthedocs.io [invoke]: https://www.pyinvoke.org @@ -69,18 +75,18 @@ On GitHub Actions or Azure, pipx is available by default, so you should use action: ```yaml -- uses: wntrblm/nox@v0.19.1 +- uses: wntrblm/nox@2023.04.22 ``` You can now access all current versions of Python from nox. At least in GitHub Actions, you should add `--forcecolor` to your nox runs to get color output in your logs, or set `env: FORCE_COLOR: 3`. If you'd like to customise the versions -of Python prepared for you, then use this input: +of Python prepared for you, then use input like this: ```yaml -- uses: wntrblm/nox@v0.19.1 +- uses: wntrblm/nox@2023.04.22 with: - python-versions: "3.8, 3.9, 3.10, 3.11, 3.12, pypy-3.9, pypy-3.10-nightly" + python-versions: "3.8, 3.9, 3.10, 3.11, 3.12, pypy-3.9, pypy-3.10" ``` ### Introduction diff --git a/src/sp_repo_review/checks/general.py b/src/sp_repo_review/checks/general.py index c7b7674b..047e4d8b 100644 --- a/src/sp_repo_review/checks/general.py +++ b/src/sp_repo_review/checks/general.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing import Any + from .._compat.importlib.resources.abc import Traversable from . import mk_url @@ -100,13 +102,25 @@ class PY007(General): url = mk_url("tasks") @staticmethod - def check(root: Traversable) -> bool: + def check(root: Traversable, pyproject: dict[str, Any]) -> bool: """ - Projects must have a `noxfile.py` or `tox.ini` to encourage new contributors. + Projects must have a `noxfile.py`, `tox.ini`, or + `tool.hatch.envs`/`tool.spin`/`tool.tox` in `pyproject.toml` to encourage new + contributors. """ - return ( - root.joinpath("noxfile.py").is_file() or root.joinpath("tox.ini").is_file() - ) + if root.joinpath("noxfile.py").is_file(): + return True + if root.joinpath("tox.ini").is_file(): + return True + match pyproject.get("tool", {}): + case {"hatch": {"envs": object()}}: + return True + case {"spin": object()}: + return True + case {"tox": object()}: + return True + case _: + return False def repo_review_checks() -> dict[str, General]: