prodkit 0.2.0__tar.gz → 0.2.1__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.
- {prodkit-0.2.0 → prodkit-0.2.1}/CHANGELOG.md +7 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/PKG-INFO +34 -10
- {prodkit-0.2.0 → prodkit-0.2.1}/README.md +33 -9
- {prodkit-0.2.0 → prodkit-0.2.1}/pyproject.toml +1 -1
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/__init__.py +1 -1
- {prodkit-0.2.0 → prodkit-0.2.1}/.gitignore +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/LICENSE +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/cli/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/cli/app.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/cli/loader.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/contracts/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/contracts/plugin.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/config.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/context.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/doctor.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/event_bus.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/exceptions.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/lifecycle.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/plugin_manager.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/production.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/core/registry.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/plugins/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/plugins/compression/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/plugins/cors/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/plugins/errors/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/plugins/health/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/plugins/logging/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/plugins/rate_limit/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/plugins/request_id/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/plugins/security/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/src/prodkit/py.typed +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/conftest.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/integration/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/integration/test_cli.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/integration/test_logging.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/integration/test_production.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/unit/__init__.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/unit/test_config.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/unit/test_doctor.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/unit/test_kernel.py +0 -0
- {prodkit-0.2.0 → prodkit-0.2.1}/tests/unit/test_rate_limit.py +0 -0
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.1] - 2026-07-23
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- README polish: PyPI/Python badges, table of contents, `prodkit[cli]` install
|
|
14
|
+
note, rate-limiting shown in the config examples, and a `doctor()` hook in the
|
|
15
|
+
plugin-authoring example. Docs-only release (no code changes).
|
|
16
|
+
|
|
10
17
|
## [0.2.0] - 2026-07-22
|
|
11
18
|
|
|
12
19
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: prodkit
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: The production framework for FastAPI. One line. Production ready.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Pushkarpant/PRODKIT
|
|
6
6
|
Project-URL: Documentation, https://github.com/Pushkarpant/PRODKIT#readme
|
|
@@ -61,14 +61,24 @@ Production(app)
|
|
|
61
61
|
|
|
62
62
|
That's it. Your app now has security headers, structured JSON logging with
|
|
63
63
|
request-ID correlation, RFC 9457 error responses, Kubernetes-ready health
|
|
64
|
-
endpoints,
|
|
65
|
-
hardened for production, and pleasant in development.
|
|
64
|
+
endpoints, gzip compression, and opt-in rate limiting — configured to current
|
|
65
|
+
best practice, hardened for production, and pleasant in development. Then run
|
|
66
|
+
[`prodkit doctor`](#cli--prodkit-doctor) to score how production-ready it is.
|
|
66
67
|
|
|
68
|
+
[](https://pypi.org/project/prodkit/)
|
|
69
|
+
[](https://pypi.org/project/prodkit/)
|
|
67
70
|
[](https://github.com/Pushkarpant/PRODKIT/actions/workflows/ci.yml)
|
|
68
71
|
[](https://github.com/Pushkarpant/PRODKIT/blob/main/LICENSE)
|
|
69
72
|
|
|
70
73
|
---
|
|
71
74
|
|
|
75
|
+
**Contents:** [Why](#why) · [Install](#installation) · [Quick Start](#quick-start) ·
|
|
76
|
+
[What You Get](#what-you-get) · [Configuration](#configuration) ·
|
|
77
|
+
[Plugins](#writing-a-plugin) · [CLI / doctor](#cli--prodkit-doctor) ·
|
|
78
|
+
[Status & Roadmap](#project-status)
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
72
82
|
## Why
|
|
73
83
|
|
|
74
84
|
Every production FastAPI service re-implements the same ~500 lines of glue:
|
|
@@ -84,11 +94,13 @@ evolve, `pip install -U prodkit` updates every app you own.
|
|
|
84
94
|
[**`pip install prodkit`**](https://pypi.org/project/prodkit/)
|
|
85
95
|
|
|
86
96
|
```bash
|
|
87
|
-
pip install prodkit
|
|
97
|
+
pip install prodkit # the library
|
|
98
|
+
pip install "prodkit[cli]" # + the `prodkit doctor` CLI (typer + rich)
|
|
88
99
|
```
|
|
89
100
|
|
|
90
101
|
Requires Python 3.10+ and FastAPI 0.110+. The base install depends only on
|
|
91
|
-
FastAPI and Pydantic — nothing else.
|
|
102
|
+
FastAPI and Pydantic — nothing else. Optional extras: `cli` (CLI),
|
|
103
|
+
`brotli` (Brotli compression).
|
|
92
104
|
|
|
93
105
|
## Quick Start
|
|
94
106
|
|
|
@@ -116,7 +128,9 @@ x-content-type-options: nosniff
|
|
|
116
128
|
x-frame-options: DENY
|
|
117
129
|
strict-transport-security: max-age=63072000; includeSubDomains
|
|
118
130
|
referrer-policy: strict-origin-when-cross-origin
|
|
119
|
-
|
|
131
|
+
permissions-policy: camera=(), microphone=(), geolocation=()
|
|
132
|
+
x-xss-protection: 0
|
|
133
|
+
content-type: application/json
|
|
120
134
|
```
|
|
121
135
|
|
|
122
136
|
For local development, flip the profile — pretty console logs, debug error
|
|
@@ -158,6 +172,7 @@ Production(
|
|
|
158
172
|
cors={"origins": ["https://app.example.com"]}, # dict = configure & enable
|
|
159
173
|
compression=False, # bool = toggle
|
|
160
174
|
security={"trusted_hosts": ["api.example.com"]},
|
|
175
|
+
rate_limit={"default": "100/minute"}, # opt-in per-IP limiting
|
|
161
176
|
)
|
|
162
177
|
```
|
|
163
178
|
|
|
@@ -181,6 +196,10 @@ level = "INFO"
|
|
|
181
196
|
[cors]
|
|
182
197
|
enabled = true
|
|
183
198
|
origins = ["https://app.example.com"]
|
|
199
|
+
|
|
200
|
+
[rate_limit]
|
|
201
|
+
enabled = true
|
|
202
|
+
default = "100/minute"
|
|
184
203
|
```
|
|
185
204
|
|
|
186
205
|
### Fail-fast, refuse-unsafe
|
|
@@ -202,7 +221,7 @@ not warned about:
|
|
|
202
221
|
## Writing a Plugin
|
|
203
222
|
|
|
204
223
|
```python
|
|
205
|
-
from prodkit import Check, Plugin, Production
|
|
224
|
+
from prodkit import Audit, Check, Plugin, Production
|
|
206
225
|
|
|
207
226
|
class DatabasePlugin(Plugin):
|
|
208
227
|
name = "database"
|
|
@@ -214,13 +233,18 @@ class DatabasePlugin(Plugin):
|
|
|
214
233
|
async def shutdown(self, ctx):
|
|
215
234
|
await self.pool.close()
|
|
216
235
|
|
|
217
|
-
def checks(self, ctx):
|
|
236
|
+
def checks(self, ctx): # runtime readiness → /ready
|
|
218
237
|
return [Check(name="database", passed=self.pool.is_alive())]
|
|
219
238
|
|
|
239
|
+
def doctor(self, ctx): # static audit → prodkit doctor
|
|
240
|
+
return [Audit(name="Database pool",
|
|
241
|
+
status="ok", detail="connection pool configured")]
|
|
242
|
+
|
|
220
243
|
Production(app, plugins=[DatabasePlugin()])
|
|
221
244
|
```
|
|
222
245
|
|
|
223
|
-
Your
|
|
246
|
+
Your `checks()` result now shows up in `/ready` automatically, and your
|
|
247
|
+
`doctor()` findings roll into the `prodkit doctor` score. Plugins can declare
|
|
224
248
|
`requires = ("other-plugin",)` and the kernel activates them in dependency
|
|
225
249
|
order — cycles and missing dependencies fail at boot.
|
|
226
250
|
|
|
@@ -277,7 +301,7 @@ plugins score too.
|
|
|
277
301
|
|
|
278
302
|
## Project Status
|
|
279
303
|
|
|
280
|
-
**v0.2.
|
|
304
|
+
**v0.2.1 — alpha.** Core kernel, eight built-in plugins (incl. rate-limiting),
|
|
281
305
|
the `prodkit doctor` CLI with a production-readiness score, strict mypy, CI
|
|
282
306
|
across Python 3.10–3.13.
|
|
283
307
|
|
|
@@ -14,14 +14,24 @@ Production(app)
|
|
|
14
14
|
|
|
15
15
|
That's it. Your app now has security headers, structured JSON logging with
|
|
16
16
|
request-ID correlation, RFC 9457 error responses, Kubernetes-ready health
|
|
17
|
-
endpoints,
|
|
18
|
-
hardened for production, and pleasant in development.
|
|
17
|
+
endpoints, gzip compression, and opt-in rate limiting — configured to current
|
|
18
|
+
best practice, hardened for production, and pleasant in development. Then run
|
|
19
|
+
[`prodkit doctor`](#cli--prodkit-doctor) to score how production-ready it is.
|
|
19
20
|
|
|
21
|
+
[](https://pypi.org/project/prodkit/)
|
|
22
|
+
[](https://pypi.org/project/prodkit/)
|
|
20
23
|
[](https://github.com/Pushkarpant/PRODKIT/actions/workflows/ci.yml)
|
|
21
24
|
[](https://github.com/Pushkarpant/PRODKIT/blob/main/LICENSE)
|
|
22
25
|
|
|
23
26
|
---
|
|
24
27
|
|
|
28
|
+
**Contents:** [Why](#why) · [Install](#installation) · [Quick Start](#quick-start) ·
|
|
29
|
+
[What You Get](#what-you-get) · [Configuration](#configuration) ·
|
|
30
|
+
[Plugins](#writing-a-plugin) · [CLI / doctor](#cli--prodkit-doctor) ·
|
|
31
|
+
[Status & Roadmap](#project-status)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
25
35
|
## Why
|
|
26
36
|
|
|
27
37
|
Every production FastAPI service re-implements the same ~500 lines of glue:
|
|
@@ -37,11 +47,13 @@ evolve, `pip install -U prodkit` updates every app you own.
|
|
|
37
47
|
[**`pip install prodkit`**](https://pypi.org/project/prodkit/)
|
|
38
48
|
|
|
39
49
|
```bash
|
|
40
|
-
pip install prodkit
|
|
50
|
+
pip install prodkit # the library
|
|
51
|
+
pip install "prodkit[cli]" # + the `prodkit doctor` CLI (typer + rich)
|
|
41
52
|
```
|
|
42
53
|
|
|
43
54
|
Requires Python 3.10+ and FastAPI 0.110+. The base install depends only on
|
|
44
|
-
FastAPI and Pydantic — nothing else.
|
|
55
|
+
FastAPI and Pydantic — nothing else. Optional extras: `cli` (CLI),
|
|
56
|
+
`brotli` (Brotli compression).
|
|
45
57
|
|
|
46
58
|
## Quick Start
|
|
47
59
|
|
|
@@ -69,7 +81,9 @@ x-content-type-options: nosniff
|
|
|
69
81
|
x-frame-options: DENY
|
|
70
82
|
strict-transport-security: max-age=63072000; includeSubDomains
|
|
71
83
|
referrer-policy: strict-origin-when-cross-origin
|
|
72
|
-
|
|
84
|
+
permissions-policy: camera=(), microphone=(), geolocation=()
|
|
85
|
+
x-xss-protection: 0
|
|
86
|
+
content-type: application/json
|
|
73
87
|
```
|
|
74
88
|
|
|
75
89
|
For local development, flip the profile — pretty console logs, debug error
|
|
@@ -111,6 +125,7 @@ Production(
|
|
|
111
125
|
cors={"origins": ["https://app.example.com"]}, # dict = configure & enable
|
|
112
126
|
compression=False, # bool = toggle
|
|
113
127
|
security={"trusted_hosts": ["api.example.com"]},
|
|
128
|
+
rate_limit={"default": "100/minute"}, # opt-in per-IP limiting
|
|
114
129
|
)
|
|
115
130
|
```
|
|
116
131
|
|
|
@@ -134,6 +149,10 @@ level = "INFO"
|
|
|
134
149
|
[cors]
|
|
135
150
|
enabled = true
|
|
136
151
|
origins = ["https://app.example.com"]
|
|
152
|
+
|
|
153
|
+
[rate_limit]
|
|
154
|
+
enabled = true
|
|
155
|
+
default = "100/minute"
|
|
137
156
|
```
|
|
138
157
|
|
|
139
158
|
### Fail-fast, refuse-unsafe
|
|
@@ -155,7 +174,7 @@ not warned about:
|
|
|
155
174
|
## Writing a Plugin
|
|
156
175
|
|
|
157
176
|
```python
|
|
158
|
-
from prodkit import Check, Plugin, Production
|
|
177
|
+
from prodkit import Audit, Check, Plugin, Production
|
|
159
178
|
|
|
160
179
|
class DatabasePlugin(Plugin):
|
|
161
180
|
name = "database"
|
|
@@ -167,13 +186,18 @@ class DatabasePlugin(Plugin):
|
|
|
167
186
|
async def shutdown(self, ctx):
|
|
168
187
|
await self.pool.close()
|
|
169
188
|
|
|
170
|
-
def checks(self, ctx):
|
|
189
|
+
def checks(self, ctx): # runtime readiness → /ready
|
|
171
190
|
return [Check(name="database", passed=self.pool.is_alive())]
|
|
172
191
|
|
|
192
|
+
def doctor(self, ctx): # static audit → prodkit doctor
|
|
193
|
+
return [Audit(name="Database pool",
|
|
194
|
+
status="ok", detail="connection pool configured")]
|
|
195
|
+
|
|
173
196
|
Production(app, plugins=[DatabasePlugin()])
|
|
174
197
|
```
|
|
175
198
|
|
|
176
|
-
Your
|
|
199
|
+
Your `checks()` result now shows up in `/ready` automatically, and your
|
|
200
|
+
`doctor()` findings roll into the `prodkit doctor` score. Plugins can declare
|
|
177
201
|
`requires = ("other-plugin",)` and the kernel activates them in dependency
|
|
178
202
|
order — cycles and missing dependencies fail at boot.
|
|
179
203
|
|
|
@@ -230,7 +254,7 @@ plugins score too.
|
|
|
230
254
|
|
|
231
255
|
## Project Status
|
|
232
256
|
|
|
233
|
-
**v0.2.
|
|
257
|
+
**v0.2.1 — alpha.** Core kernel, eight built-in plugins (incl. rate-limiting),
|
|
234
258
|
the `prodkit doctor` CLI with a production-readiness score, strict mypy, CI
|
|
235
259
|
across Python 3.10–3.13.
|
|
236
260
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|