invoke-tasklib 0.0.1__tar.gz → 0.0.2__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.
@@ -0,0 +1,246 @@
1
+ Metadata-Version: 2.5
2
+ Name: invoke-tasklib
3
+ Version: 0.0.2
4
+ Summary: Reusable Invoke tasks shared across Python projects.
5
+ Project-URL: Homepage, https://github.com/durandtibo/invoke-tasklib
6
+ Project-URL: Repository, https://github.com/durandtibo/invoke-tasklib
7
+ Project-URL: Documentation, https://durandtibo.github.io/invoke-tasklib/
8
+ Project-URL: Changelog, https://github.com/durandtibo/invoke-tasklib/releases
9
+ Project-URL: Issues, https://github.com/durandtibo/invoke-tasklib/issues
10
+ Author-email: Thibaut Durand <durand.tibo+gh@gmail.com>
11
+ License-Expression: BSD-3-Clause
12
+ License-File: LICENSE
13
+ Keywords: automation,devtools,invoke,tasks
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: BSD License
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Software Development :: Build Tools
25
+ Requires-Python: >=3.10
26
+ Requires-Dist: invoke>=3.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # invoke-tasklib
30
+
31
+ <p align="center">
32
+ <a href="https://github.com/durandtibo/invoke-tasklib/actions/workflows/ci.yaml">
33
+ <img alt="CI" src="https://github.com/durandtibo/invoke-tasklib/actions/workflows/ci.yaml/badge.svg">
34
+ </a>
35
+ <a href="https://github.com/durandtibo/invoke-tasklib/actions/workflows/nightly-package.yaml">
36
+ <img alt="Nightly Package Tests" src="https://github.com/durandtibo/invoke-tasklib/actions/workflows/nightly-package.yaml/badge.svg">
37
+ </a>
38
+ <a href="https://codecov.io/gh/durandtibo/invoke-tasklib">
39
+ <img alt="Codecov" src="https://codecov.io/gh/durandtibo/invoke-tasklib/branch/main/graph/badge.svg">
40
+ </a>
41
+ <br/>
42
+ <a href="https://durandtibo.github.io/invoke-tasklib/">
43
+ <img alt="Documentation" src="https://github.com/durandtibo/invoke-tasklib/actions/workflows/release-docs.yaml/badge.svg">
44
+ </a>
45
+ <a href="https://durandtibo.github.io/invoke-tasklib/dev/">
46
+ <img alt="Documentation" src="https://github.com/durandtibo/invoke-tasklib/actions/workflows/release-docs-dev.yaml/badge.svg">
47
+ </a>
48
+ <br/>
49
+ <a href="https://github.com/psf/black">
50
+ <img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg">
51
+ </a>
52
+ <a href="https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings">
53
+ <img alt="Doc style: google" src="https://img.shields.io/badge/%20style-google-3666d6.svg">
54
+ </a>
55
+ <a href="https://github.com/astral-sh/ruff">
56
+ <img alt="Ruff" src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json">
57
+ </a>
58
+ <a href="https://github.com/guilatrova/tryceratops">
59
+ <img alt="try/except style: tryceratops" src="https://img.shields.io/badge/try%2Fexcept%20style-tryceratops%20%F0%9F%A6%96%E2%9C%A8-black">
60
+ </a>
61
+ <br/>
62
+ <a href="https://pypi.org/project/invoke-tasklib/">
63
+ <img alt="PYPI version" src="https://img.shields.io/pypi/v/invoke-tasklib">
64
+ </a>
65
+ <a href="https://pypi.org/project/invoke-tasklib/">
66
+ <img alt="Python" src="https://img.shields.io/pypi/pyversions/invoke-tasklib.svg">
67
+ </a>
68
+ <a href="https://opensource.org/licenses/BSD-3-Clause">
69
+ <img alt="BSD-3-Clause" src="https://img.shields.io/pypi/l/invoke-tasklib">
70
+ </a>
71
+ <br/>
72
+ <a href="https://pepy.tech/project/invoke-tasklib">
73
+ <img alt="Downloads" src="https://static.pepy.tech/badge/invoke-tasklib">
74
+ </a>
75
+ <a href="https://pepy.tech/project/invoke-tasklib">
76
+ <img alt="Monthly downloads" src="https://static.pepy.tech/badge/invoke-tasklib/month">
77
+ </a>
78
+ <a href="https://github.com/durandtibo/invoke-tasklib/stargazers">
79
+ <img alt="GitHub stars" src="https://img.shields.io/github/stars/durandtibo/invoke-tasklib">
80
+ </a>
81
+ <br/>
82
+ <a href="https://www.bestpractices.dev/projects/14387">
83
+ <img src="https://www.bestpractices.dev/projects/14387/badge">
84
+ </a>
85
+ <a href="https://scorecard.dev/viewer/?uri=github.com/durandtibo/invoke-tasklib">
86
+ <img alt="OpenSSF Scorecard" src="https://img.shields.io/badge/dynamic/json?url=https://api.scorecard.dev/projects/github.com/durandtibo/invoke-tasklib&label=openssf%20scorecard&query=score">
87
+ </a>
88
+ </p>
89
+
90
+ Reusable [Invoke](https://www.pyinvoke.org/) tasks shared across Python
91
+ projects: formatting, linting, type-checking, testing, environment setup,
92
+ security auditing, releasing, documentation, and cleanup — all as a single
93
+ importable package instead of a `tasks.py` you copy-paste and let drift
94
+ between repositories.
95
+
96
+ :book: **Full documentation:** <https://durandtibo.github.io/invoke-tasklib/>
97
+
98
+ ## Install
99
+
100
+ ```shell
101
+ uv add --dev invoke-tasklib
102
+ ```
103
+
104
+ or with `pip`:
105
+
106
+ ```shell
107
+ pip install invoke-tasklib
108
+ ```
109
+
110
+ ## Quickstart
111
+
112
+ **1. Add a `tasks.py`** at the root of your project:
113
+
114
+ ```python
115
+ # tasks.py
116
+ from invoke_tasklib import ns
117
+ ```
118
+
119
+ **2. Add an `invoke.yaml`** with, at minimum, your package name:
120
+
121
+ ```yaml
122
+ tasklib:
123
+ package:
124
+ name: my_package
125
+ ```
126
+
127
+ **3. List and run the tasks:**
128
+
129
+ ```shell
130
+ invoke --list
131
+ invoke format.check-python lint.check-lint
132
+ invoke test.unit
133
+ ```
134
+
135
+ If a task fails because a tool like `ruff` or `pytest` isn't installed yet,
136
+ run `invoke env.install` first.
137
+
138
+ See the [Get Started guide](https://durandtibo.github.io/invoke-tasklib/get_started/)
139
+ for a full walkthrough.
140
+
141
+ ## Tasks
142
+
143
+ Tasks are grouped into namespaces, one per module. Each task either
144
+ **checks/reports** (read-only, exits non-zero on violations) or
145
+ **mutates** (formats, builds, publishes) — the table below flags which.
146
+
147
+ | Namespace | Task | Behavior | Mutates? |
148
+ | ------------- | ----------------------------- | ---------------------------------------------------------------------------------------- | :------: |
149
+ | `format` | `format.check-python` | Check Python formatting with ruff | ❌ |
150
+ | `format` | `format.fix-python` | Format Python code with ruff | ✅ |
151
+ | `format` | `format.check-docstrings` | Check docstring formatting with docformatter | ❌ |
152
+ | `format` | `format.fix-docstrings` | Format docstrings with docformatter | ✅ |
153
+ | `format` | `format.check-shell` | Check shell scripts with shellcheck | ❌ |
154
+ | `format` | `format.fix-shell` | Format shell scripts with shfmt | ✅ |
155
+ | `lint` | `lint.check-lint` | Check linting with ruff | ❌ |
156
+ | `lint` | `lint.fix` | Fix auto-fixable linting issues with ruff | ✅ |
157
+ | `types` | `types.check` | Check type hints with pyright | ❌ |
158
+ | `test` | `test.doctest` | Run doctests on source code and markdown files | ❌ |
159
+ | `test` | `test.doctest-src` | Run doctests on source code | ❌ |
160
+ | `test` | `test.doctest-markdown` | Run doctests on Python examples in markdown files | ❌ |
161
+ | `test` | `test.unit` | Run unit tests | ❌ |
162
+ | `test` | `test.integration` | Run integration tests | ❌ |
163
+ | `test` | `test.functional` | Run functional tests | ❌ |
164
+ | `test` | `test.all` | Run unit, integration, and functional tests | ❌ |
165
+ | `test` | `test.coverage-report` | Generate an HTML/terminal report from existing coverage data | ❌ |
166
+ | `test` | `test.benchmark` | Run performance benchmarks | ❌ |
167
+ | `env` | `env.create-venv` | Create a virtual environment and install invoke | ✅ |
168
+ | `env` | `env.install` | Install project dependencies and the package (editable) | ✅ |
169
+ | `env` | `env.update` | Update dependencies and pre-commit hooks | ✅ |
170
+ | `env` | `env.show-installed-packages` | Show the installed packages | ❌ |
171
+ | `env` | `env.show-python-config` | Show the Python configuration | ❌ |
172
+ | `release` | `release.build` | Build the package and verify installation (`--check` also validates metadata with twine) | ✅ |
173
+ | `release` | `release.pypi` | Build and publish the package to PyPI | ✅ |
174
+ | `doc` | `doc.publish-dev` | Publish development (unstable) docs | ✅ |
175
+ | `doc` | `doc.publish-latest` | Publish latest (stable) docs | ✅ |
176
+ | `security` | `security.audit` | Audit installed dependencies for known vulnerabilities with pip-audit | ❌ |
177
+ | _(top-level)_ | `clean` | Remove build artifacts and caches | ✅ |
178
+
179
+ `format.*` and `lint.*` follow a naming convention: read-only checks are
180
+ named `check_<target>`, and the matching in-place fixer is named
181
+ `fix_<target>` (e.g. `check_python`/`fix_python`), so the counterpart of a
182
+ task is always easy to find. Follow this convention when adding new tasks
183
+ to these namespaces.
184
+
185
+ For task-by-task details, options (like `--cov` on `test.*` tasks), and the
186
+ tools each one wraps, see the
187
+ [User Guide](https://durandtibo.github.io/invoke-tasklib/uguide/).
188
+
189
+ ## Configuration
190
+
191
+ Only `tasklib.package.name` is required — everything else has a sensible
192
+ default derived from it:
193
+
194
+ ```yaml
195
+ tasklib:
196
+ package:
197
+ name: my_package # required
198
+ python_version: "3.14" # used by env.create-venv
199
+ paths:
200
+ src: src/my_package # default: src/<package.name>
201
+ tests: tests
202
+ unit_tests: tests/unit # default: <tests>/unit
203
+ integration_tests: tests/integration # default: <tests>/integration
204
+ functional_tests: tests/functional # default: <tests>/functional
205
+ benchmarks: tests/benchmarks # default: <tests>/benchmarks
206
+ docs_config: docs/mkdocs.yml
207
+ ```
208
+
209
+ See the [Config reference](https://durandtibo.github.io/invoke-tasklib/uguide/config/)
210
+ for how each path default is derived.
211
+
212
+ ## Composing a custom subset of tasks
213
+
214
+ Need a different set of tasks, or a one-off task alongside the shared ones?
215
+ Import individual task modules instead of the pre-built `ns`:
216
+
217
+ ```python
218
+ from invoke import Collection
219
+ from invoke_tasklib import lint, test
220
+
221
+ from . import my_custom_task
222
+
223
+ ns = Collection(lint, test, my_custom_task)
224
+ ```
225
+
226
+ Prefer adding a config knob to a shared task over forking it; reserve custom
227
+ composition for things that are genuinely one-off to a single project.
228
+
229
+ ## API Stability
230
+
231
+ :warning: `invoke-tasklib` is under active development and its API is not
232
+ yet stable — pin a specific version in your project's dependencies for
233
+ consistent behavior across releases.
234
+
235
+ ## Contributing
236
+
237
+ Contributions are welcome! Please open an issue first to discuss
238
+ significant changes. See the
239
+ [developer guide](https://durandtibo.github.io/invoke-tasklib/dev/development/)
240
+ for how to set up a development environment.
241
+
242
+ ## License
243
+
244
+ `invoke-tasklib` is licensed under the BSD 3-Clause "New" or "Revised"
245
+ license available in
246
+ [LICENSE](https://github.com/durandtibo/invoke-tasklib/blob/main/LICENSE).
@@ -0,0 +1,218 @@
1
+ # invoke-tasklib
2
+
3
+ <p align="center">
4
+ <a href="https://github.com/durandtibo/invoke-tasklib/actions/workflows/ci.yaml">
5
+ <img alt="CI" src="https://github.com/durandtibo/invoke-tasklib/actions/workflows/ci.yaml/badge.svg">
6
+ </a>
7
+ <a href="https://github.com/durandtibo/invoke-tasklib/actions/workflows/nightly-package.yaml">
8
+ <img alt="Nightly Package Tests" src="https://github.com/durandtibo/invoke-tasklib/actions/workflows/nightly-package.yaml/badge.svg">
9
+ </a>
10
+ <a href="https://codecov.io/gh/durandtibo/invoke-tasklib">
11
+ <img alt="Codecov" src="https://codecov.io/gh/durandtibo/invoke-tasklib/branch/main/graph/badge.svg">
12
+ </a>
13
+ <br/>
14
+ <a href="https://durandtibo.github.io/invoke-tasklib/">
15
+ <img alt="Documentation" src="https://github.com/durandtibo/invoke-tasklib/actions/workflows/release-docs.yaml/badge.svg">
16
+ </a>
17
+ <a href="https://durandtibo.github.io/invoke-tasklib/dev/">
18
+ <img alt="Documentation" src="https://github.com/durandtibo/invoke-tasklib/actions/workflows/release-docs-dev.yaml/badge.svg">
19
+ </a>
20
+ <br/>
21
+ <a href="https://github.com/psf/black">
22
+ <img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg">
23
+ </a>
24
+ <a href="https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings">
25
+ <img alt="Doc style: google" src="https://img.shields.io/badge/%20style-google-3666d6.svg">
26
+ </a>
27
+ <a href="https://github.com/astral-sh/ruff">
28
+ <img alt="Ruff" src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json">
29
+ </a>
30
+ <a href="https://github.com/guilatrova/tryceratops">
31
+ <img alt="try/except style: tryceratops" src="https://img.shields.io/badge/try%2Fexcept%20style-tryceratops%20%F0%9F%A6%96%E2%9C%A8-black">
32
+ </a>
33
+ <br/>
34
+ <a href="https://pypi.org/project/invoke-tasklib/">
35
+ <img alt="PYPI version" src="https://img.shields.io/pypi/v/invoke-tasklib">
36
+ </a>
37
+ <a href="https://pypi.org/project/invoke-tasklib/">
38
+ <img alt="Python" src="https://img.shields.io/pypi/pyversions/invoke-tasklib.svg">
39
+ </a>
40
+ <a href="https://opensource.org/licenses/BSD-3-Clause">
41
+ <img alt="BSD-3-Clause" src="https://img.shields.io/pypi/l/invoke-tasklib">
42
+ </a>
43
+ <br/>
44
+ <a href="https://pepy.tech/project/invoke-tasklib">
45
+ <img alt="Downloads" src="https://static.pepy.tech/badge/invoke-tasklib">
46
+ </a>
47
+ <a href="https://pepy.tech/project/invoke-tasklib">
48
+ <img alt="Monthly downloads" src="https://static.pepy.tech/badge/invoke-tasklib/month">
49
+ </a>
50
+ <a href="https://github.com/durandtibo/invoke-tasklib/stargazers">
51
+ <img alt="GitHub stars" src="https://img.shields.io/github/stars/durandtibo/invoke-tasklib">
52
+ </a>
53
+ <br/>
54
+ <a href="https://www.bestpractices.dev/projects/14387">
55
+ <img src="https://www.bestpractices.dev/projects/14387/badge">
56
+ </a>
57
+ <a href="https://scorecard.dev/viewer/?uri=github.com/durandtibo/invoke-tasklib">
58
+ <img alt="OpenSSF Scorecard" src="https://img.shields.io/badge/dynamic/json?url=https://api.scorecard.dev/projects/github.com/durandtibo/invoke-tasklib&label=openssf%20scorecard&query=score">
59
+ </a>
60
+ </p>
61
+
62
+ Reusable [Invoke](https://www.pyinvoke.org/) tasks shared across Python
63
+ projects: formatting, linting, type-checking, testing, environment setup,
64
+ security auditing, releasing, documentation, and cleanup — all as a single
65
+ importable package instead of a `tasks.py` you copy-paste and let drift
66
+ between repositories.
67
+
68
+ :book: **Full documentation:** <https://durandtibo.github.io/invoke-tasklib/>
69
+
70
+ ## Install
71
+
72
+ ```shell
73
+ uv add --dev invoke-tasklib
74
+ ```
75
+
76
+ or with `pip`:
77
+
78
+ ```shell
79
+ pip install invoke-tasklib
80
+ ```
81
+
82
+ ## Quickstart
83
+
84
+ **1. Add a `tasks.py`** at the root of your project:
85
+
86
+ ```python
87
+ # tasks.py
88
+ from invoke_tasklib import ns
89
+ ```
90
+
91
+ **2. Add an `invoke.yaml`** with, at minimum, your package name:
92
+
93
+ ```yaml
94
+ tasklib:
95
+ package:
96
+ name: my_package
97
+ ```
98
+
99
+ **3. List and run the tasks:**
100
+
101
+ ```shell
102
+ invoke --list
103
+ invoke format.check-python lint.check-lint
104
+ invoke test.unit
105
+ ```
106
+
107
+ If a task fails because a tool like `ruff` or `pytest` isn't installed yet,
108
+ run `invoke env.install` first.
109
+
110
+ See the [Get Started guide](https://durandtibo.github.io/invoke-tasklib/get_started/)
111
+ for a full walkthrough.
112
+
113
+ ## Tasks
114
+
115
+ Tasks are grouped into namespaces, one per module. Each task either
116
+ **checks/reports** (read-only, exits non-zero on violations) or
117
+ **mutates** (formats, builds, publishes) — the table below flags which.
118
+
119
+ | Namespace | Task | Behavior | Mutates? |
120
+ | ------------- | ----------------------------- | ---------------------------------------------------------------------------------------- | :------: |
121
+ | `format` | `format.check-python` | Check Python formatting with ruff | ❌ |
122
+ | `format` | `format.fix-python` | Format Python code with ruff | ✅ |
123
+ | `format` | `format.check-docstrings` | Check docstring formatting with docformatter | ❌ |
124
+ | `format` | `format.fix-docstrings` | Format docstrings with docformatter | ✅ |
125
+ | `format` | `format.check-shell` | Check shell scripts with shellcheck | ❌ |
126
+ | `format` | `format.fix-shell` | Format shell scripts with shfmt | ✅ |
127
+ | `lint` | `lint.check-lint` | Check linting with ruff | ❌ |
128
+ | `lint` | `lint.fix` | Fix auto-fixable linting issues with ruff | ✅ |
129
+ | `types` | `types.check` | Check type hints with pyright | ❌ |
130
+ | `test` | `test.doctest` | Run doctests on source code and markdown files | ❌ |
131
+ | `test` | `test.doctest-src` | Run doctests on source code | ❌ |
132
+ | `test` | `test.doctest-markdown` | Run doctests on Python examples in markdown files | ❌ |
133
+ | `test` | `test.unit` | Run unit tests | ❌ |
134
+ | `test` | `test.integration` | Run integration tests | ❌ |
135
+ | `test` | `test.functional` | Run functional tests | ❌ |
136
+ | `test` | `test.all` | Run unit, integration, and functional tests | ❌ |
137
+ | `test` | `test.coverage-report` | Generate an HTML/terminal report from existing coverage data | ❌ |
138
+ | `test` | `test.benchmark` | Run performance benchmarks | ❌ |
139
+ | `env` | `env.create-venv` | Create a virtual environment and install invoke | ✅ |
140
+ | `env` | `env.install` | Install project dependencies and the package (editable) | ✅ |
141
+ | `env` | `env.update` | Update dependencies and pre-commit hooks | ✅ |
142
+ | `env` | `env.show-installed-packages` | Show the installed packages | ❌ |
143
+ | `env` | `env.show-python-config` | Show the Python configuration | ❌ |
144
+ | `release` | `release.build` | Build the package and verify installation (`--check` also validates metadata with twine) | ✅ |
145
+ | `release` | `release.pypi` | Build and publish the package to PyPI | ✅ |
146
+ | `doc` | `doc.publish-dev` | Publish development (unstable) docs | ✅ |
147
+ | `doc` | `doc.publish-latest` | Publish latest (stable) docs | ✅ |
148
+ | `security` | `security.audit` | Audit installed dependencies for known vulnerabilities with pip-audit | ❌ |
149
+ | _(top-level)_ | `clean` | Remove build artifacts and caches | ✅ |
150
+
151
+ `format.*` and `lint.*` follow a naming convention: read-only checks are
152
+ named `check_<target>`, and the matching in-place fixer is named
153
+ `fix_<target>` (e.g. `check_python`/`fix_python`), so the counterpart of a
154
+ task is always easy to find. Follow this convention when adding new tasks
155
+ to these namespaces.
156
+
157
+ For task-by-task details, options (like `--cov` on `test.*` tasks), and the
158
+ tools each one wraps, see the
159
+ [User Guide](https://durandtibo.github.io/invoke-tasklib/uguide/).
160
+
161
+ ## Configuration
162
+
163
+ Only `tasklib.package.name` is required — everything else has a sensible
164
+ default derived from it:
165
+
166
+ ```yaml
167
+ tasklib:
168
+ package:
169
+ name: my_package # required
170
+ python_version: "3.14" # used by env.create-venv
171
+ paths:
172
+ src: src/my_package # default: src/<package.name>
173
+ tests: tests
174
+ unit_tests: tests/unit # default: <tests>/unit
175
+ integration_tests: tests/integration # default: <tests>/integration
176
+ functional_tests: tests/functional # default: <tests>/functional
177
+ benchmarks: tests/benchmarks # default: <tests>/benchmarks
178
+ docs_config: docs/mkdocs.yml
179
+ ```
180
+
181
+ See the [Config reference](https://durandtibo.github.io/invoke-tasklib/uguide/config/)
182
+ for how each path default is derived.
183
+
184
+ ## Composing a custom subset of tasks
185
+
186
+ Need a different set of tasks, or a one-off task alongside the shared ones?
187
+ Import individual task modules instead of the pre-built `ns`:
188
+
189
+ ```python
190
+ from invoke import Collection
191
+ from invoke_tasklib import lint, test
192
+
193
+ from . import my_custom_task
194
+
195
+ ns = Collection(lint, test, my_custom_task)
196
+ ```
197
+
198
+ Prefer adding a config knob to a shared task over forking it; reserve custom
199
+ composition for things that are genuinely one-off to a single project.
200
+
201
+ ## API Stability
202
+
203
+ :warning: `invoke-tasklib` is under active development and its API is not
204
+ yet stable — pin a specific version in your project's dependencies for
205
+ consistent behavior across releases.
206
+
207
+ ## Contributing
208
+
209
+ Contributions are welcome! Please open an issue first to discuss
210
+ significant changes. See the
211
+ [developer guide](https://durandtibo.github.io/invoke-tasklib/dev/development/)
212
+ for how to set up a development environment.
213
+
214
+ ## License
215
+
216
+ `invoke-tasklib` is licensed under the BSD 3-Clause "New" or "Revised"
217
+ license available in
218
+ [LICENSE](https://github.com/durandtibo/invoke-tasklib/blob/main/LICENSE).
@@ -23,9 +23,30 @@ from __future__ import annotations
23
23
 
24
24
  from invoke.collection import Collection
25
25
 
26
- from invoke_tasklib import doc, env, format, lint, release, test, types
27
-
28
- __all__ = ["doc", "env", "format", "lint", "ns", "release", "test", "types"]
26
+ from invoke_tasklib import (
27
+ clean,
28
+ doc,
29
+ env,
30
+ format, # noqa: A004
31
+ lint,
32
+ release,
33
+ security,
34
+ test,
35
+ types,
36
+ )
37
+
38
+ __all__ = [
39
+ "clean",
40
+ "doc",
41
+ "env",
42
+ "format",
43
+ "lint",
44
+ "ns",
45
+ "release",
46
+ "security",
47
+ "test",
48
+ "types",
49
+ ]
29
50
 
30
51
  ns: Collection = Collection()
31
52
  ns.add_collection(Collection.from_module(format), name="format")
@@ -35,3 +56,5 @@ ns.add_collection(Collection.from_module(test), name="test")
35
56
  ns.add_collection(Collection.from_module(env), name="env")
36
57
  ns.add_collection(Collection.from_module(release), name="release")
37
58
  ns.add_collection(Collection.from_module(doc), name="doc")
59
+ ns.add_collection(Collection.from_module(security), name="security")
60
+ ns.add_task(clean.all, name="clean")
@@ -0,0 +1,55 @@
1
+ r"""Cleanup tasks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import shutil
7
+ from pathlib import Path
8
+ from typing import TYPE_CHECKING
9
+
10
+ from invoke.tasks import task
11
+
12
+ if TYPE_CHECKING:
13
+ from invoke.context import Context
14
+
15
+ logger: logging.Logger = logging.getLogger(__name__)
16
+
17
+ DIRS = (
18
+ "build",
19
+ "dist",
20
+ ".pytest_cache",
21
+ ".ruff_cache",
22
+ ".coverage_html",
23
+ "htmlcov",
24
+ ".benchmarks",
25
+ "site",
26
+ )
27
+ DIR_GLOBS = ("*.egg-info", "**/__pycache__")
28
+ FILES = (".coverage", "coverage.xml")
29
+
30
+
31
+ @task
32
+ def all(c: Context) -> None: # noqa: A001, ARG001 (task name/signature required by invoke)
33
+ r"""Remove build artifacts and caches (dist, __pycache__,
34
+ .pytest_cache, .coverage, etc.)."""
35
+ logger.info("🧹 Cleaning build artifacts and caches...")
36
+ for d in DIRS:
37
+ _remove_dir(Path(d))
38
+ for pattern in DIR_GLOBS:
39
+ for p in Path().glob(pattern):
40
+ _remove_dir(p)
41
+ for f in FILES:
42
+ _remove_file(Path(f))
43
+ logger.info("✅ Cleanup complete")
44
+
45
+
46
+ def _remove_dir(path: Path) -> None:
47
+ if path.is_dir():
48
+ logger.info(f"🗑️ Removing {path}")
49
+ shutil.rmtree(path)
50
+
51
+
52
+ def _remove_file(path: Path) -> None:
53
+ if path.is_file():
54
+ logger.info(f"🗑️ Removing {path}")
55
+ path.unlink()
@@ -40,11 +40,19 @@ class PathsConfig(TypedDict):
40
40
  docs_config: str
41
41
 
42
42
 
43
+ class GroupsConfig(TypedDict):
44
+ r"""Resolved ``groups`` config section."""
45
+
46
+ install: str
47
+ update: str
48
+
49
+
43
50
  class TasklibConfig(TypedDict):
44
51
  r"""Resolved tasklib config."""
45
52
 
46
53
  package: PackageConfig
47
54
  paths: PathsConfig
55
+ groups: GroupsConfig
48
56
 
49
57
 
50
58
  DEFAULT_PACKAGE: dict[str, str | None] = {
@@ -62,6 +70,11 @@ DEFAULT_PATHS: dict[str, str | None] = {
62
70
  "docs_config": "docs/mkdocs.yml",
63
71
  }
64
72
 
73
+ DEFAULT_GROUPS: dict[str, str] = {
74
+ "install": "dev",
75
+ "update": "dev,docs",
76
+ }
77
+
65
78
 
66
79
  def get_config(c: Context) -> TasklibConfig:
67
80
  r"""Return the effective tasklib config, merging user overrides from
@@ -79,6 +92,7 @@ def get_config(c: Context) -> TasklibConfig:
79
92
  user = dict(c.config.get("tasklib", {}))
80
93
  package = {**DEFAULT_PACKAGE, **user.get("package", {})}
81
94
  paths = {**DEFAULT_PATHS, **user.get("paths", {})}
95
+ groups = {**DEFAULT_GROUPS, **user.get("groups", {})}
82
96
 
83
97
  if not package["name"]:
84
98
  msg = "'tasklib.package.name' must be set in invoke.yaml"
@@ -106,4 +120,5 @@ def get_config(c: Context) -> TasklibConfig:
106
120
  benchmarks=paths["benchmarks"],
107
121
  docs_config=paths["docs_config"],
108
122
  ),
123
+ "groups": GroupsConfig(install=groups["install"], update=groups["update"]),
109
124
  }
@@ -35,8 +35,8 @@ def publish_latest(c: Context) -> None:
35
35
  Requires the ``feu`` and ``packaging`` packages to determine the
36
36
  latest version tag.
37
37
  """
38
- from feu.local_git import get_last_version_tag_name
39
- from packaging.version import Version
38
+ from feu.local_git import get_last_version_tag_name # noqa: PLC0415 (optional dependency)
39
+ from packaging.version import Version # noqa: PLC0415 (optional dependency)
40
40
 
41
41
  cfg = get_config(c)
42
42
  docs_config = cfg["paths"]["docs_config"]