plain 0.66.0__py3-none-any.whl → 0.101.2__py3-none-any.whl

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.
Files changed (197) hide show
  1. plain/CHANGELOG.md +684 -0
  2. plain/README.md +1 -1
  3. plain/assets/compile.py +25 -12
  4. plain/assets/finders.py +24 -17
  5. plain/assets/fingerprints.py +10 -7
  6. plain/assets/urls.py +1 -1
  7. plain/assets/views.py +47 -33
  8. plain/chores/README.md +25 -23
  9. plain/chores/__init__.py +2 -1
  10. plain/chores/core.py +27 -0
  11. plain/chores/registry.py +23 -53
  12. plain/cli/README.md +185 -16
  13. plain/cli/__init__.py +2 -1
  14. plain/cli/agent.py +236 -0
  15. plain/cli/build.py +7 -8
  16. plain/cli/changelog.py +11 -5
  17. plain/cli/chores.py +32 -34
  18. plain/cli/core.py +112 -28
  19. plain/cli/docs.py +52 -11
  20. plain/cli/formatting.py +40 -17
  21. plain/cli/install.py +10 -54
  22. plain/cli/{agent/llmdocs.py → llmdocs.py} +21 -9
  23. plain/cli/output.py +6 -2
  24. plain/cli/preflight.py +175 -102
  25. plain/cli/print.py +4 -4
  26. plain/cli/registry.py +95 -26
  27. plain/cli/request.py +206 -0
  28. plain/cli/runtime.py +45 -0
  29. plain/cli/scaffold.py +2 -7
  30. plain/cli/server.py +153 -0
  31. plain/cli/settings.py +53 -49
  32. plain/cli/shell.py +15 -12
  33. plain/cli/startup.py +9 -8
  34. plain/cli/upgrade.py +17 -104
  35. plain/cli/urls.py +12 -7
  36. plain/cli/utils.py +3 -3
  37. plain/csrf/README.md +65 -40
  38. plain/csrf/middleware.py +53 -43
  39. plain/debug.py +5 -2
  40. plain/exceptions.py +22 -114
  41. plain/forms/README.md +453 -24
  42. plain/forms/__init__.py +55 -4
  43. plain/forms/boundfield.py +15 -8
  44. plain/forms/exceptions.py +1 -1
  45. plain/forms/fields.py +346 -143
  46. plain/forms/forms.py +75 -45
  47. plain/http/README.md +356 -9
  48. plain/http/__init__.py +41 -26
  49. plain/http/cookie.py +15 -7
  50. plain/http/exceptions.py +65 -0
  51. plain/http/middleware.py +32 -0
  52. plain/http/multipartparser.py +99 -88
  53. plain/http/request.py +362 -250
  54. plain/http/response.py +99 -197
  55. plain/internal/__init__.py +8 -1
  56. plain/internal/files/base.py +35 -19
  57. plain/internal/files/locks.py +19 -11
  58. plain/internal/files/move.py +8 -3
  59. plain/internal/files/temp.py +25 -6
  60. plain/internal/files/uploadedfile.py +47 -28
  61. plain/internal/files/uploadhandler.py +64 -58
  62. plain/internal/files/utils.py +24 -10
  63. plain/internal/handlers/base.py +34 -23
  64. plain/internal/handlers/exception.py +68 -65
  65. plain/internal/handlers/wsgi.py +65 -54
  66. plain/internal/middleware/headers.py +37 -11
  67. plain/internal/middleware/hosts.py +11 -13
  68. plain/internal/middleware/https.py +17 -7
  69. plain/internal/middleware/slash.py +14 -9
  70. plain/internal/reloader.py +77 -0
  71. plain/json.py +2 -1
  72. plain/logs/README.md +161 -62
  73. plain/logs/__init__.py +1 -1
  74. plain/logs/{loggers.py → app.py} +71 -67
  75. plain/logs/configure.py +63 -14
  76. plain/logs/debug.py +17 -6
  77. plain/logs/filters.py +15 -0
  78. plain/logs/formatters.py +7 -4
  79. plain/packages/README.md +105 -23
  80. plain/packages/config.py +15 -7
  81. plain/packages/registry.py +40 -15
  82. plain/paginator.py +31 -21
  83. plain/preflight/README.md +208 -23
  84. plain/preflight/__init__.py +5 -24
  85. plain/preflight/checks.py +12 -0
  86. plain/preflight/files.py +19 -13
  87. plain/preflight/registry.py +80 -58
  88. plain/preflight/results.py +37 -0
  89. plain/preflight/security.py +65 -71
  90. plain/preflight/settings.py +54 -0
  91. plain/preflight/urls.py +10 -48
  92. plain/runtime/README.md +115 -47
  93. plain/runtime/__init__.py +10 -6
  94. plain/runtime/global_settings.py +43 -33
  95. plain/runtime/secret.py +20 -0
  96. plain/runtime/user_settings.py +110 -38
  97. plain/runtime/utils.py +1 -1
  98. plain/server/LICENSE +35 -0
  99. plain/server/README.md +155 -0
  100. plain/server/__init__.py +9 -0
  101. plain/server/app.py +52 -0
  102. plain/server/arbiter.py +555 -0
  103. plain/server/config.py +118 -0
  104. plain/server/errors.py +31 -0
  105. plain/server/glogging.py +292 -0
  106. plain/server/http/__init__.py +12 -0
  107. plain/server/http/body.py +283 -0
  108. plain/server/http/errors.py +155 -0
  109. plain/server/http/message.py +400 -0
  110. plain/server/http/parser.py +70 -0
  111. plain/server/http/unreader.py +88 -0
  112. plain/server/http/wsgi.py +421 -0
  113. plain/server/pidfile.py +92 -0
  114. plain/server/sock.py +240 -0
  115. plain/server/util.py +317 -0
  116. plain/server/workers/__init__.py +6 -0
  117. plain/server/workers/base.py +304 -0
  118. plain/server/workers/sync.py +212 -0
  119. plain/server/workers/thread.py +399 -0
  120. plain/server/workers/workertmp.py +50 -0
  121. plain/signals/README.md +170 -1
  122. plain/signals/__init__.py +0 -1
  123. plain/signals/dispatch/dispatcher.py +49 -27
  124. plain/signing.py +131 -35
  125. plain/skills/README.md +36 -0
  126. plain/skills/plain-docs/SKILL.md +25 -0
  127. plain/skills/plain-install/SKILL.md +26 -0
  128. plain/skills/plain-request/SKILL.md +39 -0
  129. plain/skills/plain-shell/SKILL.md +24 -0
  130. plain/skills/plain-upgrade/SKILL.md +35 -0
  131. plain/templates/README.md +211 -20
  132. plain/templates/jinja/__init__.py +14 -27
  133. plain/templates/jinja/environments.py +5 -4
  134. plain/templates/jinja/extensions.py +12 -5
  135. plain/templates/jinja/filters.py +7 -2
  136. plain/templates/jinja/globals.py +2 -2
  137. plain/test/README.md +184 -22
  138. plain/test/client.py +340 -222
  139. plain/test/encoding.py +9 -6
  140. plain/test/exceptions.py +7 -2
  141. plain/urls/README.md +157 -73
  142. plain/urls/converters.py +18 -15
  143. plain/urls/exceptions.py +2 -2
  144. plain/urls/patterns.py +56 -40
  145. plain/urls/resolvers.py +38 -28
  146. plain/urls/utils.py +5 -1
  147. plain/utils/README.md +250 -3
  148. plain/utils/cache.py +17 -11
  149. plain/utils/crypto.py +21 -5
  150. plain/utils/datastructures.py +89 -56
  151. plain/utils/dateparse.py +9 -6
  152. plain/utils/deconstruct.py +15 -7
  153. plain/utils/decorators.py +5 -1
  154. plain/utils/dotenv.py +373 -0
  155. plain/utils/duration.py +8 -4
  156. plain/utils/encoding.py +14 -7
  157. plain/utils/functional.py +66 -49
  158. plain/utils/hashable.py +5 -1
  159. plain/utils/html.py +36 -22
  160. plain/utils/http.py +16 -9
  161. plain/utils/inspect.py +14 -6
  162. plain/utils/ipv6.py +7 -3
  163. plain/utils/itercompat.py +6 -1
  164. plain/utils/module_loading.py +7 -3
  165. plain/utils/regex_helper.py +37 -23
  166. plain/utils/safestring.py +14 -6
  167. plain/utils/text.py +41 -23
  168. plain/utils/timezone.py +33 -22
  169. plain/utils/tree.py +35 -19
  170. plain/validators.py +94 -52
  171. plain/views/README.md +156 -79
  172. plain/views/__init__.py +0 -1
  173. plain/views/base.py +25 -18
  174. plain/views/errors.py +13 -5
  175. plain/views/exceptions.py +4 -1
  176. plain/views/forms.py +6 -6
  177. plain/views/objects.py +52 -49
  178. plain/views/redirect.py +18 -15
  179. plain/views/templates.py +5 -3
  180. plain/wsgi.py +3 -1
  181. {plain-0.66.0.dist-info → plain-0.101.2.dist-info}/METADATA +4 -2
  182. plain-0.101.2.dist-info/RECORD +201 -0
  183. {plain-0.66.0.dist-info → plain-0.101.2.dist-info}/WHEEL +1 -1
  184. plain-0.101.2.dist-info/entry_points.txt +2 -0
  185. plain/AGENTS.md +0 -18
  186. plain/cli/agent/__init__.py +0 -20
  187. plain/cli/agent/docs.py +0 -80
  188. plain/cli/agent/md.py +0 -87
  189. plain/cli/agent/prompt.py +0 -45
  190. plain/cli/agent/request.py +0 -181
  191. plain/csrf/views.py +0 -31
  192. plain/logs/utils.py +0 -46
  193. plain/preflight/messages.py +0 -81
  194. plain/templates/AGENTS.md +0 -3
  195. plain-0.66.0.dist-info/RECORD +0 -168
  196. plain-0.66.0.dist-info/entry_points.txt +0 -4
  197. {plain-0.66.0.dist-info → plain-0.101.2.dist-info}/licenses/LICENSE +0 -0
