minchin.tasks 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- minchin_tasks-1.0.0/LICENSE.txt +21 -0
- minchin_tasks-1.0.0/PKG-INFO +46 -0
- minchin_tasks-1.0.0/README.rst +22 -0
- minchin_tasks-1.0.0/minchin/tasks/__init__.py +24 -0
- minchin_tasks-1.0.0/minchin/tasks/dev.py +162 -0
- minchin_tasks-1.0.0/minchin/tasks/tests/test_dev.py +58 -0
- minchin_tasks-1.0.0/minchin.tasks.egg-info/PKG-INFO +46 -0
- minchin_tasks-1.0.0/minchin.tasks.egg-info/SOURCES.txt +11 -0
- minchin_tasks-1.0.0/minchin.tasks.egg-info/dependency_links.txt +1 -0
- minchin_tasks-1.0.0/minchin.tasks.egg-info/requires.txt +3 -0
- minchin_tasks-1.0.0/minchin.tasks.egg-info/top_level.txt +1 -0
- minchin_tasks-1.0.0/pyproject.toml +132 -0
- minchin_tasks-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 William Minchin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: minchin.tasks
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Common development tasks (lint, format, test, ...) for use with Invoke.
|
|
5
|
+
Author-email: William Minchin <w_minchin@hotmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/MinchinWeb/minchin.tasks/issues
|
|
8
|
+
Project-URL: Repository, https://github.com/MinchinWeb/minchin.tasks
|
|
9
|
+
Project-URL: Changelog, https://github.com/MinchinWeb/minchin.tasks/blob/master/CHANGELOG.rst
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Environment :: Console
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/x-rst
|
|
19
|
+
License-File: LICENSE.txt
|
|
20
|
+
Requires-Dist: invoke>=2.0.0
|
|
21
|
+
Requires-Dist: taplo
|
|
22
|
+
Requires-Dist: validate-pyproject
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
Minchin.Tasks
|
|
26
|
+
=============
|
|
27
|
+
|
|
28
|
+
Common development tasks for use with `Invoke <https://www.pyinvoke.org/>`_.
|
|
29
|
+
Defaults to a ``uv`` and ``ruff`` setup, but should continue to work with
|
|
30
|
+
``black``, ``isort``, and ``pip-tools``. Useful for applying my in-house Python
|
|
31
|
+
style, see https://github.com/minchinweb/python-style-guide
|
|
32
|
+
|
|
33
|
+
In your ``tasks.py`` (import each for clarity)::
|
|
34
|
+
|
|
35
|
+
from minchin.tasks import check, format_code, lint, test, update, upgrade # noqa: F401
|
|
36
|
+
|
|
37
|
+
The tasks are defined in ``minchin.tasks.dev``; ``minchin.tasks`` re-exports them.
|
|
38
|
+
|
|
39
|
+
This gives you:
|
|
40
|
+
|
|
41
|
+
- ``invoke update`` -- update requirements to the current versions
|
|
42
|
+
- ``invoke upgrade`` -- install the locked requirements
|
|
43
|
+
- ``invoke lint`` -- report only format check, including ``pyproject.toml``
|
|
44
|
+
- ``invoke format`` -- fix formatting issues
|
|
45
|
+
- ``invoke test`` -- run ``pytest``.
|
|
46
|
+
- ``invoke check`` -- ``lint`` and ``test``.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Minchin.Tasks
|
|
2
|
+
=============
|
|
3
|
+
|
|
4
|
+
Common development tasks for use with `Invoke <https://www.pyinvoke.org/>`_.
|
|
5
|
+
Defaults to a ``uv`` and ``ruff`` setup, but should continue to work with
|
|
6
|
+
``black``, ``isort``, and ``pip-tools``. Useful for applying my in-house Python
|
|
7
|
+
style, see https://github.com/minchinweb/python-style-guide
|
|
8
|
+
|
|
9
|
+
In your ``tasks.py`` (import each for clarity)::
|
|
10
|
+
|
|
11
|
+
from minchin.tasks import check, format_code, lint, test, update, upgrade # noqa: F401
|
|
12
|
+
|
|
13
|
+
The tasks are defined in ``minchin.tasks.dev``; ``minchin.tasks`` re-exports them.
|
|
14
|
+
|
|
15
|
+
This gives you:
|
|
16
|
+
|
|
17
|
+
- ``invoke update`` -- update requirements to the current versions
|
|
18
|
+
- ``invoke upgrade`` -- install the locked requirements
|
|
19
|
+
- ``invoke lint`` -- report only format check, including ``pyproject.toml``
|
|
20
|
+
- ``invoke format`` -- fix formatting issues
|
|
21
|
+
- ``invoke test`` -- run ``pytest``.
|
|
22
|
+
- ``invoke check`` -- ``lint`` and ``test``.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Common development tasks to use from `invoke`.
|
|
2
|
+
|
|
3
|
+
In a project's ``tasks.py``::
|
|
4
|
+
|
|
5
|
+
from minchin.tasks import ( # noqa: F401
|
|
6
|
+
check,
|
|
7
|
+
format_code,
|
|
8
|
+
lint,
|
|
9
|
+
test,
|
|
10
|
+
update,
|
|
11
|
+
upgrade,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
Uses ``uv run`` under the hood by default, or ``pip-tools`` on "legacy" setups.
|
|
15
|
+
The tasks themselves live in `minchin.tasks.dev`.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from minchin.tasks.dev import check, format_code, lint, test, update, upgrade
|
|
21
|
+
|
|
22
|
+
__version__ = "1.0.0"
|
|
23
|
+
|
|
24
|
+
__all__ = ["check", "format_code", "lint", "test", "update", "upgrade"]
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Common development tasks (lint, format, test, ...) to use from `invoke`.
|
|
2
|
+
|
|
3
|
+
Uses ``uv run`` under the hood by default, or ``pip-tools`` on "legacy" setups.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from invoke import task
|
|
12
|
+
|
|
13
|
+
__all__ = ["check", "format_code", "lint", "test", "update", "upgrade"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _uses_uv() -> bool:
|
|
17
|
+
# A `uv.lock` implies the project is managed by uv
|
|
18
|
+
return Path("uv.lock").is_file()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _pip_tools_inputs() -> list[Path]:
|
|
22
|
+
# look for `.in` files in both `.requirements/*.in` or the repo root `*.in`
|
|
23
|
+
found = [*Path(".requirements").glob("*.in"), *Path().glob("*.in")]
|
|
24
|
+
# blacklist `MANIFEST.in` as a setuptools file
|
|
25
|
+
return sorted(p for p in found if p.name.lower() != "manifest.in")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _compiled_requirements() -> dict[str, Path]:
|
|
29
|
+
"""Get a list of the requirement files.
|
|
30
|
+
|
|
31
|
+
`requirements-base.in` is assumed to the "main" one.
|
|
32
|
+
"""
|
|
33
|
+
found = {}
|
|
34
|
+
for path in _pip_tools_inputs():
|
|
35
|
+
compiled = path.with_suffix(".txt")
|
|
36
|
+
if not compiled.is_file():
|
|
37
|
+
continue
|
|
38
|
+
name = compiled.stem.removeprefix("requirements").lstrip("-_")
|
|
39
|
+
if name in ("", "base"):
|
|
40
|
+
name = "main"
|
|
41
|
+
found[name] = compiled
|
|
42
|
+
return found
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _uses_black() -> bool:
|
|
46
|
+
# Black/isort config in `pyproject.toml` without a ruff config
|
|
47
|
+
pyproject = Path("pyproject.toml")
|
|
48
|
+
if not pyproject.is_file():
|
|
49
|
+
return False
|
|
50
|
+
text = pyproject.read_text(encoding="utf-8")
|
|
51
|
+
legacy = "[tool.black]" in text or "[tool.isort]" in text
|
|
52
|
+
return legacy and "[tool.ruff" not in text
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _run_prefix() -> str:
|
|
56
|
+
# run uv projects using `uv`
|
|
57
|
+
return "uv run " if _uses_uv() else ""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@task
|
|
61
|
+
def update(ctx):
|
|
62
|
+
"""Refresh the requirements with the current versions.
|
|
63
|
+
|
|
64
|
+
Rewrites `uv.lock`, or recompiles pip-tools' `.txt`.
|
|
65
|
+
"""
|
|
66
|
+
if _uses_uv():
|
|
67
|
+
ctx.run("uv lock --upgrade", pty=False)
|
|
68
|
+
return
|
|
69
|
+
inputs = _pip_tools_inputs()
|
|
70
|
+
if not inputs:
|
|
71
|
+
raise SystemExit("No `uv.lock` or pip-tools `.in` files found.")
|
|
72
|
+
for source in inputs:
|
|
73
|
+
ctx.run(f"pip-compile --upgrade {source.as_posix()}", pty=False)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@task(
|
|
77
|
+
iterable=["extra"],
|
|
78
|
+
help={
|
|
79
|
+
"extra": "Also install this requirements set, e.g. `dev` ("
|
|
80
|
+
"pip-tools projects only)",
|
|
81
|
+
"all_": "Install every compiled requirements file (pip-tools only)",
|
|
82
|
+
"dry_run": "Show what would change without installing anything",
|
|
83
|
+
},
|
|
84
|
+
)
|
|
85
|
+
def upgrade(ctx, extra=None, all_=False, dry_run=False):
|
|
86
|
+
"""Install based on the current requiremnts.
|
|
87
|
+
|
|
88
|
+
Runs `uv sync`, or `pip-sync` on the main compiled pip-tools file plus any
|
|
89
|
+
sets named with `--extra` (or all of them with `--all`).
|
|
90
|
+
|
|
91
|
+
Use `--dry-run` to check first.
|
|
92
|
+
"""
|
|
93
|
+
flag = " --dry-run" if dry_run else ""
|
|
94
|
+
if _uses_uv():
|
|
95
|
+
ctx.run(f"uv sync{flag}", pty=False)
|
|
96
|
+
return
|
|
97
|
+
available = _compiled_requirements()
|
|
98
|
+
if not available:
|
|
99
|
+
raise SystemExit("No `uv.lock` or compiled pip-tools `.txt` files found.")
|
|
100
|
+
names = list(available) if all_ else ["main", *(extra or [])]
|
|
101
|
+
unknown = [n for n in names if n not in available]
|
|
102
|
+
if unknown:
|
|
103
|
+
raise SystemExit(
|
|
104
|
+
f"No compiled requirements for: {', '.join(unknown)}. "
|
|
105
|
+
f"Available: {', '.join(available)}."
|
|
106
|
+
)
|
|
107
|
+
# pip-sync wants each file once; keep the order given
|
|
108
|
+
files = dict.fromkeys(available[n].as_posix() for n in names)
|
|
109
|
+
ctx.run(f"pip-sync{flag} {' '.join(files)}", pty=False)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@task
|
|
113
|
+
def lint(ctx):
|
|
114
|
+
"""Check code, formatting and `pyproject.toml`."""
|
|
115
|
+
run = _run_prefix()
|
|
116
|
+
if _uses_black():
|
|
117
|
+
ctx.run(f"{run}black --check .", pty=False)
|
|
118
|
+
ctx.run(f"{run}isort --check-only .", pty=False)
|
|
119
|
+
print(
|
|
120
|
+
"WARNING: pyproject.toml was not checked (validate-pyproject and "
|
|
121
|
+
"taplo only run for ruff projects); review it by hand.",
|
|
122
|
+
file=sys.stderr,
|
|
123
|
+
)
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
ctx.run("uv run ruff check", pty=False)
|
|
127
|
+
ctx.run("uv run ruff format --check", pty=False)
|
|
128
|
+
ctx.run("uv run validate-pyproject pyproject.toml", pty=False)
|
|
129
|
+
ctx.run("uv run taplo format --check pyproject.toml", pty=False)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# named `format_code` so it doesn't shadow the builtin (ruff rule `A`)
|
|
133
|
+
@task(name="format")
|
|
134
|
+
def format_code(ctx):
|
|
135
|
+
"""Apply safe lint fixes, import sorting and formatting (code and TOML)."""
|
|
136
|
+
if _uses_black():
|
|
137
|
+
run = _run_prefix()
|
|
138
|
+
ctx.run(f"{run}isort .", pty=False)
|
|
139
|
+
ctx.run(f"{run}black .", pty=False)
|
|
140
|
+
return
|
|
141
|
+
|
|
142
|
+
# unfixable problems exit non-zero; still format, `lint` reports them
|
|
143
|
+
ctx.run("uv run ruff check --fix", pty=False, warn=True)
|
|
144
|
+
ctx.run("uv run ruff format", pty=False)
|
|
145
|
+
ctx.run("uv run taplo format pyproject.toml", pty=False)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@task
|
|
149
|
+
def test(ctx):
|
|
150
|
+
"""Run the test suite.
|
|
151
|
+
|
|
152
|
+
Assumes `pytest`.
|
|
153
|
+
"""
|
|
154
|
+
ctx.run(f"{_run_prefix()}pytest", pty=False)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@task(pre=[lint, test])
|
|
158
|
+
def check(ctx):
|
|
159
|
+
"""lint, formatting and tests.
|
|
160
|
+
|
|
161
|
+
Useful for single-run CI runs.
|
|
162
|
+
"""
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Tests for the shared development tasks."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from invoke import Collection, Context
|
|
6
|
+
|
|
7
|
+
from minchin.tasks import dev as tasks
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RecordingContext(Context):
|
|
11
|
+
"""Stands in for an Invoke context and records the commands it is given."""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
super().__init__()
|
|
15
|
+
self.commands = []
|
|
16
|
+
|
|
17
|
+
def run(self, command, **kwargs):
|
|
18
|
+
self.commands.append((command, kwargs))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def run_task(task):
|
|
22
|
+
ctx = RecordingContext()
|
|
23
|
+
task(ctx)
|
|
24
|
+
return ctx.commands
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_update_and_upgrade_mirror_apt():
|
|
28
|
+
assert run_task(tasks.update)[0][0] == "uv lock --upgrade"
|
|
29
|
+
assert run_task(tasks.upgrade)[0][0] == "uv sync"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_lint_changes_nothing_and_checks_pyproject():
|
|
33
|
+
commands = [c for c, _ in run_task(tasks.lint)]
|
|
34
|
+
assert commands == [
|
|
35
|
+
"uv run ruff check",
|
|
36
|
+
"uv run ruff format --check",
|
|
37
|
+
"uv run validate-pyproject pyproject.toml",
|
|
38
|
+
"uv run taplo format --check pyproject.toml",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_format_still_formats_when_lint_fixes_fail():
|
|
43
|
+
commands = run_task(tasks.format_code)
|
|
44
|
+
assert commands[0][0] == "uv run ruff check --fix"
|
|
45
|
+
assert commands[0][1]["warn"] is True
|
|
46
|
+
assert [c for c, _ in commands[1:]] == [
|
|
47
|
+
"uv run ruff format",
|
|
48
|
+
"uv run taplo format pyproject.toml",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_task_names_match_the_documented_commands():
|
|
53
|
+
names = set(Collection.from_module(tasks).task_names)
|
|
54
|
+
assert names == {"check", "format", "lint", "test", "update", "upgrade"}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_check_runs_lint_then_test():
|
|
58
|
+
assert [t.__name__ for t in tasks.check.pre] == ["lint", "test"]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: minchin.tasks
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Common development tasks (lint, format, test, ...) for use with Invoke.
|
|
5
|
+
Author-email: William Minchin <w_minchin@hotmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/MinchinWeb/minchin.tasks/issues
|
|
8
|
+
Project-URL: Repository, https://github.com/MinchinWeb/minchin.tasks
|
|
9
|
+
Project-URL: Changelog, https://github.com/MinchinWeb/minchin.tasks/blob/master/CHANGELOG.rst
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Environment :: Console
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/x-rst
|
|
19
|
+
License-File: LICENSE.txt
|
|
20
|
+
Requires-Dist: invoke>=2.0.0
|
|
21
|
+
Requires-Dist: taplo
|
|
22
|
+
Requires-Dist: validate-pyproject
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
Minchin.Tasks
|
|
26
|
+
=============
|
|
27
|
+
|
|
28
|
+
Common development tasks for use with `Invoke <https://www.pyinvoke.org/>`_.
|
|
29
|
+
Defaults to a ``uv`` and ``ruff`` setup, but should continue to work with
|
|
30
|
+
``black``, ``isort``, and ``pip-tools``. Useful for applying my in-house Python
|
|
31
|
+
style, see https://github.com/minchinweb/python-style-guide
|
|
32
|
+
|
|
33
|
+
In your ``tasks.py`` (import each for clarity)::
|
|
34
|
+
|
|
35
|
+
from minchin.tasks import check, format_code, lint, test, update, upgrade # noqa: F401
|
|
36
|
+
|
|
37
|
+
The tasks are defined in ``minchin.tasks.dev``; ``minchin.tasks`` re-exports them.
|
|
38
|
+
|
|
39
|
+
This gives you:
|
|
40
|
+
|
|
41
|
+
- ``invoke update`` -- update requirements to the current versions
|
|
42
|
+
- ``invoke upgrade`` -- install the locked requirements
|
|
43
|
+
- ``invoke lint`` -- report only format check, including ``pyproject.toml``
|
|
44
|
+
- ``invoke format`` -- fix formatting issues
|
|
45
|
+
- ``invoke test`` -- run ``pytest``.
|
|
46
|
+
- ``invoke check`` -- ``lint`` and ``test``.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
README.rst
|
|
3
|
+
pyproject.toml
|
|
4
|
+
minchin.tasks.egg-info/PKG-INFO
|
|
5
|
+
minchin.tasks.egg-info/SOURCES.txt
|
|
6
|
+
minchin.tasks.egg-info/dependency_links.txt
|
|
7
|
+
minchin.tasks.egg-info/requires.txt
|
|
8
|
+
minchin.tasks.egg-info/top_level.txt
|
|
9
|
+
minchin/tasks/__init__.py
|
|
10
|
+
minchin/tasks/dev.py
|
|
11
|
+
minchin/tasks/tests/test_dev.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
minchin
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
# v77 needed for SPDX `license` expressions (PEP 639)
|
|
3
|
+
requires = ["setuptools >= 77"]
|
|
4
|
+
build-backend = "setuptools.build_meta"
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "minchin.tasks"
|
|
8
|
+
description = "Common development tasks (lint, format, test, ...) for use with Invoke."
|
|
9
|
+
dynamic = ["version", "readme"]
|
|
10
|
+
authors = [{ name = "William Minchin", email = "w_minchin@hotmail.com" }]
|
|
11
|
+
requires-python = ">= 3.9"
|
|
12
|
+
license = "MIT"
|
|
13
|
+
license-files = ["LICEN[CS]E*"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
# having an unknown classifier should keep PyPI from accepting the
|
|
16
|
+
# package as an upload
|
|
17
|
+
# 'Private :: Do Not Upload',
|
|
18
|
+
# 'Development Status :: 1 - Planning',
|
|
19
|
+
# 'Development Status :: 2 - Pre-Alpha',
|
|
20
|
+
# 'Development Status :: 3 - Alpha',
|
|
21
|
+
'Development Status :: 4 - Beta',
|
|
22
|
+
# 'Development Status :: 5 - Production/Stable',
|
|
23
|
+
# 'Development Status :: 6 - Mature',
|
|
24
|
+
# 'Development Status :: 7 - Inactive',
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
# "Programming Language :: Python :: 3.9",
|
|
27
|
+
# "Programming Language :: Python :: 3.10",
|
|
28
|
+
# "Programming Language :: Python :: 3.11",
|
|
29
|
+
# "Programming Language :: Python :: 3.12",
|
|
30
|
+
# "Programming Language :: Python :: 3.13",
|
|
31
|
+
# "Programming Language :: Python :: 3.14",
|
|
32
|
+
# "Programming Language :: Python :: 3.15",
|
|
33
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
34
|
+
"Natural Language :: English",
|
|
35
|
+
"Intended Audience :: Developers",
|
|
36
|
+
"Operating System :: OS Independent",
|
|
37
|
+
"Environment :: Console",
|
|
38
|
+
# full list at https://pypi.org/classifiers/
|
|
39
|
+
]
|
|
40
|
+
dependencies = [
|
|
41
|
+
"invoke >= 2.0.0",
|
|
42
|
+
# for pyproject.toml format checks
|
|
43
|
+
"taplo",
|
|
44
|
+
"validate-pyproject",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
"Bug Tracker" = "https://github.com/MinchinWeb/minchin.tasks/issues"
|
|
49
|
+
Repository = "https://github.com/MinchinWeb/minchin.tasks"
|
|
50
|
+
Changelog = "https://github.com/MinchinWeb/minchin.tasks/blob/master/CHANGELOG.rst"
|
|
51
|
+
|
|
52
|
+
[dependency-groups]
|
|
53
|
+
# PEP 735; not published. `uv sync` installs `dev` by default.
|
|
54
|
+
dev = ["pytest >= 8", "ruff >= 0.14", { include-group = "release" }]
|
|
55
|
+
release = ["minchin.releaser >= 0.9.6"]
|
|
56
|
+
|
|
57
|
+
[tool.setuptools.packages.find]
|
|
58
|
+
# flat layout; tests live in the package (`minchin/<name>/tests/`).
|
|
59
|
+
# `minchin` is an implicit (PEP 420) namespace package, so it has NO
|
|
60
|
+
# `__init__.py`
|
|
61
|
+
include = ["minchin*"]
|
|
62
|
+
exclude = [
|
|
63
|
+
# top-level only; `minchin.<name>.tests` ships with the package
|
|
64
|
+
"build",
|
|
65
|
+
"dist",
|
|
66
|
+
"docs",
|
|
67
|
+
"env",
|
|
68
|
+
"test",
|
|
69
|
+
"tests",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
[tool.setuptools.dynamic]
|
|
73
|
+
# this has to be the place the version is located via static analysis, i.e.
|
|
74
|
+
# a plain `__version__ = "x.y.z"` with no imports needed to compute it
|
|
75
|
+
version = { attr = "minchin.tasks.__version__" }
|
|
76
|
+
readme = { file = ["README.rst"], content-type = "text/x-rst" }
|
|
77
|
+
|
|
78
|
+
[tool.pytest.ini_options]
|
|
79
|
+
addopts = ["--import-mode=importlib"]
|
|
80
|
+
# tests ship inside the package: minchin/<name>/tests/
|
|
81
|
+
testpaths = ["minchin"]
|
|
82
|
+
|
|
83
|
+
[tool.ruff]
|
|
84
|
+
line-length = 88
|
|
85
|
+
# also skip excluded paths when a path is given explicitly
|
|
86
|
+
force-exclude = true
|
|
87
|
+
extend-exclude = ["_build"]
|
|
88
|
+
|
|
89
|
+
[tool.ruff.format]
|
|
90
|
+
# Reformat code snippets in docstrings.
|
|
91
|
+
docstring-code-format = true
|
|
92
|
+
# Keep each file's existing line endings, so Windows (CRLF working tree) and
|
|
93
|
+
# the Linux CI runner don't fight each other.
|
|
94
|
+
line-ending = "auto"
|
|
95
|
+
|
|
96
|
+
[tool.ruff.lint]
|
|
97
|
+
# Enable `from __future__ import annotations` imports
|
|
98
|
+
future-annotations = true
|
|
99
|
+
# Added to ruff's default (E4, E7, E9, F)
|
|
100
|
+
extend-select = [
|
|
101
|
+
"A", # shadowing builtin names
|
|
102
|
+
"B", # bugbear
|
|
103
|
+
"E",
|
|
104
|
+
"W", # pycodestyle
|
|
105
|
+
"I", # isort
|
|
106
|
+
"N", # PEP8 naming
|
|
107
|
+
"PTH", # use pathlib
|
|
108
|
+
"RUF", # ruff-specific
|
|
109
|
+
"SIM", # simplify
|
|
110
|
+
"UP", # pyupgrade (limited by `requires-python`)
|
|
111
|
+
"YTT", # flake8-2020 (common issues with Python version checks)
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
[tool.ruff.lint.isort]
|
|
115
|
+
# Sort imports within their section independent of the import type
|
|
116
|
+
force-sort-within-sections = true
|
|
117
|
+
known-first-party = ["minchin"]
|
|
118
|
+
# Framework sections are standard boilerplate; an unused one costs nothing.
|
|
119
|
+
# Delete a section's name from `section-order` only if its package clashes.
|
|
120
|
+
section-order = [
|
|
121
|
+
"future",
|
|
122
|
+
"standard-library",
|
|
123
|
+
"django",
|
|
124
|
+
"pelican",
|
|
125
|
+
"third-party",
|
|
126
|
+
"first-party",
|
|
127
|
+
"local-folder",
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
[tool.ruff.lint.isort.sections]
|
|
131
|
+
"django" = ["django"]
|
|
132
|
+
"pelican" = ["pelican"]
|