pyprojkit 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Matt
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,310 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyprojkit
3
+ Version: 0.1.0
4
+ Summary: Development workflow toolkit for Python projects: pyproject.toml sync, doit tasks, nox sessions
5
+ Author: mm21
6
+ Author-email: mm21 <mm21.dev@gmail.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Natural Language :: English
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Programming Language :: Python :: Implementation :: CPython
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Typing :: Typed
19
+ Requires-Dist: doit>=0.36.0,<0.37
20
+ Requires-Dist: nox>=2026.4.10
21
+ Requires-Dist: python-dotenv>=1.0.1,<2
22
+ Requires-Dist: toml-sort>=0.24.2,<0.25
23
+ Requires-Dist: tomlkit>=0.13.3,<0.14
24
+ Requires-Dist: pyprojkit[analysis,doc,format,test] ; extra == 'all'
25
+ Requires-Dist: mypy[reports]>=1.5.1,<2 ; extra == 'analysis'
26
+ Requires-Dist: pyright>=1.1.329,<2 ; extra == 'analysis'
27
+ Requires-Dist: mkinit ; extra == 'doc'
28
+ Requires-Dist: autoflake>=2.3.1,<3 ; extra == 'format'
29
+ Requires-Dist: black>=25.1.0,<26 ; extra == 'format'
30
+ Requires-Dist: docformatter>=1.7.7,<2 ; extra == 'format'
31
+ Requires-Dist: isort>=6.0.1,<7 ; extra == 'format'
32
+ Requires-Dist: genbadge[tests,coverage]>=1.1.0,<2 ; extra == 'test'
33
+ Requires-Dist: pytest>=8.4.2,<9 ; extra == 'test'
34
+ Requires-Dist: pytest-cov>=7.1.0 ; extra == 'test'
35
+ Requires-Python: >=3.12, <3.15
36
+ Project-URL: homepage, https://github.com/mm21/pyprojkit
37
+ Provides-Extra: all
38
+ Provides-Extra: analysis
39
+ Provides-Extra: doc
40
+ Provides-Extra: format
41
+ Provides-Extra: test
42
+ Description-Content-Type: text/markdown
43
+
44
+ # PyProjKit
45
+
46
+ Development workflow toolkit for Python projects
47
+
48
+ [![Python versions](https://img.shields.io/pypi/pyversions/pyprojkit.svg)](https://pypi.org/project/pyprojkit)
49
+ [![PyPI](https://img.shields.io/pypi/v/pyprojkit?color=%2334D058&label=pypi%20package)](https://pypi.org/project/pyprojkit)
50
+ [![Tests](./badges/tests.svg?dummy=8484744)]()
51
+ [![Coverage](./badges/cov.svg?dummy=8484744)]()
52
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
53
+
54
+ - [PyProjKit](#pyprojkit)
55
+ - [Motivation](#motivation)
56
+ - [Getting started](#getting-started)
57
+ - [Declaring configuration: `pyprojconf.py`](#declaring-configuration-pyprojconfpy)
58
+ - [Python versions](#python-versions)
59
+ - [Tools and profiles](#tools-and-profiles)
60
+ - [Syncing `pyproject.toml`](#syncing-pyprojecttoml)
61
+ - [Managed content](#managed-content)
62
+ - [Check mode](#check-mode)
63
+ - [doit tasks](#doit-tasks)
64
+ - [nox sessions](#nox-sessions)
65
+ - [Path conventions](#path-conventions)
66
+ - [Custom profiles](#custom-profiles)
67
+
68
+ ## Motivation
69
+
70
+ Every Python project accumulates the same development workflow boilerplate: formatter settings in `pyproject.toml`, supported Python versions repeated across classifiers, `requires-python`, black's `target-version`, and the testing matrix, plus a `dodo.py` and `noxfile.py` that look nearly identical from project to project. Keeping all of it consistent — and keeping it up to date as tools and Python versions evolve — is tedious and error-prone.
71
+
72
+ PyProjKit centralizes all of this. Each project declares its configuration exactly once in a `pyprojconf.py` at the project root; PyProjKit then:
73
+
74
+ 1. **Syncs `pyproject.toml`**: writes the managed parts (version classifiers, `requires-python`, `[tool.*]` tables) while preserving everything else, with a `--check` mode for CI.
75
+ 2. **Provides `doit` task factories**: format, test, badges, publish, and more, pre-wired to sensible conventions.
76
+ 3. **Provides `nox` session factories**: a test session across all supported Python versions, pinned to exact patch releases.
77
+
78
+ Supported Python versions are declared once and drive everything: classifiers, `requires-python`, black's `target-version`, mypy's `python_version`, and the nox interpreter matrix.
79
+
80
+ ## Getting started
81
+
82
+ Install from PyPI:
83
+
84
+ ```bash
85
+ pip install pyprojkit
86
+ ```
87
+
88
+ Or add it to your project's dev dependencies (formatter, test, and analysis tools are available as extras):
89
+
90
+ ```toml
91
+ [dependency-groups]
92
+ dev = [
93
+ "pyprojkit[all]"
94
+ ]
95
+ ```
96
+
97
+ Then drop three small files into your project root.
98
+
99
+ `pyprojconf.py`:
100
+
101
+ ```python
102
+ from pyprojkit import ProjectConfig, PythonVersions
103
+
104
+ config = ProjectConfig(package="my_package", python=PythonVersions(3, (12, 14)))
105
+ ```
106
+
107
+ `dodo.py`:
108
+
109
+ ```python
110
+ from pyprojkit import TaskFactory
111
+
112
+ globals().update(TaskFactory().create_all_tasks())
113
+ ```
114
+
115
+ `noxfile.py`:
116
+
117
+ ```python
118
+ from pyprojkit import NoxFactory
119
+
120
+ test = NoxFactory().create_test_session()
121
+ ```
122
+
123
+ Then sync your `pyproject.toml` and run your workflow:
124
+
125
+ ```bash
126
+ doit sync # or: pyprojkit sync
127
+ doit format
128
+ doit test
129
+ doit badges
130
+ nox
131
+ ```
132
+
133
+ ## Declaring configuration: `pyprojconf.py`
134
+
135
+ `pyprojconf.py` must define a module-level `config: ProjectConfig`. `TaskFactory`, `NoxFactory`, and the `pyprojkit` CLI load it automatically from the current directory.
136
+
137
+ ### Python versions
138
+
139
+ `PythonVersions` takes the major version and an inclusive range of minor versions — only versions you explicitly support (i.e. test against):
140
+
141
+ ```python
142
+ python = PythonVersions(3, (12, 14))
143
+ ```
144
+
145
+ This single declaration drives:
146
+
147
+ - `requires-python` (`>=3.12,<3.15`)
148
+ - Trove classifiers (`Programming Language :: Python :: 3.12`, ...)
149
+ - black's `target-version` (`["py312", "py313", "py314"]`)
150
+ - mypy's `python_version` (`3.12`)
151
+ - nox interpreter pins (`3.12.13`, `3.13.13`, `3.14.6`)
152
+
153
+ The exact patch releases used for nox come from a mapping bundled with PyProjKit, updated with each release — so updating PyProjKit refreshes the pins across all your projects. Individual projects can override:
154
+
155
+ ```python
156
+ python = PythonVersions(3, (12, 14), patch_overrides={(3, 14): "3.14.7"})
157
+ ```
158
+
159
+ ### Tools and profiles
160
+
161
+ Tool configurations are grouped by category under `ToolsConfig`, whose defaults constitute the default *profile*:
162
+
163
+ - `formatting`: ordered chain of formatters; by default autoflake &rarr; isort &rarr; black &rarr; docformatter &rarr; toml-sort
164
+ - `test`: pytest + coverage settings
165
+ - `doit`, `nox`: cache locations and backends
166
+ - `doc`: documentation tools — mkinit (enabled by default) and sphinx (opt-in)
167
+ - `analysis`: mypy + pyright (opt-in)
168
+ - `publish`: build/publish output directory
169
+
170
+ Customize with `dataclasses.replace`:
171
+
172
+ ```python
173
+ from dataclasses import replace
174
+
175
+ from pyprojkit import (
176
+ AnalysisConfig,
177
+ DocConfig,
178
+ ProjectConfig,
179
+ PythonVersions,
180
+ SphinxConfig,
181
+ ToolsConfig,
182
+ )
183
+
184
+ config = ProjectConfig(
185
+ package="my_package",
186
+ python=PythonVersions(3, (12, 14)),
187
+ tools=replace(
188
+ ToolsConfig.default(),
189
+ doc=DocConfig(sphinx=SphinxConfig(copy_env_var="MY_PACKAGE_DOCS_DIR")),
190
+ analysis=AnalysisConfig(),
191
+ ),
192
+ )
193
+ ```
194
+
195
+ For one-off tweaks to managed tables there's an escape hatch, merged last into the synced output:
196
+
197
+ ```python
198
+ tools=replace(
199
+ ToolsConfig.default(),
200
+ tool_overrides={"tool.pytest.ini_options": {"addopts": "-x"}},
201
+ )
202
+ ```
203
+
204
+ ## Syncing `pyproject.toml`
205
+
206
+ Formatters and other tools read their settings from `pyproject.toml`, so PyProjKit writes them there — `pyproject.toml` remains the single source of truth for the tools themselves, while `pyprojconf.py` is the single source of truth for you.
207
+
208
+ ### Managed content
209
+
210
+ The sync engine owns:
211
+
212
+ - `project.requires-python`
213
+ - Python version classifiers (other classifiers are untouched)
214
+ - One `[tool.X]` table per enabled tool (fully owned; hand edits inside are overwritten)
215
+ - `[tool.pyprojkit].managed`: bookkeeping list of owned tables, so a tool dropped from your configuration gets its table cleanly removed on the next sync
216
+
217
+ Everything else — dependencies, `[tool.uv.sources]`, build system, unmanaged tool tables — is preserved. Output is normalized with toml-sort using the same settings as the managed `[tool.tomlsort]` table, so syncing and formatting never fight.
218
+
219
+ ### Check mode
220
+
221
+ Verify a project is in sync without writing (e.g. in CI):
222
+
223
+ ```bash
224
+ pyprojkit sync --check
225
+ ```
226
+
227
+ Prints a diff and exits nonzero if `pyproject.toml` is out of date.
228
+
229
+ ## doit tasks
230
+
231
+ `TaskFactory` creates `doit` tasks pre-wired to the configuration. Create them selectively:
232
+
233
+ ```python
234
+ from pyprojkit import TaskFactory
235
+
236
+ factory = TaskFactory()
237
+
238
+ task_sync = factory.create_sync_task()
239
+ task_format = factory.create_format_task()
240
+ task_test = factory.create_test_task()
241
+ task_badges = factory.create_badges_task()
242
+ task_publish = factory.create_publish_task()
243
+ ```
244
+
245
+ or all at once: `globals().update(factory.create_all_tasks())`, which creates every task enabled by the configuration.
246
+
247
+ | Task | Description |
248
+ | --- | --- |
249
+ | `sync` | Update `pyproject.toml` from `pyprojconf.py` |
250
+ | `format` | Run the configured formatter chain over the project |
251
+ | `test` | Run pytest with coverage (HTML + XML) and JUnit output |
252
+ | `badges` | Generate test/coverage badges via genbadge |
253
+ | `publish` | Build and publish via uv (output dir is cleaned first, so stale artifacts are never published) |
254
+ | `init` | Generate `__init__.py` files via mkinit (enabled by default) |
255
+ | `doc` | Build documentation via sphinx; `--copy` deploys to a directory given by an env var (opt-in) |
256
+ | `analysis` | Run mypy (with HTML/cobertura reports) and pyright (opt-in) |
257
+
258
+ The `format` task passes an explicit list of paths to each formatter — root `*.py`/`*.toml` files plus the configured `format_paths` directories that exist (`src`, `test`, `doc`, `examples` by default) — so formatters never wander into `.venv` or other unrelated trees.
259
+
260
+ ## nox sessions
261
+
262
+ `NoxFactory.create_test_session()` registers a `test` session which, for each pinned interpreter, syncs the project's dev dependency group via uv into the session environment and runs pytest:
263
+
264
+ ```bash
265
+ $ nox -l
266
+ * test-3.12.13
267
+ * test-3.13.13
268
+ * test-3.14.6
269
+ ```
270
+
271
+ Extra arguments pass through to pytest: `nox -s test-3.12.13 -- -k my_test`.
272
+
273
+ ## Path conventions
274
+
275
+ All tasks share the same layout:
276
+
277
+ - `__cache__/`: caches (doit db, pytest cache, coverage data, nox envs)
278
+ - `__out__/`: generated artifacts (`test/` coverage + JUnit results, `doc/html`, `analysis/`, `uv/` build artifacts)
279
+ - `badges/`: generated badge SVGs
280
+
281
+ ## Custom profiles
282
+
283
+ A profile is a named factory for a pre-canned configuration, at two levels: the overall tools profile and the formatting profile it contains. The `"default"` profiles ship with PyProjKit; register your own once and reuse it across projects:
284
+
285
+ ```python
286
+ # in your shared module, e.g. mycompany_profiles.py
287
+ from dataclasses import replace
288
+
289
+ from pyprojkit import AnalysisConfig, ToolsConfig, register_tools_profile
290
+
291
+ register_tools_profile(
292
+ "mycompany",
293
+ lambda: replace(ToolsConfig.default(), analysis=AnalysisConfig()),
294
+ )
295
+ ```
296
+
297
+ ```python
298
+ # in each project's pyprojconf.py
299
+ import mycompany_profiles # noqa: F401 -- registers the profile
300
+
301
+ from pyprojkit import ProjectConfig, PythonVersions, get_tools_profile
302
+
303
+ config = ProjectConfig(
304
+ package="my_package",
305
+ python=PythonVersions(3, (12, 14)),
306
+ tools=get_tools_profile("mycompany"),
307
+ )
308
+ ```
309
+
310
+ New formatters are equally pluggable: subclass `BaseFormatterConfig` (declaring the tool's `[tool.X]` table and command line) and include it in a `FormattingConfig` — the sync engine and format task pick it up automatically.
@@ -0,0 +1,267 @@
1
+ # PyProjKit
2
+
3
+ Development workflow toolkit for Python projects
4
+
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/pyprojkit.svg)](https://pypi.org/project/pyprojkit)
6
+ [![PyPI](https://img.shields.io/pypi/v/pyprojkit?color=%2334D058&label=pypi%20package)](https://pypi.org/project/pyprojkit)
7
+ [![Tests](./badges/tests.svg?dummy=8484744)]()
8
+ [![Coverage](./badges/cov.svg?dummy=8484744)]()
9
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
10
+
11
+ - [PyProjKit](#pyprojkit)
12
+ - [Motivation](#motivation)
13
+ - [Getting started](#getting-started)
14
+ - [Declaring configuration: `pyprojconf.py`](#declaring-configuration-pyprojconfpy)
15
+ - [Python versions](#python-versions)
16
+ - [Tools and profiles](#tools-and-profiles)
17
+ - [Syncing `pyproject.toml`](#syncing-pyprojecttoml)
18
+ - [Managed content](#managed-content)
19
+ - [Check mode](#check-mode)
20
+ - [doit tasks](#doit-tasks)
21
+ - [nox sessions](#nox-sessions)
22
+ - [Path conventions](#path-conventions)
23
+ - [Custom profiles](#custom-profiles)
24
+
25
+ ## Motivation
26
+
27
+ Every Python project accumulates the same development workflow boilerplate: formatter settings in `pyproject.toml`, supported Python versions repeated across classifiers, `requires-python`, black's `target-version`, and the testing matrix, plus a `dodo.py` and `noxfile.py` that look nearly identical from project to project. Keeping all of it consistent — and keeping it up to date as tools and Python versions evolve — is tedious and error-prone.
28
+
29
+ PyProjKit centralizes all of this. Each project declares its configuration exactly once in a `pyprojconf.py` at the project root; PyProjKit then:
30
+
31
+ 1. **Syncs `pyproject.toml`**: writes the managed parts (version classifiers, `requires-python`, `[tool.*]` tables) while preserving everything else, with a `--check` mode for CI.
32
+ 2. **Provides `doit` task factories**: format, test, badges, publish, and more, pre-wired to sensible conventions.
33
+ 3. **Provides `nox` session factories**: a test session across all supported Python versions, pinned to exact patch releases.
34
+
35
+ Supported Python versions are declared once and drive everything: classifiers, `requires-python`, black's `target-version`, mypy's `python_version`, and the nox interpreter matrix.
36
+
37
+ ## Getting started
38
+
39
+ Install from PyPI:
40
+
41
+ ```bash
42
+ pip install pyprojkit
43
+ ```
44
+
45
+ Or add it to your project's dev dependencies (formatter, test, and analysis tools are available as extras):
46
+
47
+ ```toml
48
+ [dependency-groups]
49
+ dev = [
50
+ "pyprojkit[all]"
51
+ ]
52
+ ```
53
+
54
+ Then drop three small files into your project root.
55
+
56
+ `pyprojconf.py`:
57
+
58
+ ```python
59
+ from pyprojkit import ProjectConfig, PythonVersions
60
+
61
+ config = ProjectConfig(package="my_package", python=PythonVersions(3, (12, 14)))
62
+ ```
63
+
64
+ `dodo.py`:
65
+
66
+ ```python
67
+ from pyprojkit import TaskFactory
68
+
69
+ globals().update(TaskFactory().create_all_tasks())
70
+ ```
71
+
72
+ `noxfile.py`:
73
+
74
+ ```python
75
+ from pyprojkit import NoxFactory
76
+
77
+ test = NoxFactory().create_test_session()
78
+ ```
79
+
80
+ Then sync your `pyproject.toml` and run your workflow:
81
+
82
+ ```bash
83
+ doit sync # or: pyprojkit sync
84
+ doit format
85
+ doit test
86
+ doit badges
87
+ nox
88
+ ```
89
+
90
+ ## Declaring configuration: `pyprojconf.py`
91
+
92
+ `pyprojconf.py` must define a module-level `config: ProjectConfig`. `TaskFactory`, `NoxFactory`, and the `pyprojkit` CLI load it automatically from the current directory.
93
+
94
+ ### Python versions
95
+
96
+ `PythonVersions` takes the major version and an inclusive range of minor versions — only versions you explicitly support (i.e. test against):
97
+
98
+ ```python
99
+ python = PythonVersions(3, (12, 14))
100
+ ```
101
+
102
+ This single declaration drives:
103
+
104
+ - `requires-python` (`>=3.12,<3.15`)
105
+ - Trove classifiers (`Programming Language :: Python :: 3.12`, ...)
106
+ - black's `target-version` (`["py312", "py313", "py314"]`)
107
+ - mypy's `python_version` (`3.12`)
108
+ - nox interpreter pins (`3.12.13`, `3.13.13`, `3.14.6`)
109
+
110
+ The exact patch releases used for nox come from a mapping bundled with PyProjKit, updated with each release — so updating PyProjKit refreshes the pins across all your projects. Individual projects can override:
111
+
112
+ ```python
113
+ python = PythonVersions(3, (12, 14), patch_overrides={(3, 14): "3.14.7"})
114
+ ```
115
+
116
+ ### Tools and profiles
117
+
118
+ Tool configurations are grouped by category under `ToolsConfig`, whose defaults constitute the default *profile*:
119
+
120
+ - `formatting`: ordered chain of formatters; by default autoflake &rarr; isort &rarr; black &rarr; docformatter &rarr; toml-sort
121
+ - `test`: pytest + coverage settings
122
+ - `doit`, `nox`: cache locations and backends
123
+ - `doc`: documentation tools — mkinit (enabled by default) and sphinx (opt-in)
124
+ - `analysis`: mypy + pyright (opt-in)
125
+ - `publish`: build/publish output directory
126
+
127
+ Customize with `dataclasses.replace`:
128
+
129
+ ```python
130
+ from dataclasses import replace
131
+
132
+ from pyprojkit import (
133
+ AnalysisConfig,
134
+ DocConfig,
135
+ ProjectConfig,
136
+ PythonVersions,
137
+ SphinxConfig,
138
+ ToolsConfig,
139
+ )
140
+
141
+ config = ProjectConfig(
142
+ package="my_package",
143
+ python=PythonVersions(3, (12, 14)),
144
+ tools=replace(
145
+ ToolsConfig.default(),
146
+ doc=DocConfig(sphinx=SphinxConfig(copy_env_var="MY_PACKAGE_DOCS_DIR")),
147
+ analysis=AnalysisConfig(),
148
+ ),
149
+ )
150
+ ```
151
+
152
+ For one-off tweaks to managed tables there's an escape hatch, merged last into the synced output:
153
+
154
+ ```python
155
+ tools=replace(
156
+ ToolsConfig.default(),
157
+ tool_overrides={"tool.pytest.ini_options": {"addopts": "-x"}},
158
+ )
159
+ ```
160
+
161
+ ## Syncing `pyproject.toml`
162
+
163
+ Formatters and other tools read their settings from `pyproject.toml`, so PyProjKit writes them there — `pyproject.toml` remains the single source of truth for the tools themselves, while `pyprojconf.py` is the single source of truth for you.
164
+
165
+ ### Managed content
166
+
167
+ The sync engine owns:
168
+
169
+ - `project.requires-python`
170
+ - Python version classifiers (other classifiers are untouched)
171
+ - One `[tool.X]` table per enabled tool (fully owned; hand edits inside are overwritten)
172
+ - `[tool.pyprojkit].managed`: bookkeeping list of owned tables, so a tool dropped from your configuration gets its table cleanly removed on the next sync
173
+
174
+ Everything else — dependencies, `[tool.uv.sources]`, build system, unmanaged tool tables — is preserved. Output is normalized with toml-sort using the same settings as the managed `[tool.tomlsort]` table, so syncing and formatting never fight.
175
+
176
+ ### Check mode
177
+
178
+ Verify a project is in sync without writing (e.g. in CI):
179
+
180
+ ```bash
181
+ pyprojkit sync --check
182
+ ```
183
+
184
+ Prints a diff and exits nonzero if `pyproject.toml` is out of date.
185
+
186
+ ## doit tasks
187
+
188
+ `TaskFactory` creates `doit` tasks pre-wired to the configuration. Create them selectively:
189
+
190
+ ```python
191
+ from pyprojkit import TaskFactory
192
+
193
+ factory = TaskFactory()
194
+
195
+ task_sync = factory.create_sync_task()
196
+ task_format = factory.create_format_task()
197
+ task_test = factory.create_test_task()
198
+ task_badges = factory.create_badges_task()
199
+ task_publish = factory.create_publish_task()
200
+ ```
201
+
202
+ or all at once: `globals().update(factory.create_all_tasks())`, which creates every task enabled by the configuration.
203
+
204
+ | Task | Description |
205
+ | --- | --- |
206
+ | `sync` | Update `pyproject.toml` from `pyprojconf.py` |
207
+ | `format` | Run the configured formatter chain over the project |
208
+ | `test` | Run pytest with coverage (HTML + XML) and JUnit output |
209
+ | `badges` | Generate test/coverage badges via genbadge |
210
+ | `publish` | Build and publish via uv (output dir is cleaned first, so stale artifacts are never published) |
211
+ | `init` | Generate `__init__.py` files via mkinit (enabled by default) |
212
+ | `doc` | Build documentation via sphinx; `--copy` deploys to a directory given by an env var (opt-in) |
213
+ | `analysis` | Run mypy (with HTML/cobertura reports) and pyright (opt-in) |
214
+
215
+ The `format` task passes an explicit list of paths to each formatter — root `*.py`/`*.toml` files plus the configured `format_paths` directories that exist (`src`, `test`, `doc`, `examples` by default) — so formatters never wander into `.venv` or other unrelated trees.
216
+
217
+ ## nox sessions
218
+
219
+ `NoxFactory.create_test_session()` registers a `test` session which, for each pinned interpreter, syncs the project's dev dependency group via uv into the session environment and runs pytest:
220
+
221
+ ```bash
222
+ $ nox -l
223
+ * test-3.12.13
224
+ * test-3.13.13
225
+ * test-3.14.6
226
+ ```
227
+
228
+ Extra arguments pass through to pytest: `nox -s test-3.12.13 -- -k my_test`.
229
+
230
+ ## Path conventions
231
+
232
+ All tasks share the same layout:
233
+
234
+ - `__cache__/`: caches (doit db, pytest cache, coverage data, nox envs)
235
+ - `__out__/`: generated artifacts (`test/` coverage + JUnit results, `doc/html`, `analysis/`, `uv/` build artifacts)
236
+ - `badges/`: generated badge SVGs
237
+
238
+ ## Custom profiles
239
+
240
+ A profile is a named factory for a pre-canned configuration, at two levels: the overall tools profile and the formatting profile it contains. The `"default"` profiles ship with PyProjKit; register your own once and reuse it across projects:
241
+
242
+ ```python
243
+ # in your shared module, e.g. mycompany_profiles.py
244
+ from dataclasses import replace
245
+
246
+ from pyprojkit import AnalysisConfig, ToolsConfig, register_tools_profile
247
+
248
+ register_tools_profile(
249
+ "mycompany",
250
+ lambda: replace(ToolsConfig.default(), analysis=AnalysisConfig()),
251
+ )
252
+ ```
253
+
254
+ ```python
255
+ # in each project's pyprojconf.py
256
+ import mycompany_profiles # noqa: F401 -- registers the profile
257
+
258
+ from pyprojkit import ProjectConfig, PythonVersions, get_tools_profile
259
+
260
+ config = ProjectConfig(
261
+ package="my_package",
262
+ python=PythonVersions(3, (12, 14)),
263
+ tools=get_tools_profile("mycompany"),
264
+ )
265
+ ```
266
+
267
+ New formatters are equally pluggable: subclass `BaseFormatterConfig` (declaring the tool's `[tool.X]` table and command line) and include it in a `FormattingConfig` — the sync engine and format task pick it up automatically.