plain/CHANGELOG.md CHANGED
@@ -1,5 +1,689 @@
1
1
  # plain changelog
2
2
 
3
+ ## [0.101.2](https://github.com/dropseed/plain/releases/plain@0.101.2) (2026-01-28)
4
+
5
+ ### What's changed
6
+
7
+ - When `load_dotenv()` is called with `override=False` (the default), command substitution is now skipped for keys that already exist in `os.environ`. This prevents redundant command execution in child processes that re-load the `.env` file after inheriting resolved values from the parent, avoiding multiple auth prompts with tools like the 1Password CLI ([2f6ff93499](https://github.com/dropseed/plain/commit/2f6ff93499))
8
+ - The `_execute_command` helper now uses `stdout=subprocess.PIPE` instead of `capture_output=True`, allowing stderr/tty to pass through for interactive prompts ([2f6ff93499](https://github.com/dropseed/plain/commit/2f6ff93499))
9
+ - Updated templates README examples to use `id` instead of `pk` ([837d345d23](https://github.com/dropseed/plain/commit/837d345d23))
10
+ - Added Settings section to README ([803fee1ad5](https://github.com/dropseed/plain/commit/803fee1ad5))
11
+
12
+ ### Upgrade instructions
13
+
14
+ - No changes required.
15
+
16
+ ## [0.101.1](https://github.com/dropseed/plain/releases/plain@0.101.1) (2026-01-17)
17
+
18
+ ### What's changed
19
+
20
+ - Fixed a crash when running the development server with `--reload` when an app's `assets` directory doesn't exist ([df33f93ece](https://github.com/dropseed/plain/commit/df33f93ece))
21
+ - The `plain agent install` command now preserves user-created skills (those without the `plain-` prefix) instead of removing them as orphans ([bbc87498ed](https://github.com/dropseed/plain/commit/bbc87498ed))
22
+
23
+ ### Upgrade instructions
24
+
25
+ - No changes required.
26
+
27
+ ## [0.101.0](https://github.com/dropseed/plain/releases/plain@0.101.0) (2026-01-15)
28
+
29
+ ### What's changed
30
+
31
+ - The `plain server` command now accepts `--workers auto` (or `WEB_CONCURRENCY=auto`) to automatically set worker count based on CPU count ([02a1769948](https://github.com/dropseed/plain/commit/02a1769948))
32
+ - Response headers can now be set to `None` to opt out of default headers; `None` values are filtered out at the WSGI layer rather than being deleted by middleware ([cbf27e728d](https://github.com/dropseed/plain/commit/cbf27e728d))
33
+ - Removed unused `Response` methods: `serialize_headers`, `serialize`, file-like interface stubs (`write`, `flush`, `tell`, `readable`, `seekable`, `writable`, `writelines`), `text` property, pickling support, and `getvalue` ([cbf27e728d](https://github.com/dropseed/plain/commit/cbf27e728d))
34
+
35
+ ### Upgrade instructions
36
+
37
+ - No changes required
38
+
39
+ ## [0.100.1](https://github.com/dropseed/plain/releases/plain@0.100.1) (2026-01-15)
40
+
41
+ ### What's changed
42
+
43
+ - The `plain agent install` command now only sets up session hooks for Claude Code, not Codex, since the `settings.json` hook format is Claude Code-specific ([a41e08bcd2](https://github.com/dropseed/plain/commit/a41e08bcd2))
44
+
45
+ ### Upgrade instructions
46
+
47
+ - No changes required
48
+
49
+ ## [0.100.0](https://github.com/dropseed/plain/releases/plain@0.100.0) (2026-01-15)
50
+
51
+ ### What's changed
52
+
53
+ - The `plain skills` command has been renamed to `plain agent` with new subcommands: `plain agent install` (installs skills and sets up hooks), `plain agent skills` (lists available skills), and `plain agent context` (outputs framework context) ([fac8673436](https://github.com/dropseed/plain/commit/fac8673436))
54
+ - Added `SessionStart` hook that automatically runs `plain agent context` at the start of every Claude Code or Codex session, providing framework context without needing a separate skill ([fac8673436](https://github.com/dropseed/plain/commit/fac8673436))
55
+ - The `plain-principles` skill has been removed - its content is now provided by the `plain agent context` command via the SessionStart hook ([fac8673436](https://github.com/dropseed/plain/commit/fac8673436))
56
+ - Added `--no-headers` and `--no-body` flags to `plain request` for limiting output ([fac8673436](https://github.com/dropseed/plain/commit/fac8673436))
57
+
58
+ ### Upgrade instructions
59
+
60
+ - Replace `plain skills --install` with `plain agent install`
61
+ - Replace `plain skills` (without flags) with `plain agent skills`
62
+ - Run `plain agent install` to set up the new SessionStart hook in your project's `.claude/` or `.codex/` directory
63
+
64
+ ## [0.99.0](https://github.com/dropseed/plain/releases/plain@0.99.0) (2026-01-15)
65
+
66
+ ### What's changed
67
+
68
+ - Added `plain.utils.dotenv` module with `load_dotenv()` and `parse_dotenv()` functions for bash-compatible `.env` file parsing, supporting variable expansion, command substitution, multiline values, and escape sequences ([a9b2dc3e16](https://github.com/dropseed/plain/commit/a9b2dc3e16))
69
+
70
+ ### Upgrade instructions
71
+
72
+ - No changes required
73
+
74
+ ## [0.98.1](https://github.com/dropseed/plain/releases/plain@0.98.1) (2026-01-13)
75
+
76
+ ### What's changed
77
+
78
+ - Fixed `INSTALLED_PACKAGES` not being optional in user settings, restoring the default empty list behavior ([820773c473](https://github.com/dropseed/plain/commit/820773c473))
79
+
80
+ ### Upgrade instructions
81
+
82
+ - No changes required
83
+
84
+ ## [0.98.0](https://github.com/dropseed/plain/releases/plain@0.98.0) (2026-01-13)
85
+
86
+ ### What's changed
87
+
88
+ - The `plain skills --install` command now removes orphaned skills from destination directories when skills are renamed or removed from packages ([d51294ace1](https://github.com/dropseed/plain/commit/d51294ace1))
89
+ - Added README documentation for `plain.skills` with available skills and installation instructions ([7c90fc8595](https://github.com/dropseed/plain/commit/7c90fc8595))
90
+
91
+ ### Upgrade instructions
92
+
93
+ - No changes required
94
+
95
+ ## [0.97.0](https://github.com/dropseed/plain/releases/plain@0.97.0) (2026-01-13)
96
+
97
+ ### What's changed
98
+
99
+ - HTTP exceptions (`NotFoundError404`, `ForbiddenError403`, `BadRequestError400`, and `SuspiciousOperationError400` variants) moved from `plain.exceptions` to `plain.http.exceptions` and are now exported from `plain.http` ([b61f909e29](https://github.com/dropseed/plain/commit/b61f909e29))
100
+
101
+ ### Upgrade instructions
102
+
103
+ - Update imports of HTTP exceptions from `plain.exceptions` to `plain.http`:
104
+
105
+ ```python
106
+ # Before
107
+ from plain.exceptions import NotFoundError404, ForbiddenError403, BadRequestError400
108
+
109
+ # After
110
+ from plain.http import NotFoundError404, ForbiddenError403, BadRequestError400
111
+ ```
112
+
113
+ ## [0.96.0](https://github.com/dropseed/plain/releases/plain@0.96.0) (2026-01-13)
114
+
115
+ ### What's changed
116
+
117
+ - Response classes renamed for consistency: `ResponseRedirect` → `RedirectResponse`, `ResponseNotModified` → `NotModifiedResponse`, `ResponseNotAllowed` → `NotAllowedResponse` ([fad5bf28b0](https://github.com/dropseed/plain/commit/fad5bf28b0))
118
+ - Redundant response classes removed: `ResponseNotFound`, `ResponseForbidden`, `ResponseBadRequest`, `ResponseGone`, `ResponseServerError` - use `Response(status_code=X)` instead ([fad5bf28b0](https://github.com/dropseed/plain/commit/fad5bf28b0))
119
+ - HTTP exceptions renamed to include status code suffix: `Http404` → `NotFoundError404`, `PermissionDenied` → `ForbiddenError403`, `BadRequest` → `BadRequestError400`, `SuspiciousOperation` → `SuspiciousOperationError400` ([5a1f020f52](https://github.com/dropseed/plain/commit/5a1f020f52))
120
+ - Added `Secret[T]` type annotation for masking sensitive settings like `SECRET_KEY` in CLI output ([8713dc08b0](https://github.com/dropseed/plain/commit/8713dc08b0))
121
+ - Added `ENV_SETTINGS_PREFIXES` setting to configure which environment variable prefixes are checked for settings (defaults to `["PLAIN_"]`) ([8713dc08b0](https://github.com/dropseed/plain/commit/8713dc08b0))
122
+ - New `plain settings list` and `plain settings get` CLI commands for viewing settings with their sources ([8713dc08b0](https://github.com/dropseed/plain/commit/8713dc08b0))
123
+ - Added preflight check for unused environment variables matching configured prefixes ([8713dc08b0](https://github.com/dropseed/plain/commit/8713dc08b0))
124
+ - Renamed `request.meta` to `request.environ` for clarity ([786b95bef8](https://github.com/dropseed/plain/commit/786b95bef8))
125
+ - Added `request.query_string` and `request.content_length` properties ([786b95bef8](https://github.com/dropseed/plain/commit/786b95bef8), [76dfd477d2](https://github.com/dropseed/plain/commit/76dfd477d2))
126
+ - Renamed X-Forwarded settings: `USE_X_FORWARDED_HOST` → `HTTP_X_FORWARDED_HOST`, `USE_X_FORWARDED_PORT` → `HTTP_X_FORWARDED_PORT`, `USE_X_FORWARDED_FOR` → `HTTP_X_FORWARDED_FOR` ([22f241a55c](https://github.com/dropseed/plain/commit/22f241a55c))
127
+ - Changed `HTTPS_PROXY_HEADER` from a tuple to a string format (e.g., `"X-Forwarded-Proto: https"`) ([7ac2a431b6](https://github.com/dropseed/plain/commit/7ac2a431b6))
128
+
129
+ ### Upgrade instructions
130
+
131
+ - Replace Response class imports and usages:
132
+ - `ResponseRedirect` → `RedirectResponse`
133
+ - `ResponseNotModified` → `NotModifiedResponse`
134
+ - `ResponseNotAllowed` → `NotAllowedResponse`
135
+ - `ResponseNotFound` → `Response(status_code=404)`
136
+ - `ResponseForbidden` → `Response(status_code=403)`
137
+ - `ResponseBadRequest` → `Response(status_code=400)`
138
+ - `ResponseGone` → `Response(status_code=410)`
139
+ - `ResponseServerError` → `Response(status_code=500)`
140
+ - Replace exception imports and usages:
141
+ - `Http404` → `NotFoundError404`
142
+ - `PermissionDenied` → `ForbiddenError403`
143
+ - `BadRequest` → `BadRequestError400`
144
+ - `SuspiciousOperation` → `SuspiciousOperationError400`
145
+ - `SuspiciousMultipartForm` → `SuspiciousMultipartFormError400`
146
+ - `SuspiciousFileOperation` → `SuspiciousFileOperationError400`
147
+ - `TooManyFieldsSent` → `TooManyFieldsSentError400`
148
+ - `TooManyFilesSent` → `TooManyFilesSentError400`
149
+ - `RequestDataTooBig` → `RequestDataTooBigError400`
150
+ - Replace `request.meta` with `request.environ`
151
+ - Rename X-Forwarded settings in your configuration:
152
+ - `USE_X_FORWARDED_HOST` → `HTTP_X_FORWARDED_HOST`
153
+ - `USE_X_FORWARDED_PORT` → `HTTP_X_FORWARDED_PORT`
154
+ - `USE_X_FORWARDED_FOR` → `HTTP_X_FORWARDED_FOR`
155
+ - Update `HTTPS_PROXY_HEADER` from tuple format to string format:
156
+
157
+ ```python
158
+ # Before
159
+ HTTPS_PROXY_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
160
+
161
+ # After
162
+ HTTPS_PROXY_HEADER = "X-Forwarded-Proto: https"
163
+ ```
164
+
165
+ - Replace `plain setting <name>` command with `plain settings get <name>`
166
+
167
+ ## [0.95.0](https://github.com/dropseed/plain/releases/plain@0.95.0) (2025-12-22)
168
+
169
+ ### What's changed
170
+
171
+ - Improved thread worker server shutdown behavior with `cancel_futures=True` for faster and cleaner process termination ([72d0620](https://github.com/dropseed/plain/commit/72d0620094))
172
+
173
+ ### Upgrade instructions
174
+
175
+ - No changes required
176
+
177
+ ## [0.94.0](https://github.com/dropseed/plain/releases/plain@0.94.0) (2025-12-12)
178
+
179
+ ### What's changed
180
+
181
+ - `FormFieldMissingError` exceptions are now automatically converted to HTTP 400 Bad Request responses with a warning log instead of causing a 500 error ([b38f6e5](https://github.com/dropseed/plain/commit/b38f6e50db))
182
+
183
+ ### Upgrade instructions
184
+
185
+ - No changes required
186
+
187
+ ## [0.93.1](https://github.com/dropseed/plain/releases/plain@0.93.1) (2025-12-09)
188
+
189
+ ### What's changed
190
+
191
+ - Added type annotation for `request.unique_id` attribute to improve IDE support and type checking ([23af501](https://github.com/dropseed/plain/commit/23af501d09))
192
+
193
+ ### Upgrade instructions
194
+
195
+ - No changes required
196
+
197
+ ## [0.93.0](https://github.com/dropseed/plain/releases/plain@0.93.0) (2025-12-04)
198
+
199
+ ### What's changed
200
+
201
+ - Improved type annotations across forms, HTTP handling, logging, and other core modules for better IDE support and type checking ([ac1eeb0](https://github.com/dropseed/plain/commit/ac1eeb0ea0))
202
+ - Internal refactor of `TimestampSigner` to use composition instead of inheritance from `Signer`, maintaining the same public API ([ac1eeb0](https://github.com/dropseed/plain/commit/ac1eeb0ea0))
203
+
204
+ ### Upgrade instructions
205
+
206
+ - No changes required
207
+
208
+ ## [0.92.0](https://github.com/dropseed/plain/releases/plain@0.92.0) (2025-12-01)
209
+
210
+ ### What's changed
211
+
212
+ - Added `request.client_ip` property to get the client's IP address, with support for `X-Forwarded-For` header when behind a trusted proxy ([cb0bc5d](https://github.com/dropseed/plain/commit/cb0bc5d08f))
213
+ - Added `USE_X_FORWARDED_FOR` setting to enable reading client IP from `X-Forwarded-For` header ([cb0bc5d](https://github.com/dropseed/plain/commit/cb0bc5d08f))
214
+ - Improved `print_event` CLI output styling with dimmed text for less visual noise ([b09edfd](https://github.com/dropseed/plain/commit/b09edfd2a1))
215
+
216
+ ### Upgrade instructions
217
+
218
+ - No changes required
219
+
220
+ ## [0.91.0](https://github.com/dropseed/plain/releases/plain@0.91.0) (2025-11-24)
221
+
222
+ ### What's changed
223
+
224
+ - Request body parsing refactored: the `request.data` attribute has been replaced with `request.json_data` and `request.form_data` for explicit content-type handling ([90332a9](https://github.com/dropseed/plain/commit/90332a9c21))
225
+ - `QueryDict` now has proper type annotations for `get()`, `pop()`, `getlist()`, and `__getitem__()` methods that reflect string return types ([90332a9](https://github.com/dropseed/plain/commit/90332a9c21))
226
+ - Forms now automatically select between `json_data` and `form_data` based on request content-type ([90332a9](https://github.com/dropseed/plain/commit/90332a9c21))
227
+ - View mixins `ObjectTemplateViewMixin` removed in favor of class inheritance for better typing - `UpdateView` and `DeleteView` now inherit from `DetailView` ([569afd6](https://github.com/dropseed/plain/commit/569afd606d))
228
+ - `AppLogger` context logging now uses a `context` dict parameter instead of `**kwargs` for better type checking ([581b406](https://github.com/dropseed/plain/commit/581b4060d3))
229
+ - Removed erroneous `AuthViewMixin` export from `plain.views` ([334bbb6](https://github.com/dropseed/plain/commit/334bbb6e7a))
230
+
231
+ ### Upgrade instructions
232
+
233
+ - Replace `request.data` with the appropriate method:
234
+ - For JSON requests: use `request.json_data` (returns a dict, raises `BadRequest` for invalid JSON)
235
+ - For form data: use `request.form_data` (returns a `QueryDict`)
236
+ - Update `app_logger` calls that pass context as kwargs to use the `context` parameter:
237
+
238
+ ```python
239
+ # Before
240
+ app_logger.info("Message", user_id=123, action="login")
241
+
242
+ # After
243
+ app_logger.info("Message", context={"user_id": 123, "action": "login"})
244
+ ```
245
+
246
+ ## [0.90.0](https://github.com/dropseed/plain/releases/plain@0.90.0) (2025-11-20)
247
+
248
+ ### What's changed
249
+
250
+ - Improved type annotations in `timezone.py`: `is_aware()` and `is_naive()` now accept both `datetime` and `time` objects for more flexible type checking ([a43145e](https://github.com/dropseed/plain/commit/a43145e697))
251
+ - Enhanced type annotations in view classes: `convert_value_to_response()` and handler result variables now use more explicit type hints for better IDE support ([dc4454e](https://github.com/dropseed/plain/commit/dc4454e196))
252
+ - Fixed type errors in forms and server workers: URL field now handles bytes properly, and worker wait_fds has explicit type annotation ([fc98d66](https://github.com/dropseed/plain/commit/fc98d666d4))
253
+
254
+ ### Upgrade instructions
255
+
256
+ - No changes required
257
+
258
+ ## [0.89.0](https://github.com/dropseed/plain/releases/plain@0.89.0) (2025-11-14)
259
+
260
+ ### What's changed
261
+
262
+ - Improved type annotations in view classes: `url_args`, `url_kwargs`, and various template/form context dictionaries now have more specific type hints for better IDE support and type checking ([83bcb95](https://github.com/dropseed/plain/commit/83bcb95b09))
263
+
264
+ ### Upgrade instructions
265
+
266
+ - No changes required
267
+
268
+ ## [0.88.0](https://github.com/dropseed/plain/releases/plain@0.88.0) (2025-11-13)
269
+
270
+ ### What's changed
271
+
272
+ - The `plain.forms` module now uses explicit imports instead of wildcard imports, improving IDE autocomplete and type checking support ([eff36f3](https://github.com/dropseed/plain/commit/eff36f31e8e15f84e11164a44c833aeab096ffbd))
273
+
274
+ ### Upgrade instructions
275
+
276
+ - No changes required
277
+
278
+ ## [0.87.0](https://github.com/dropseed/plain/releases/plain@0.87.0) (2025-11-12)
279
+
280
+ ### What's changed
281
+
282
+ - Internal classes now use abstract base classes with `@abstractmethod` decorators instead of raising `NotImplementedError`, improving type checking and IDE support ([91b329a](https://github.com/dropseed/plain/commit/91b329a8adb477031c4358e638b12f35f19bb85d), [81b5f88](https://github.com/dropseed/plain/commit/81b5f88a4bd39785f6b19c3c00c0ed23a36fb72f), [d2e2423](https://github.com/dropseed/plain/commit/d2e24235f497a92f45d5a21fc83d802897c2dec0), [61e7b5a](https://github.com/dropseed/plain/commit/61e7b5a0c8675aaaf65f0a626ff7959a786dca7f))
283
+ - Updated to latest version of `ty` type checker and fixed type errors and warnings throughout the codebase ([f4dbcef](https://github.com/dropseed/plain/commit/f4dbcefa929058be517cb1d4ab35bd73a89f26b8))
284
+
285
+ ### Upgrade instructions
286
+
287
+ - No changes required
288
+
289
+ ## [0.86.2](https://github.com/dropseed/plain/releases/plain@0.86.2) (2025-11-11)
290
+
291
+ ### What's changed
292
+
293
+ - CLI color output is now enabled in CI environments by checking the `CI` environment variable, matching the behavior of modern tools like uv ([a1500f15ed](https://github.com/dropseed/plain/commit/a1500f15ed))
294
+
295
+ ### Upgrade instructions
296
+
297
+ - No changes required
298
+
299
+ ## [0.86.1](https://github.com/dropseed/plain/releases/plain@0.86.1) (2025-11-10)
300
+
301
+ ### What's changed
302
+
303
+ - The `plain preflight` command now outputs to stderr only when using `--format json`, keeping stdout clean for JSON parsing while avoiding success messages appearing in error logs for text format ([72ebee7729](https://github.com/dropseed/plain/commit/72ebee7729))
304
+ - CLI color handling now follows the CLICOLOR standard with proper priority: `NO_COLOR` > `CLICOLOR_FORCE`/`FORCE_COLOR` > `CLICOLOR` > `isatty` ([c7fea406c5](https://github.com/dropseed/plain/commit/c7fea406c5))
305
+
306
+ ### Upgrade instructions
307
+
308
+ - No changes required
309
+
310
+ ## [0.86.0](https://github.com/dropseed/plain/releases/plain@0.86.0) (2025-11-10)
311
+
312
+ ### What's changed
313
+
314
+ - Log output is now split by severity level: INFO and below go to stdout, WARNING and above go to stderr for proper cloud platform log classification ([52403b15ba](https://github.com/dropseed/plain/commit/52403b15ba))
315
+ - Added `LOG_STREAM` setting to customize log output behavior with options: `"split"` (default), `"stdout"`, or `"stderr"` ([52403b15ba](https://github.com/dropseed/plain/commit/52403b15ba))
316
+ - Log configuration documentation expanded with detailed guidance on output streams and environment variable settings ([52403b15ba](https://github.com/dropseed/plain/commit/52403b15ba))
317
+
318
+ ### Upgrade instructions
319
+
320
+ - No changes required (default behavior splits logs to stdout/stderr automatically, but this can be customized via `PLAIN_LOG_STREAM` environment variable if needed)
321
+
322
+ ## [0.85.0](https://github.com/dropseed/plain/releases/plain@0.85.0) (2025-11-03)
323
+
324
+ ### What's changed
325
+
326
+ - CLI help output now organizes commands into "Common Commands", "Core Commands", and "Package Commands" sections for better discoverability ([73d3a48](https://github.com/dropseed/plain/commit/73d3a48fca))
327
+ - CLI help output has been customized with improved formatting and shortcut indicators showing which commands are shortcuts (e.g., `migrate → models migrate`) ([db882e6](https://github.com/dropseed/plain/commit/db882e6d47))
328
+ - CSRF exception messages now include more detailed context about what was rejected and why (e.g., port mismatches, host mismatches) ([9a8e09c](https://github.com/dropseed/plain/commit/9a8e09c1dc))
329
+ - The `plain agent md` command now saves a combined `AGENTS.md` file to `.plain/` by default when using `plain dev`, making it easier to provide context to coding agents ([786b7a0](https://github.com/dropseed/plain/commit/786b7a0ca1))
330
+ - CLI help text styling has been refined with dimmed descriptions and usage prefixes for improved readability ([d7f7053](https://github.com/dropseed/plain/commit/d7f705398d))
331
+
332
+ ### Upgrade instructions
333
+
334
+ - No changes required
335
+
336
+ ## [0.84.1](https://github.com/dropseed/plain/releases/plain@0.84.1) (2025-10-31)
337
+
338
+ ### What's changed
339
+
340
+ - Added `license = "BSD-3-Clause"` to package metadata in `pyproject.toml` ([8477355](https://github.com/dropseed/plain/commit/8477355e65))
341
+
342
+ ### Upgrade instructions
343
+
344
+ - No changes required
345
+
346
+ ## [0.84.0](https://github.com/dropseed/plain/releases/plain@0.84.0) (2025-10-29)
347
+
348
+ ### What's changed
349
+
350
+ - The `DEFAULT_RESPONSE_HEADERS` setting now supports format string placeholders (e.g., `{request.csp_nonce}`) for dynamic header values instead of requiring a callable function ([5199383128](https://github.com/dropseed/plain/commit/5199383128))
351
+ - Views can now set headers to `None` to explicitly remove default response headers ([5199383128](https://github.com/dropseed/plain/commit/5199383128))
352
+ - Added comprehensive documentation for customizing default response headers including override, remove, and extend patterns ([5199383128](https://github.com/dropseed/plain/commit/5199383128))
353
+
354
+ ### Upgrade instructions
355
+
356
+ - If you have `DEFAULT_RESPONSE_HEADERS` configured as a callable function, convert it to a dictionary with format string placeholders:
357
+
358
+ ```python
359
+ # Before:
360
+ def DEFAULT_RESPONSE_HEADERS(request):
361
+ nonce = request.csp_nonce
362
+ return {
363
+ "Content-Security-Policy": f"script-src 'self' 'nonce-{nonce}'",
364
+ }
365
+
366
+ # After:
367
+ DEFAULT_RESPONSE_HEADERS = {
368
+ "Content-Security-Policy": "script-src 'self' 'nonce-{request.csp_nonce}'",
369
+ }
370
+ ```
371
+
372
+ - If you were overriding default headers to empty strings (`""`) to remove them, change those to `None` instead
373
+
374
+ ## [0.83.0](https://github.com/dropseed/plain/releases/plain@0.83.0) (2025-10-29)
375
+
376
+ ### What's changed
377
+
378
+ - Added comprehensive Content Security Policy (CSP) documentation explaining how to use nonces with inline scripts and styles ([784f3dd972](https://github.com/dropseed/plain/commit/784f3dd972))
379
+ - The `json_script` utility function now accepts an optional `nonce` parameter for CSP-compliant inline JSON scripts ([784f3dd972](https://github.com/dropseed/plain/commit/784f3dd972))
380
+
381
+ ### Upgrade instructions
382
+
383
+ - Any `|json_script` usages need to make sure the second argument is a nonce, not a custom encoder (which is now third)
384
+
385
+ ## [0.82.0](https://github.com/dropseed/plain/releases/plain@0.82.0) (2025-10-29)
386
+
387
+ ### What's changed
388
+
389
+ - The `DEFAULT_RESPONSE_HEADERS` setting can now be a callable that accepts a request argument, enabling dynamic header generation per request ([cb92905834](https://github.com/dropseed/plain/commit/cb92905834))
390
+ - Added `request.csp_nonce` cached property for generating Content Security Policy nonces ([75071dcc70](https://github.com/dropseed/plain/commit/75071dcc70))
391
+ - Simplified the preflight command by moving `plain preflight check` back to `plain preflight` ([40c2c4560e](https://github.com/dropseed/plain/commit/40c2c4560e))
392
+
393
+ ### Upgrade instructions
394
+
395
+ - If you use `plain preflight check`, update to `plain preflight` (the `check` subcommand has been removed for simplicity)
396
+ - If you use `plain preflight check --deploy`, update to `plain preflight --deploy`
397
+
398
+ ## [0.81.0](https://github.com/dropseed/plain/releases/plain@0.81.0) (2025-10-22)
399
+
400
+ ### What's changed
401
+
402
+ - Removed support for category-specific error template fallbacks like `4xx.html` and `5xx.html` ([9513f7c4fa](https://github.com/dropseed/plain/commit/9513f7c4fa))
403
+
404
+ ### Upgrade instructions
405
+
406
+ - If you have `4xx.html` or `5xx.html` error templates, rename them to specific status code templates (e.g., `404.html`, `500.html`) or remove them if you prefer the plain HTTP response fallback
407
+
408
+ ## [0.80.0](https://github.com/dropseed/plain/releases/plain@0.80.0) (2025-10-22)
409
+
410
+ ### What's changed
411
+
412
+ - CSRF failures now raise `SuspiciousOperation` (HTTP 400) instead of `PermissionDenied` (HTTP 403) ([ad146bde3e](https://github.com/dropseed/plain/commit/ad146bde3e))
413
+ - Error templates can now use category-specific fallbacks like `4xx.html` or `5xx.html` instead of the generic `error.html` ([716cfa3cfc](https://github.com/dropseed/plain/commit/716cfa3cfc))
414
+ - Updated error template documentation with best practices for self-contained `500.html` templates ([55cea3b522](https://github.com/dropseed/plain/commit/55cea3b522))
415
+
416
+ ### Upgrade instructions
417
+
418
+ - If you have a `templates/error.html` template, instead create specific error templates for each status code you want to customize (e.g., `400.html`, `403.html`, `404.html`, `500.html`). You can also create category-specific templates like `4xx.html` or `5xx.html` for broader coverage.
419
+
420
+ ## [0.79.0](https://github.com/dropseed/plain/releases/plain@0.79.0) (2025-10-22)
421
+
422
+ ### What's changed
423
+
424
+ - Response objects now have an `exception` attribute that stores the exception that caused 5xx errors ([0a243ba89c](https://github.com/dropseed/plain/commit/0a243ba89c))
425
+ - Middleware classes now use an abstract base class `HttpMiddleware` with a `process_request()` method ([b960eed6c6](https://github.com/dropseed/plain/commit/b960eed6c6))
426
+ - CSRF middleware now raises `PermissionDenied` instead of rendering a custom `CsrfFailureView` ([d4b93e59b3](https://github.com/dropseed/plain/commit/d4b93e59b3))
427
+ - The `HTTP_ERROR_VIEWS` setting has been removed ([7a4e3a31f4](https://github.com/dropseed/plain/commit/7a4e3a31f4))
428
+ - Standalone `plain-changelog` and `plain-upgrade` executables have been removed in favor of the built-in commands ([07c3a4c540](https://github.com/dropseed/plain/commit/07c3a4c540))
429
+ - Standalone `plain-build` executable has been removed ([99301ea797](https://github.com/dropseed/plain/commit/99301ea797))
430
+ - Removed automatic logging of all HTTP 400+ status codes for cleaner logs ([c2769d7281](https://github.com/dropseed/plain/commit/c2769d7281))
431
+
432
+ ### Upgrade instructions
433
+
434
+ - If you have custom middleware, inherit from `HttpMiddleware` and rename your `__call__()` method to `process_request()`:
435
+
436
+ ```python
437
+ # Before:
438
+ class MyMiddleware:
439
+ def __init__(self, get_response):
440
+ self.get_response = get_response
441
+
442
+ def __call__(self, request):
443
+ response = self.get_response(request)
444
+ return response
445
+
446
+ # After:
447
+ from plain.http import HttpMiddleware
448
+
449
+ class MyMiddleware(HttpMiddleware):
450
+ def process_request(self, request):
451
+ response = self.get_response(request)
452
+ return response
453
+ ```
454
+
455
+ - Remove any custom `HTTP_ERROR_VIEWS` setting from your configuration - error views are now controlled entirely by exception handlers
456
+ - If you were calling `plain-changelog` or `plain-upgrade` as standalone commands, use `plain changelog` or `plain upgrade` instead
457
+ - If you were calling `plain-build` as a standalone command, use `plain build` instead
458
+
459
+ ## [0.78.2](https://github.com/dropseed/plain/releases/plain@0.78.2) (2025-10-20)
460
+
461
+ ### What's changed
462
+
463
+ - Updated package metadata to use `[dependency-groups]` instead of `[tool.uv]` for development dependencies, following PEP 735 standard ([1b43a3a272](https://github.com/dropseed/plain/commit/1b43a3a272))
464
+
465
+ ### Upgrade instructions
466
+
467
+ - No changes required
468
+
469
+ ## [0.78.1](https://github.com/dropseed/plain/releases/plain@0.78.1) (2025-10-17)
470
+
471
+ ### What's changed
472
+
473
+ - Fixed job worker logging by using `getLogger` instead of directly instantiating `Logger` for the plain logger ([dd675666b9](https://github.com/dropseed/plain/commit/dd675666b9))
474
+
475
+ ### Upgrade instructions
476
+
477
+ - No changes required
478
+
479
+ ## [0.78.0](https://github.com/dropseed/plain/releases/plain@0.78.0) (2025-10-17)
480
+
481
+ ### What's changed
482
+
483
+ - Chores have been refactored to use abstract base classes instead of decorated functions ([c4466d3c60](https://github.com/dropseed/plain/commit/c4466d3c60))
484
+ - Added `SHELL_IMPORT` setting to customize what gets automatically imported in `plain shell` ([9055f59c08](https://github.com/dropseed/plain/commit/9055f59c08))
485
+ - Views that return `None` now raise `Http404` instead of returning `ResponseNotFound` ([5bb60016eb](https://github.com/dropseed/plain/commit/5bb60016eb))
486
+ - The `plain chores list` command output formatting now matches the `plain jobs list` format ([4b6881a49e](https://github.com/dropseed/plain/commit/4b6881a49e))
487
+
488
+ ### Upgrade instructions
489
+
490
+ - Update any chores from decorated functions to class-based chores:
491
+
492
+ ```python
493
+ # Before:
494
+ @register_chore("group")
495
+ def chore_name():
496
+ """Description"""
497
+ return "Done!"
498
+
499
+ # After:
500
+ from plain.chores import Chore, register_chore
501
+
502
+ @register_chore
503
+ class ChoreName(Chore):
504
+ """Description"""
505
+
506
+ def run(self):
507
+ return "Done!"
508
+ ```
509
+
510
+ - Import `Chore` base class from `plain.chores` when creating new chores
511
+
512
+ ## [0.77.0](https://github.com/dropseed/plain/releases/plain@0.77.0) (2025-10-13)
513
+
514
+ ### What's changed
515
+
516
+ - The `plain server --reload` now uses `watchfiles` for improved cross-platform file watching ([92e95c5032](https://github.com/dropseed/plain/commit/92e95c5032))
517
+ - Server reloader now watches `.env*` files for changes and triggers automatic reload ([92e95c5032](https://github.com/dropseed/plain/commit/92e95c5032))
518
+ - HTML template additions and deletions now trigger automatic server reload when using `--reload` ([f2f31c288b](https://github.com/dropseed/plain/commit/f2f31c288b))
519
+ - Internal server worker type renamed from "gthread" to "thread" for clarity ([6470748e91](https://github.com/dropseed/plain/commit/6470748e91))
520
+
521
+ ### Upgrade instructions
522
+
523
+ - No changes required
524
+
525
+ ## [0.76.0](https://github.com/dropseed/plain/releases/plain@0.76.0) (2025-10-12)
526
+
527
+ ### What's changed
528
+
529
+ - Added new `plain server` command with built-in WSGI server (vendored gunicorn) ([f9dc2867c7](https://github.com/dropseed/plain/commit/f9dc2867c7))
530
+ - The `plain server` command supports `WEB_CONCURRENCY` environment variable for worker processes ([0c3e8c6f32](https://github.com/dropseed/plain/commit/0c3e8c6f32))
531
+ - Simplified server startup logging to use a single consolidated log line ([b1405b71f0](https://github.com/dropseed/plain/commit/b1405b71f0))
532
+ - Removed `gunicorn` as an external dependency - server functionality is now built into plain core ([cb6c2f484d](https://github.com/dropseed/plain/commit/cb6c2f484d))
533
+ - Internal server environment variables renamed from `GUNICORN_*` to `PLAIN_SERVER_*` ([745c073123](https://github.com/dropseed/plain/commit/745c073123))
534
+ - Removed unused server features including hooks, syslog, proxy protocol, user/group dropping, and config file loading ([be0f82d92b](https://github.com/dropseed/plain/commit/be0f82d92b), [10c206875b](https://github.com/dropseed/plain/commit/10c206875b), [ecf327014c](https://github.com/dropseed/plain/commit/ecf327014c), [fb5a10f50b](https://github.com/dropseed/plain/commit/fb5a10f50b))
535
+
536
+ ### Upgrade instructions
537
+
538
+ - Replace any direct usage of `gunicorn` with the new `plain server` command (ex. `gunicorn plain.wsgi:app --workers 4` becomes `plain server --workers 4`)
539
+ - Update any deployment scripts or Procfiles that use `gunicorn` to use `plain server` instead
540
+ - Remove `gunicorn` from your project dependencies if you added it separately (it's now built into plain)
541
+ - For Heroku deployments, the `$PORT` is not automatically detected - update your Procfile to `web: plain server --bind 0.0.0.0:$PORT`
542
+ - If you were using gunicorn configuration files, migrate the settings to `plain server` command-line options (run `plain server --help` to see available options)
543
+
544
+ ## [0.75.0](https://github.com/dropseed/plain/releases/plain@0.75.0) (2025-10-10)
545
+
546
+ ### What's changed
547
+
548
+ - Documentation references updated from `plain-worker` to `plain-jobs` following the package rename ([24219856e0](https://github.com/dropseed/plain/commit/24219856e0))
549
+
550
+ ### Upgrade instructions
551
+
552
+ - No changes required
553
+
554
+ ## [0.74.0](https://github.com/dropseed/plain/releases/plain@0.74.0) (2025-10-08)
555
+
556
+ ### What's changed
557
+
558
+ - The `plain agent request` command now displays request ID in the response output ([4a20cfa3fc](https://github.com/dropseed/plain/commit/4a20cfa3fc))
559
+ - Request headers are now included in OpenTelemetry tracing baggage for improved observability ([08a3376d06](https://github.com/dropseed/plain/commit/08a3376d06))
560
+
561
+ ### Upgrade instructions
562
+
563
+ - No changes required
564
+
565
+ ## [0.73.0](https://github.com/dropseed/plain/releases/plain@0.73.0) (2025-10-07)
566
+
567
+ ### What's changed
568
+
569
+ - Internal preflight result handling updated to use `model_options` instead of `_meta` for model label retrieval ([73ba469](https://github.com/dropseed/plain/commit/73ba469ba0))
570
+
571
+ ### Upgrade instructions
572
+
573
+ - No changes required
574
+
575
+ ## [0.72.2](https://github.com/dropseed/plain/releases/plain@0.72.2) (2025-10-06)
576
+
577
+ ### What's changed
578
+
579
+ - Improved type annotations for test client responses with new `ClientResponse` wrapper class ([369353f9d6](https://github.com/dropseed/plain/commit/369353f9d6))
580
+ - Enhanced internal type checking for WSGI handler and request/response types ([50463b00c3](https://github.com/dropseed/plain/commit/50463b00c3))
581
+
582
+ ### Upgrade instructions
583
+
584
+ - No changes required
585
+
586
+ ## [0.72.1](https://github.com/dropseed/plain/releases/plain@0.72.1) (2025-10-02)
587
+
588
+ ### What's changed
589
+
590
+ - Fixed documentation examples to use the correct view attribute names (`self.user` instead of `self.request.user`) ([f6278d9](https://github.com/dropseed/plain/commit/f6278d9bb4))
591
+
592
+ ### Upgrade instructions
593
+
594
+ - No changes required
595
+
596
+ ## [0.72.0](https://github.com/dropseed/plain/releases/plain@0.72.0) (2025-10-02)
597
+
598
+ ### What's changed
599
+
600
+ - Request attributes `user` and `session` are no longer set directly on the request object ([154ee10](https://github.com/dropseed/plain/commit/154ee10375))
601
+ - Test client now uses `plain.auth.requests.get_request_user()` to retrieve user for response object when available ([154ee10](https://github.com/dropseed/plain/commit/154ee10375))
602
+ - Removed `plain.auth.middleware.AuthenticationMiddleware` from default middleware configuration ([154ee10](https://github.com/dropseed/plain/commit/154ee10375))
603
+
604
+ ### Upgrade instructions
605
+
606
+ - No changes required
607
+
608
+ ## [0.71.0](https://github.com/dropseed/plain/releases/plain@0.71.0) (2025-09-30)
609
+
610
+ ### What's changed
611
+
612
+ - Renamed `HttpRequest` to `Request` throughout the codebase for consistency and simplicity ([cd46ff20](https://github.com/dropseed/plain/commit/cd46ff2003))
613
+ - Renamed `HttpHeaders` to `RequestHeaders` for naming consistency ([cd46ff20](https://github.com/dropseed/plain/commit/cd46ff2003))
614
+ - Renamed settings: `APP_NAME` → `NAME`, `APP_VERSION` → `VERSION`, `APP_LOG_LEVEL` → `LOG_LEVEL`, `APP_LOG_FORMAT` → `LOG_FORMAT`, `PLAIN_LOG_LEVEL` → `FRAMEWORK_LOG_LEVEL` ([4c5f2166](https://github.com/dropseed/plain/commit/4c5f2166c1))
615
+ - Added `request.get_preferred_type()` method to select the most preferred media type from Accept header ([b105ba4d](https://github.com/dropseed/plain/commit/b105ba4dd0))
616
+ - Moved helper functions in `http/request.py` to be static methods of `QueryDict` ([0e1b0133](https://github.com/dropseed/plain/commit/0e1b0133c5))
617
+
618
+ ### Upgrade instructions
619
+
620
+ - Replace all imports and usage of `HttpRequest` with `Request`
621
+ - Replace all imports and usage of `HttpHeaders` with `RequestHeaders`
622
+ - Update any custom settings that reference `APP_NAME` to `NAME`, `APP_VERSION` to `VERSION`, `APP_LOG_LEVEL` to `LOG_LEVEL`, `APP_LOG_FORMAT` to `LOG_FORMAT`, and `PLAIN_LOG_LEVEL` to `FRAMEWORK_LOG_LEVEL`
623
+ - Configuring these settings via the `PLAIN_` prefixed environment variable will need to be updated accordingly
624
+
625
+ ## [0.70.0](https://github.com/dropseed/plain/releases/plain@0.70.0) (2025-09-30)
626
+
627
+ ### What's changed
628
+
629
+ - Added comprehensive type annotations throughout the codebase for improved IDE support and type checking ([365414c](https://github.com/dropseed/plain/commit/365414cc6f))
630
+ - The `Asset` class in `plain.assets.finders` is now a module-level public class instead of being defined inside `iter_assets()` ([6321765](https://github.com/dropseed/plain/commit/6321765d30))
631
+
632
+ ### Upgrade instructions
633
+
634
+ - No changes required
635
+
636
+ ## [0.69.0](https://github.com/dropseed/plain/releases/plain@0.69.0) (2025-09-29)
637
+
638
+ ### What's changed
639
+
640
+ - Model-related exceptions (`FieldDoesNotExist`, `FieldError`, `ObjectDoesNotExist`, `MultipleObjectsReturned`, `EmptyResultSet`, `FullResultSet`) moved from `plain.exceptions` to `plain.models.exceptions` ([1c02564](https://github.com/dropseed/plain/commit/1c02564561))
641
+ - Added `plain dev` alias prompt that suggests adding `p` as a shell alias for convenience ([d913b44](https://github.com/dropseed/plain/commit/d913b44fab))
642
+
643
+ ### Upgrade instructions
644
+
645
+ - Replace imports of `FieldDoesNotExist`, `FieldError`, `ObjectDoesNotExist`, `MultipleObjectsReturned`, `EmptyResultSet`, or `FullResultSet` from `plain.exceptions` to `plain.models.exceptions`
646
+ - If you're using `ObjectDoesNotExist` in views, update your import from `plain.exceptions.ObjectDoesNotExist` to `plain.models.exceptions.ObjectDoesNotExist`
647
+
648
+ ## [0.68.1](https://github.com/dropseed/plain/releases/plain@0.68.1) (2025-09-25)
649
+
650
+ ### What's changed
651
+
652
+ - Preflight checks are now sorted by name for consistent ordering ([cb8e160](https://github.com/dropseed/plain/commit/cb8e160934))
653
+
654
+ ### Upgrade instructions
655
+
656
+ - No changes required
657
+
658
+ ## [0.68.0](https://github.com/dropseed/plain/releases/plain@0.68.0) (2025-09-25)
659
+
660
+ ### What's changed
661
+
662
+ - Major refactor of the preflight check system with new CLI commands and improved output ([b0b610d461](https://github.com/dropseed/plain/commit/b0b610d461))
663
+ - Preflight checks now use descriptive IDs instead of numeric codes ([cd96c97b25](https://github.com/dropseed/plain/commit/cd96c97b25))
664
+ - Unified preflight error messages and hints into a single `fix` field ([c7cde12149](https://github.com/dropseed/plain/commit/c7cde12149))
665
+ - Added `plain-upgrade` as a standalone command for upgrading Plain packages ([42f2eed80c](https://github.com/dropseed/plain/commit/42f2eed80c))
666
+
667
+ ### Upgrade instructions
668
+
669
+ - Update any uses of the `plain preflight` command to `plain preflight check`, and remove the `--database` and `--fail-level` options which no longer exist
670
+ - Custom preflight checks should be class based, extending `PreflightCheck` and implementing the `run()` method
671
+ - Preflight checks need to be registered with a custom name (ex. `@register_check("app.my_custom_check")`) and optionally with `deploy=True` if it should run in only in deploy mode
672
+ - Preflight results should use `PreflightResult` (optionally with `warning=True`) instead of `preflight.Warning` or `preflight.Error`
673
+ - Preflight result IDs should be descriptive strings (e.g., `models.lazy_reference_resolution_failed`) instead of numeric codes
674
+ - `PREFLIGHT_SILENCED_CHECKS` setting has been replaced with `PREFLIGHT_SILENCED_RESULTS` which should contain a list of result IDs to silence. `PREFLIGHT_SILENCED_CHECKS` now silences entire checks by name.
675
+
676
+ ## [0.67.0](https://github.com/dropseed/plain/releases/plain@0.67.0) (2025-09-22)
677
+
678
+ ### What's changed
679
+
680
+ - `ALLOWED_HOSTS` now defaults to `[]` (empty list) which allows all hosts, making it easier for development setups ([d3cb7712b9](https://github.com/dropseed/plain/commit/d3cb7712b9))
681
+ - Empty `ALLOWED_HOSTS` in production now triggers a preflight error instead of a warning to ensure proper security configuration ([d3cb7712b9](https://github.com/dropseed/plain/commit/d3cb7712b9))
682
+
683
+ ### Upgrade instructions
684
+
685
+ - No changes required
686
+
3
687
  ## [0.66.0](https://github.com/dropseed/plain/releases/plain@0.66.0) (2025-09-22)
4
688
 
5
689
  ### What's changed