plain 0.68.0__py3-none-any.whl → 0.103.0__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 (192) hide show
  1. plain/CHANGELOG.md +684 -1
  2. plain/README.md +1 -1
  3. plain/agents/.claude/rules/plain.md +88 -0
  4. plain/agents/.claude/skills/plain-install/SKILL.md +26 -0
  5. plain/agents/.claude/skills/plain-upgrade/SKILL.md +35 -0
  6. plain/assets/compile.py +25 -12
  7. plain/assets/finders.py +24 -17
  8. plain/assets/fingerprints.py +10 -7
  9. plain/assets/urls.py +1 -1
  10. plain/assets/views.py +47 -33
  11. plain/chores/README.md +25 -23
  12. plain/chores/__init__.py +2 -1
  13. plain/chores/core.py +27 -0
  14. plain/chores/registry.py +23 -36
  15. plain/cli/README.md +185 -16
  16. plain/cli/__init__.py +2 -1
  17. plain/cli/agent.py +234 -0
  18. plain/cli/build.py +7 -8
  19. plain/cli/changelog.py +11 -5
  20. plain/cli/chores.py +32 -34
  21. plain/cli/core.py +110 -26
  22. plain/cli/docs.py +98 -21
  23. plain/cli/formatting.py +40 -17
  24. plain/cli/install.py +10 -54
  25. plain/cli/{agent/llmdocs.py → llmdocs.py} +45 -26
  26. plain/cli/output.py +6 -2
  27. plain/cli/preflight.py +27 -75
  28. plain/cli/print.py +4 -4
  29. plain/cli/registry.py +96 -10
  30. plain/cli/{agent/request.py → request.py} +67 -33
  31. plain/cli/runtime.py +45 -0
  32. plain/cli/scaffold.py +2 -7
  33. plain/cli/server.py +153 -0
  34. plain/cli/settings.py +53 -49
  35. plain/cli/shell.py +15 -12
  36. plain/cli/startup.py +9 -8
  37. plain/cli/upgrade.py +17 -104
  38. plain/cli/urls.py +12 -7
  39. plain/cli/utils.py +3 -3
  40. plain/csrf/README.md +65 -40
  41. plain/csrf/middleware.py +53 -43
  42. plain/debug.py +5 -2
  43. plain/exceptions.py +22 -114
  44. plain/forms/README.md +453 -24
  45. plain/forms/__init__.py +55 -4
  46. plain/forms/boundfield.py +15 -8
  47. plain/forms/exceptions.py +1 -1
  48. plain/forms/fields.py +346 -143
  49. plain/forms/forms.py +75 -45
  50. plain/http/README.md +356 -9
  51. plain/http/__init__.py +41 -26
  52. plain/http/cookie.py +15 -7
  53. plain/http/exceptions.py +65 -0
  54. plain/http/middleware.py +32 -0
  55. plain/http/multipartparser.py +99 -88
  56. plain/http/request.py +362 -250
  57. plain/http/response.py +99 -197
  58. plain/internal/__init__.py +8 -1
  59. plain/internal/files/base.py +35 -19
  60. plain/internal/files/locks.py +19 -11
  61. plain/internal/files/move.py +8 -3
  62. plain/internal/files/temp.py +25 -6
  63. plain/internal/files/uploadedfile.py +47 -28
  64. plain/internal/files/uploadhandler.py +64 -58
  65. plain/internal/files/utils.py +24 -10
  66. plain/internal/handlers/base.py +34 -23
  67. plain/internal/handlers/exception.py +68 -65
  68. plain/internal/handlers/wsgi.py +65 -54
  69. plain/internal/middleware/headers.py +37 -11
  70. plain/internal/middleware/hosts.py +11 -8
  71. plain/internal/middleware/https.py +17 -7
  72. plain/internal/middleware/slash.py +14 -9
  73. plain/internal/reloader.py +77 -0
  74. plain/json.py +2 -1
  75. plain/logs/README.md +161 -62
  76. plain/logs/__init__.py +1 -1
  77. plain/logs/{loggers.py → app.py} +71 -67
  78. plain/logs/configure.py +63 -14
  79. plain/logs/debug.py +17 -6
  80. plain/logs/filters.py +15 -0
  81. plain/logs/formatters.py +7 -4
  82. plain/packages/README.md +105 -23
  83. plain/packages/config.py +15 -7
  84. plain/packages/registry.py +27 -16
  85. plain/paginator.py +31 -21
  86. plain/preflight/README.md +209 -24
  87. plain/preflight/__init__.py +1 -0
  88. plain/preflight/checks.py +3 -1
  89. plain/preflight/files.py +3 -1
  90. plain/preflight/registry.py +26 -11
  91. plain/preflight/results.py +15 -7
  92. plain/preflight/security.py +15 -13
  93. plain/preflight/settings.py +54 -0
  94. plain/preflight/urls.py +4 -1
  95. plain/runtime/README.md +115 -47
  96. plain/runtime/__init__.py +10 -6
  97. plain/runtime/global_settings.py +34 -25
  98. plain/runtime/secret.py +20 -0
  99. plain/runtime/user_settings.py +110 -38
  100. plain/runtime/utils.py +1 -1
  101. plain/server/LICENSE +35 -0
  102. plain/server/README.md +155 -0
  103. plain/server/__init__.py +9 -0
  104. plain/server/app.py +52 -0
  105. plain/server/arbiter.py +555 -0
  106. plain/server/config.py +118 -0
  107. plain/server/errors.py +31 -0
  108. plain/server/glogging.py +292 -0
  109. plain/server/http/__init__.py +12 -0
  110. plain/server/http/body.py +283 -0
  111. plain/server/http/errors.py +155 -0
  112. plain/server/http/message.py +400 -0
  113. plain/server/http/parser.py +70 -0
  114. plain/server/http/unreader.py +88 -0
  115. plain/server/http/wsgi.py +421 -0
  116. plain/server/pidfile.py +92 -0
  117. plain/server/sock.py +240 -0
  118. plain/server/util.py +317 -0
  119. plain/server/workers/__init__.py +6 -0
  120. plain/server/workers/base.py +304 -0
  121. plain/server/workers/sync.py +212 -0
  122. plain/server/workers/thread.py +399 -0
  123. plain/server/workers/workertmp.py +50 -0
  124. plain/signals/README.md +170 -1
  125. plain/signals/__init__.py +0 -1
  126. plain/signals/dispatch/dispatcher.py +49 -27
  127. plain/signing.py +131 -35
  128. plain/templates/README.md +211 -20
  129. plain/templates/jinja/__init__.py +13 -5
  130. plain/templates/jinja/environments.py +5 -4
  131. plain/templates/jinja/extensions.py +12 -5
  132. plain/templates/jinja/filters.py +7 -2
  133. plain/templates/jinja/globals.py +2 -2
  134. plain/test/README.md +184 -22
  135. plain/test/client.py +340 -222
  136. plain/test/encoding.py +9 -6
  137. plain/test/exceptions.py +7 -2
  138. plain/urls/README.md +157 -73
  139. plain/urls/converters.py +18 -15
  140. plain/urls/exceptions.py +2 -2
  141. plain/urls/patterns.py +38 -22
  142. plain/urls/resolvers.py +35 -25
  143. plain/urls/utils.py +5 -1
  144. plain/utils/README.md +250 -3
  145. plain/utils/cache.py +17 -11
  146. plain/utils/crypto.py +21 -5
  147. plain/utils/datastructures.py +89 -56
  148. plain/utils/dateparse.py +9 -6
  149. plain/utils/deconstruct.py +15 -7
  150. plain/utils/decorators.py +5 -1
  151. plain/utils/dotenv.py +373 -0
  152. plain/utils/duration.py +8 -4
  153. plain/utils/encoding.py +14 -7
  154. plain/utils/functional.py +66 -49
  155. plain/utils/hashable.py +5 -1
  156. plain/utils/html.py +36 -22
  157. plain/utils/http.py +16 -9
  158. plain/utils/inspect.py +14 -6
  159. plain/utils/ipv6.py +7 -3
  160. plain/utils/itercompat.py +6 -1
  161. plain/utils/module_loading.py +7 -3
  162. plain/utils/regex_helper.py +37 -23
  163. plain/utils/safestring.py +14 -6
  164. plain/utils/text.py +41 -23
  165. plain/utils/timezone.py +33 -22
  166. plain/utils/tree.py +35 -19
  167. plain/validators.py +94 -52
  168. plain/views/README.md +156 -79
  169. plain/views/__init__.py +0 -1
  170. plain/views/base.py +25 -18
  171. plain/views/errors.py +13 -5
  172. plain/views/exceptions.py +4 -1
  173. plain/views/forms.py +6 -6
  174. plain/views/objects.py +52 -49
  175. plain/views/redirect.py +18 -15
  176. plain/views/templates.py +5 -3
  177. plain/wsgi.py +3 -1
  178. {plain-0.68.0.dist-info → plain-0.103.0.dist-info}/METADATA +4 -2
  179. plain-0.103.0.dist-info/RECORD +198 -0
  180. {plain-0.68.0.dist-info → plain-0.103.0.dist-info}/WHEEL +1 -1
  181. plain-0.103.0.dist-info/entry_points.txt +2 -0
  182. plain/AGENTS.md +0 -18
  183. plain/cli/agent/__init__.py +0 -20
  184. plain/cli/agent/docs.py +0 -80
  185. plain/cli/agent/md.py +0 -87
  186. plain/cli/agent/prompt.py +0 -45
  187. plain/csrf/views.py +0 -31
  188. plain/logs/utils.py +0 -46
  189. plain/templates/AGENTS.md +0 -3
  190. plain-0.68.0.dist-info/RECORD +0 -169
  191. plain-0.68.0.dist-info/entry_points.txt +0 -5
  192. {plain-0.68.0.dist-info → plain-0.103.0.dist-info}/licenses/LICENSE +0 -0
plain/CHANGELOG.md CHANGED
@@ -1,5 +1,688 @@
1
1
  # plain changelog
2
2
 
3
+ ## [0.103.0](https://github.com/dropseed/plain/releases/plain@0.103.0) (2026-01-30)
4
+
5
+ ### What's changed
6
+
7
+ - `plain docs` now shows markdown documentation by default (previously required `--source`), with a new `--symbols` flag to show only the symbolicated API surface ([b71dab9d5d](https://github.com/dropseed/plain/commit/b71dab9d5d))
8
+ - `plain docs --list` now shows all official Plain packages (installed and uninstalled) with descriptions and install status ([9cba705d62](https://github.com/dropseed/plain/commit/9cba705d62))
9
+ - `plain docs` for uninstalled packages now shows the install command and an online docs URL instead of a generic error ([9cba705d62](https://github.com/dropseed/plain/commit/9cba705d62))
10
+ - Removed the `plain agent context` command and the `SessionStart` hook setup — agent rules now provide context directly without needing a startup hook ([88d9424643](https://github.com/dropseed/plain/commit/88d9424643))
11
+ - `plain agent install` now cleans up old SessionStart hooks from `.claude/settings.json` ([88d9424643](https://github.com/dropseed/plain/commit/88d9424643))
12
+
13
+ ### Upgrade instructions
14
+
15
+ - The `--source` flag for `plain docs` has been removed. Use `--symbols` instead to see the symbolicated API surface.
16
+ - The `--open` flag for `plain docs` has been removed.
17
+ - Run `plain agent install` to clean up the old SessionStart hook from your `.claude/settings.json`.
18
+
19
+ ## [0.102.0](https://github.com/dropseed/plain/releases/plain@0.102.0) (2026-01-28)
20
+
21
+ ### What's changed
22
+
23
+ - Refactored agent integration from skills-based to rules-based: packages now provide `agents/.claude/rules/` files and `agents/.claude/skills/` directories instead of `skills/` directories ([512040ac51](https://github.com/dropseed/plain/commit/512040ac51))
24
+ - The `plain agent install` command now copies both rules (`.md` files) and skills to the project's `.claude/` directory, and cleans up orphaned `plain*` items ([512040ac51](https://github.com/dropseed/plain/commit/512040ac51))
25
+ - Removed standalone skills (`plain-docs`, `plain-shell`, `plain-request`) that are now provided as passive rules instead ([512040ac51](https://github.com/dropseed/plain/commit/512040ac51))
26
+
27
+ ### Upgrade instructions
28
+
29
+ - Run `plain agent install` to update your `.claude/` directory with the new rules-based structure.
30
+
31
+ ## [0.101.2](https://github.com/dropseed/plain/releases/plain@0.101.2) (2026-01-28)
32
+
33
+ ### What's changed
34
+
35
+ - 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))
36
+ - 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))
37
+ - Updated templates README examples to use `id` instead of `pk` ([837d345d23](https://github.com/dropseed/plain/commit/837d345d23))
38
+ - Added Settings section to README ([803fee1ad5](https://github.com/dropseed/plain/commit/803fee1ad5))
39
+
40
+ ### Upgrade instructions
41
+
42
+ - No changes required.
43
+
44
+ ## [0.101.1](https://github.com/dropseed/plain/releases/plain@0.101.1) (2026-01-17)
45
+
46
+ ### What's changed
47
+
48
+ - 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))
49
+ - 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))
50
+
51
+ ### Upgrade instructions
52
+
53
+ - No changes required.
54
+
55
+ ## [0.101.0](https://github.com/dropseed/plain/releases/plain@0.101.0) (2026-01-15)
56
+
57
+ ### What's changed
58
+
59
+ - 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))
60
+ - 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))
61
+ - 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))
62
+
63
+ ### Upgrade instructions
64
+
65
+ - No changes required
66
+
67
+ ## [0.100.1](https://github.com/dropseed/plain/releases/plain@0.100.1) (2026-01-15)
68
+
69
+ ### What's changed
70
+
71
+ - 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))
72
+
73
+ ### Upgrade instructions
74
+
75
+ - No changes required
76
+
77
+ ## [0.100.0](https://github.com/dropseed/plain/releases/plain@0.100.0) (2026-01-15)
78
+
79
+ ### What's changed
80
+
81
+ - 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))
82
+ - 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))
83
+ - 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))
84
+ - Added `--no-headers` and `--no-body` flags to `plain request` for limiting output ([fac8673436](https://github.com/dropseed/plain/commit/fac8673436))
85
+
86
+ ### Upgrade instructions
87
+
88
+ - Replace `plain skills --install` with `plain agent install`
89
+ - Replace `plain skills` (without flags) with `plain agent skills`
90
+ - Run `plain agent install` to set up the new SessionStart hook in your project's `.claude/` or `.codex/` directory
91
+
92
+ ## [0.99.0](https://github.com/dropseed/plain/releases/plain@0.99.0) (2026-01-15)
93
+
94
+ ### What's changed
95
+
96
+ - 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))
97
+
98
+ ### Upgrade instructions
99
+
100
+ - No changes required
101
+
102
+ ## [0.98.1](https://github.com/dropseed/plain/releases/plain@0.98.1) (2026-01-13)
103
+
104
+ ### What's changed
105
+
106
+ - Fixed `INSTALLED_PACKAGES` not being optional in user settings, restoring the default empty list behavior ([820773c473](https://github.com/dropseed/plain/commit/820773c473))
107
+
108
+ ### Upgrade instructions
109
+
110
+ - No changes required
111
+
112
+ ## [0.98.0](https://github.com/dropseed/plain/releases/plain@0.98.0) (2026-01-13)
113
+
114
+ ### What's changed
115
+
116
+ - 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))
117
+ - Added README documentation for `plain.skills` with available skills and installation instructions ([7c90fc8595](https://github.com/dropseed/plain/commit/7c90fc8595))
118
+
119
+ ### Upgrade instructions
120
+
121
+ - No changes required
122
+
123
+ ## [0.97.0](https://github.com/dropseed/plain/releases/plain@0.97.0) (2026-01-13)
124
+
125
+ ### What's changed
126
+
127
+ - 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))
128
+
129
+ ### Upgrade instructions
130
+
131
+ - Update imports of HTTP exceptions from `plain.exceptions` to `plain.http`:
132
+
133
+ ```python
134
+ # Before
135
+ from plain.exceptions import NotFoundError404, ForbiddenError403, BadRequestError400
136
+
137
+ # After
138
+ from plain.http import NotFoundError404, ForbiddenError403, BadRequestError400
139
+ ```
140
+
141
+ ## [0.96.0](https://github.com/dropseed/plain/releases/plain@0.96.0) (2026-01-13)
142
+
143
+ ### What's changed
144
+
145
+ - Response classes renamed for consistency: `ResponseRedirect` → `RedirectResponse`, `ResponseNotModified` → `NotModifiedResponse`, `ResponseNotAllowed` → `NotAllowedResponse` ([fad5bf28b0](https://github.com/dropseed/plain/commit/fad5bf28b0))
146
+ - Redundant response classes removed: `ResponseNotFound`, `ResponseForbidden`, `ResponseBadRequest`, `ResponseGone`, `ResponseServerError` - use `Response(status_code=X)` instead ([fad5bf28b0](https://github.com/dropseed/plain/commit/fad5bf28b0))
147
+ - HTTP exceptions renamed to include status code suffix: `Http404` → `NotFoundError404`, `PermissionDenied` → `ForbiddenError403`, `BadRequest` → `BadRequestError400`, `SuspiciousOperation` → `SuspiciousOperationError400` ([5a1f020f52](https://github.com/dropseed/plain/commit/5a1f020f52))
148
+ - Added `Secret[T]` type annotation for masking sensitive settings like `SECRET_KEY` in CLI output ([8713dc08b0](https://github.com/dropseed/plain/commit/8713dc08b0))
149
+ - 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))
150
+ - New `plain settings list` and `plain settings get` CLI commands for viewing settings with their sources ([8713dc08b0](https://github.com/dropseed/plain/commit/8713dc08b0))
151
+ - Added preflight check for unused environment variables matching configured prefixes ([8713dc08b0](https://github.com/dropseed/plain/commit/8713dc08b0))
152
+ - Renamed `request.meta` to `request.environ` for clarity ([786b95bef8](https://github.com/dropseed/plain/commit/786b95bef8))
153
+ - 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))
154
+ - 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))
155
+ - 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))
156
+
157
+ ### Upgrade instructions
158
+
159
+ - Replace Response class imports and usages:
160
+ - `ResponseRedirect` → `RedirectResponse`
161
+ - `ResponseNotModified` → `NotModifiedResponse`
162
+ - `ResponseNotAllowed` → `NotAllowedResponse`
163
+ - `ResponseNotFound` → `Response(status_code=404)`
164
+ - `ResponseForbidden` → `Response(status_code=403)`
165
+ - `ResponseBadRequest` → `Response(status_code=400)`
166
+ - `ResponseGone` → `Response(status_code=410)`
167
+ - `ResponseServerError` → `Response(status_code=500)`
168
+ - Replace exception imports and usages:
169
+ - `Http404` → `NotFoundError404`
170
+ - `PermissionDenied` → `ForbiddenError403`
171
+ - `BadRequest` → `BadRequestError400`
172
+ - `SuspiciousOperation` → `SuspiciousOperationError400`
173
+ - `SuspiciousMultipartForm` → `SuspiciousMultipartFormError400`
174
+ - `SuspiciousFileOperation` → `SuspiciousFileOperationError400`
175
+ - `TooManyFieldsSent` → `TooManyFieldsSentError400`
176
+ - `TooManyFilesSent` → `TooManyFilesSentError400`
177
+ - `RequestDataTooBig` → `RequestDataTooBigError400`
178
+ - Replace `request.meta` with `request.environ`
179
+ - Rename X-Forwarded settings in your configuration:
180
+ - `USE_X_FORWARDED_HOST` → `HTTP_X_FORWARDED_HOST`
181
+ - `USE_X_FORWARDED_PORT` → `HTTP_X_FORWARDED_PORT`
182
+ - `USE_X_FORWARDED_FOR` → `HTTP_X_FORWARDED_FOR`
183
+ - Update `HTTPS_PROXY_HEADER` from tuple format to string format:
184
+
185
+ ```python
186
+ # Before
187
+ HTTPS_PROXY_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
188
+
189
+ # After
190
+ HTTPS_PROXY_HEADER = "X-Forwarded-Proto: https"
191
+ ```
192
+
193
+ - Replace `plain setting <name>` command with `plain settings get <name>`
194
+
195
+ ## [0.95.0](https://github.com/dropseed/plain/releases/plain@0.95.0) (2025-12-22)
196
+
197
+ ### What's changed
198
+
199
+ - Improved thread worker server shutdown behavior with `cancel_futures=True` for faster and cleaner process termination ([72d0620](https://github.com/dropseed/plain/commit/72d0620094))
200
+
201
+ ### Upgrade instructions
202
+
203
+ - No changes required
204
+
205
+ ## [0.94.0](https://github.com/dropseed/plain/releases/plain@0.94.0) (2025-12-12)
206
+
207
+ ### What's changed
208
+
209
+ - `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))
210
+
211
+ ### Upgrade instructions
212
+
213
+ - No changes required
214
+
215
+ ## [0.93.1](https://github.com/dropseed/plain/releases/plain@0.93.1) (2025-12-09)
216
+
217
+ ### What's changed
218
+
219
+ - Added type annotation for `request.unique_id` attribute to improve IDE support and type checking ([23af501](https://github.com/dropseed/plain/commit/23af501d09))
220
+
221
+ ### Upgrade instructions
222
+
223
+ - No changes required
224
+
225
+ ## [0.93.0](https://github.com/dropseed/plain/releases/plain@0.93.0) (2025-12-04)
226
+
227
+ ### What's changed
228
+
229
+ - 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))
230
+ - 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))
231
+
232
+ ### Upgrade instructions
233
+
234
+ - No changes required
235
+
236
+ ## [0.92.0](https://github.com/dropseed/plain/releases/plain@0.92.0) (2025-12-01)
237
+
238
+ ### What's changed
239
+
240
+ - 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))
241
+ - Added `USE_X_FORWARDED_FOR` setting to enable reading client IP from `X-Forwarded-For` header ([cb0bc5d](https://github.com/dropseed/plain/commit/cb0bc5d08f))
242
+ - Improved `print_event` CLI output styling with dimmed text for less visual noise ([b09edfd](https://github.com/dropseed/plain/commit/b09edfd2a1))
243
+
244
+ ### Upgrade instructions
245
+
246
+ - No changes required
247
+
248
+ ## [0.91.0](https://github.com/dropseed/plain/releases/plain@0.91.0) (2025-11-24)
249
+
250
+ ### What's changed
251
+
252
+ - 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))
253
+ - `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))
254
+ - Forms now automatically select between `json_data` and `form_data` based on request content-type ([90332a9](https://github.com/dropseed/plain/commit/90332a9c21))
255
+ - 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))
256
+ - `AppLogger` context logging now uses a `context` dict parameter instead of `**kwargs` for better type checking ([581b406](https://github.com/dropseed/plain/commit/581b4060d3))
257
+ - Removed erroneous `AuthViewMixin` export from `plain.views` ([334bbb6](https://github.com/dropseed/plain/commit/334bbb6e7a))
258
+
259
+ ### Upgrade instructions
260
+
261
+ - Replace `request.data` with the appropriate method:
262
+ - For JSON requests: use `request.json_data` (returns a dict, raises `BadRequest` for invalid JSON)
263
+ - For form data: use `request.form_data` (returns a `QueryDict`)
264
+ - Update `app_logger` calls that pass context as kwargs to use the `context` parameter:
265
+
266
+ ```python
267
+ # Before
268
+ app_logger.info("Message", user_id=123, action="login")
269
+
270
+ # After
271
+ app_logger.info("Message", context={"user_id": 123, "action": "login"})
272
+ ```
273
+
274
+ ## [0.90.0](https://github.com/dropseed/plain/releases/plain@0.90.0) (2025-11-20)
275
+
276
+ ### What's changed
277
+
278
+ - 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))
279
+ - 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))
280
+ - 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))
281
+
282
+ ### Upgrade instructions
283
+
284
+ - No changes required
285
+
286
+ ## [0.89.0](https://github.com/dropseed/plain/releases/plain@0.89.0) (2025-11-14)
287
+
288
+ ### What's changed
289
+
290
+ - 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))
291
+
292
+ ### Upgrade instructions
293
+
294
+ - No changes required
295
+
296
+ ## [0.88.0](https://github.com/dropseed/plain/releases/plain@0.88.0) (2025-11-13)
297
+
298
+ ### What's changed
299
+
300
+ - 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))
301
+
302
+ ### Upgrade instructions
303
+
304
+ - No changes required
305
+
306
+ ## [0.87.0](https://github.com/dropseed/plain/releases/plain@0.87.0) (2025-11-12)
307
+
308
+ ### What's changed
309
+
310
+ - 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))
311
+ - 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))
312
+
313
+ ### Upgrade instructions
314
+
315
+ - No changes required
316
+
317
+ ## [0.86.2](https://github.com/dropseed/plain/releases/plain@0.86.2) (2025-11-11)
318
+
319
+ ### What's changed
320
+
321
+ - 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))
322
+
323
+ ### Upgrade instructions
324
+
325
+ - No changes required
326
+
327
+ ## [0.86.1](https://github.com/dropseed/plain/releases/plain@0.86.1) (2025-11-10)
328
+
329
+ ### What's changed
330
+
331
+ - 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))
332
+ - 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))
333
+
334
+ ### Upgrade instructions
335
+
336
+ - No changes required
337
+
338
+ ## [0.86.0](https://github.com/dropseed/plain/releases/plain@0.86.0) (2025-11-10)
339
+
340
+ ### What's changed
341
+
342
+ - 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))
343
+ - Added `LOG_STREAM` setting to customize log output behavior with options: `"split"` (default), `"stdout"`, or `"stderr"` ([52403b15ba](https://github.com/dropseed/plain/commit/52403b15ba))
344
+ - Log configuration documentation expanded with detailed guidance on output streams and environment variable settings ([52403b15ba](https://github.com/dropseed/plain/commit/52403b15ba))
345
+
346
+ ### Upgrade instructions
347
+
348
+ - No changes required (default behavior splits logs to stdout/stderr automatically, but this can be customized via `PLAIN_LOG_STREAM` environment variable if needed)
349
+
350
+ ## [0.85.0](https://github.com/dropseed/plain/releases/plain@0.85.0) (2025-11-03)
351
+
352
+ ### What's changed
353
+
354
+ - 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))
355
+ - 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))
356
+ - 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))
357
+ - 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))
358
+ - CLI help text styling has been refined with dimmed descriptions and usage prefixes for improved readability ([d7f7053](https://github.com/dropseed/plain/commit/d7f705398d))
359
+
360
+ ### Upgrade instructions
361
+
362
+ - No changes required
363
+
364
+ ## [0.84.1](https://github.com/dropseed/plain/releases/plain@0.84.1) (2025-10-31)
365
+
366
+ ### What's changed
367
+
368
+ - Added `license = "BSD-3-Clause"` to package metadata in `pyproject.toml` ([8477355](https://github.com/dropseed/plain/commit/8477355e65))
369
+
370
+ ### Upgrade instructions
371
+
372
+ - No changes required
373
+
374
+ ## [0.84.0](https://github.com/dropseed/plain/releases/plain@0.84.0) (2025-10-29)
375
+
376
+ ### What's changed
377
+
378
+ - 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))
379
+ - Views can now set headers to `None` to explicitly remove default response headers ([5199383128](https://github.com/dropseed/plain/commit/5199383128))
380
+ - Added comprehensive documentation for customizing default response headers including override, remove, and extend patterns ([5199383128](https://github.com/dropseed/plain/commit/5199383128))
381
+
382
+ ### Upgrade instructions
383
+
384
+ - If you have `DEFAULT_RESPONSE_HEADERS` configured as a callable function, convert it to a dictionary with format string placeholders:
385
+
386
+ ```python
387
+ # Before:
388
+ def DEFAULT_RESPONSE_HEADERS(request):
389
+ nonce = request.csp_nonce
390
+ return {
391
+ "Content-Security-Policy": f"script-src 'self' 'nonce-{nonce}'",
392
+ }
393
+
394
+ # After:
395
+ DEFAULT_RESPONSE_HEADERS = {
396
+ "Content-Security-Policy": "script-src 'self' 'nonce-{request.csp_nonce}'",
397
+ }
398
+ ```
399
+
400
+ - If you were overriding default headers to empty strings (`""`) to remove them, change those to `None` instead
401
+
402
+ ## [0.83.0](https://github.com/dropseed/plain/releases/plain@0.83.0) (2025-10-29)
403
+
404
+ ### What's changed
405
+
406
+ - 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))
407
+ - 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))
408
+
409
+ ### Upgrade instructions
410
+
411
+ - Any `|json_script` usages need to make sure the second argument is a nonce, not a custom encoder (which is now third)
412
+
413
+ ## [0.82.0](https://github.com/dropseed/plain/releases/plain@0.82.0) (2025-10-29)
414
+
415
+ ### What's changed
416
+
417
+ - 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))
418
+ - Added `request.csp_nonce` cached property for generating Content Security Policy nonces ([75071dcc70](https://github.com/dropseed/plain/commit/75071dcc70))
419
+ - Simplified the preflight command by moving `plain preflight check` back to `plain preflight` ([40c2c4560e](https://github.com/dropseed/plain/commit/40c2c4560e))
420
+
421
+ ### Upgrade instructions
422
+
423
+ - If you use `plain preflight check`, update to `plain preflight` (the `check` subcommand has been removed for simplicity)
424
+ - If you use `plain preflight check --deploy`, update to `plain preflight --deploy`
425
+
426
+ ## [0.81.0](https://github.com/dropseed/plain/releases/plain@0.81.0) (2025-10-22)
427
+
428
+ ### What's changed
429
+
430
+ - Removed support for category-specific error template fallbacks like `4xx.html` and `5xx.html` ([9513f7c4fa](https://github.com/dropseed/plain/commit/9513f7c4fa))
431
+
432
+ ### Upgrade instructions
433
+
434
+ - 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
435
+
436
+ ## [0.80.0](https://github.com/dropseed/plain/releases/plain@0.80.0) (2025-10-22)
437
+
438
+ ### What's changed
439
+
440
+ - CSRF failures now raise `SuspiciousOperation` (HTTP 400) instead of `PermissionDenied` (HTTP 403) ([ad146bde3e](https://github.com/dropseed/plain/commit/ad146bde3e))
441
+ - 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))
442
+ - Updated error template documentation with best practices for self-contained `500.html` templates ([55cea3b522](https://github.com/dropseed/plain/commit/55cea3b522))
443
+
444
+ ### Upgrade instructions
445
+
446
+ - 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.
447
+
448
+ ## [0.79.0](https://github.com/dropseed/plain/releases/plain@0.79.0) (2025-10-22)
449
+
450
+ ### What's changed
451
+
452
+ - Response objects now have an `exception` attribute that stores the exception that caused 5xx errors ([0a243ba89c](https://github.com/dropseed/plain/commit/0a243ba89c))
453
+ - Middleware classes now use an abstract base class `HttpMiddleware` with a `process_request()` method ([b960eed6c6](https://github.com/dropseed/plain/commit/b960eed6c6))
454
+ - CSRF middleware now raises `PermissionDenied` instead of rendering a custom `CsrfFailureView` ([d4b93e59b3](https://github.com/dropseed/plain/commit/d4b93e59b3))
455
+ - The `HTTP_ERROR_VIEWS` setting has been removed ([7a4e3a31f4](https://github.com/dropseed/plain/commit/7a4e3a31f4))
456
+ - 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))
457
+ - Standalone `plain-build` executable has been removed ([99301ea797](https://github.com/dropseed/plain/commit/99301ea797))
458
+ - Removed automatic logging of all HTTP 400+ status codes for cleaner logs ([c2769d7281](https://github.com/dropseed/plain/commit/c2769d7281))
459
+
460
+ ### Upgrade instructions
461
+
462
+ - If you have custom middleware, inherit from `HttpMiddleware` and rename your `__call__()` method to `process_request()`:
463
+
464
+ ```python
465
+ # Before:
466
+ class MyMiddleware:
467
+ def __init__(self, get_response):
468
+ self.get_response = get_response
469
+
470
+ def __call__(self, request):
471
+ response = self.get_response(request)
472
+ return response
473
+
474
+ # After:
475
+ from plain.http import HttpMiddleware
476
+
477
+ class MyMiddleware(HttpMiddleware):
478
+ def process_request(self, request):
479
+ response = self.get_response(request)
480
+ return response
481
+ ```
482
+
483
+ - Remove any custom `HTTP_ERROR_VIEWS` setting from your configuration - error views are now controlled entirely by exception handlers
484
+ - If you were calling `plain-changelog` or `plain-upgrade` as standalone commands, use `plain changelog` or `plain upgrade` instead
485
+ - If you were calling `plain-build` as a standalone command, use `plain build` instead
486
+
487
+ ## [0.78.2](https://github.com/dropseed/plain/releases/plain@0.78.2) (2025-10-20)
488
+
489
+ ### What's changed
490
+
491
+ - 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))
492
+
493
+ ### Upgrade instructions
494
+
495
+ - No changes required
496
+
497
+ ## [0.78.1](https://github.com/dropseed/plain/releases/plain@0.78.1) (2025-10-17)
498
+
499
+ ### What's changed
500
+
501
+ - Fixed job worker logging by using `getLogger` instead of directly instantiating `Logger` for the plain logger ([dd675666b9](https://github.com/dropseed/plain/commit/dd675666b9))
502
+
503
+ ### Upgrade instructions
504
+
505
+ - No changes required
506
+
507
+ ## [0.78.0](https://github.com/dropseed/plain/releases/plain@0.78.0) (2025-10-17)
508
+
509
+ ### What's changed
510
+
511
+ - Chores have been refactored to use abstract base classes instead of decorated functions ([c4466d3c60](https://github.com/dropseed/plain/commit/c4466d3c60))
512
+ - Added `SHELL_IMPORT` setting to customize what gets automatically imported in `plain shell` ([9055f59c08](https://github.com/dropseed/plain/commit/9055f59c08))
513
+ - Views that return `None` now raise `Http404` instead of returning `ResponseNotFound` ([5bb60016eb](https://github.com/dropseed/plain/commit/5bb60016eb))
514
+ - The `plain chores list` command output formatting now matches the `plain jobs list` format ([4b6881a49e](https://github.com/dropseed/plain/commit/4b6881a49e))
515
+
516
+ ### Upgrade instructions
517
+
518
+ - Update any chores from decorated functions to class-based chores:
519
+
520
+ ```python
521
+ # Before:
522
+ @register_chore("group")
523
+ def chore_name():
524
+ """Description"""
525
+ return "Done!"
526
+
527
+ # After:
528
+ from plain.chores import Chore, register_chore
529
+
530
+ @register_chore
531
+ class ChoreName(Chore):
532
+ """Description"""
533
+
534
+ def run(self):
535
+ return "Done!"
536
+ ```
537
+
538
+ - Import `Chore` base class from `plain.chores` when creating new chores
539
+
540
+ ## [0.77.0](https://github.com/dropseed/plain/releases/plain@0.77.0) (2025-10-13)
541
+
542
+ ### What's changed
543
+
544
+ - The `plain server --reload` now uses `watchfiles` for improved cross-platform file watching ([92e95c5032](https://github.com/dropseed/plain/commit/92e95c5032))
545
+ - Server reloader now watches `.env*` files for changes and triggers automatic reload ([92e95c5032](https://github.com/dropseed/plain/commit/92e95c5032))
546
+ - HTML template additions and deletions now trigger automatic server reload when using `--reload` ([f2f31c288b](https://github.com/dropseed/plain/commit/f2f31c288b))
547
+ - Internal server worker type renamed from "gthread" to "thread" for clarity ([6470748e91](https://github.com/dropseed/plain/commit/6470748e91))
548
+
549
+ ### Upgrade instructions
550
+
551
+ - No changes required
552
+
553
+ ## [0.76.0](https://github.com/dropseed/plain/releases/plain@0.76.0) (2025-10-12)
554
+
555
+ ### What's changed
556
+
557
+ - Added new `plain server` command with built-in WSGI server (vendored gunicorn) ([f9dc2867c7](https://github.com/dropseed/plain/commit/f9dc2867c7))
558
+ - The `plain server` command supports `WEB_CONCURRENCY` environment variable for worker processes ([0c3e8c6f32](https://github.com/dropseed/plain/commit/0c3e8c6f32))
559
+ - Simplified server startup logging to use a single consolidated log line ([b1405b71f0](https://github.com/dropseed/plain/commit/b1405b71f0))
560
+ - Removed `gunicorn` as an external dependency - server functionality is now built into plain core ([cb6c2f484d](https://github.com/dropseed/plain/commit/cb6c2f484d))
561
+ - Internal server environment variables renamed from `GUNICORN_*` to `PLAIN_SERVER_*` ([745c073123](https://github.com/dropseed/plain/commit/745c073123))
562
+ - 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))
563
+
564
+ ### Upgrade instructions
565
+
566
+ - Replace any direct usage of `gunicorn` with the new `plain server` command (ex. `gunicorn plain.wsgi:app --workers 4` becomes `plain server --workers 4`)
567
+ - Update any deployment scripts or Procfiles that use `gunicorn` to use `plain server` instead
568
+ - Remove `gunicorn` from your project dependencies if you added it separately (it's now built into plain)
569
+ - For Heroku deployments, the `$PORT` is not automatically detected - update your Procfile to `web: plain server --bind 0.0.0.0:$PORT`
570
+ - If you were using gunicorn configuration files, migrate the settings to `plain server` command-line options (run `plain server --help` to see available options)
571
+
572
+ ## [0.75.0](https://github.com/dropseed/plain/releases/plain@0.75.0) (2025-10-10)
573
+
574
+ ### What's changed
575
+
576
+ - Documentation references updated from `plain-worker` to `plain-jobs` following the package rename ([24219856e0](https://github.com/dropseed/plain/commit/24219856e0))
577
+
578
+ ### Upgrade instructions
579
+
580
+ - No changes required
581
+
582
+ ## [0.74.0](https://github.com/dropseed/plain/releases/plain@0.74.0) (2025-10-08)
583
+
584
+ ### What's changed
585
+
586
+ - The `plain agent request` command now displays request ID in the response output ([4a20cfa3fc](https://github.com/dropseed/plain/commit/4a20cfa3fc))
587
+ - Request headers are now included in OpenTelemetry tracing baggage for improved observability ([08a3376d06](https://github.com/dropseed/plain/commit/08a3376d06))
588
+
589
+ ### Upgrade instructions
590
+
591
+ - No changes required
592
+
593
+ ## [0.73.0](https://github.com/dropseed/plain/releases/plain@0.73.0) (2025-10-07)
594
+
595
+ ### What's changed
596
+
597
+ - Internal preflight result handling updated to use `model_options` instead of `_meta` for model label retrieval ([73ba469](https://github.com/dropseed/plain/commit/73ba469ba0))
598
+
599
+ ### Upgrade instructions
600
+
601
+ - No changes required
602
+
603
+ ## [0.72.2](https://github.com/dropseed/plain/releases/plain@0.72.2) (2025-10-06)
604
+
605
+ ### What's changed
606
+
607
+ - Improved type annotations for test client responses with new `ClientResponse` wrapper class ([369353f9d6](https://github.com/dropseed/plain/commit/369353f9d6))
608
+ - Enhanced internal type checking for WSGI handler and request/response types ([50463b00c3](https://github.com/dropseed/plain/commit/50463b00c3))
609
+
610
+ ### Upgrade instructions
611
+
612
+ - No changes required
613
+
614
+ ## [0.72.1](https://github.com/dropseed/plain/releases/plain@0.72.1) (2025-10-02)
615
+
616
+ ### What's changed
617
+
618
+ - 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))
619
+
620
+ ### Upgrade instructions
621
+
622
+ - No changes required
623
+
624
+ ## [0.72.0](https://github.com/dropseed/plain/releases/plain@0.72.0) (2025-10-02)
625
+
626
+ ### What's changed
627
+
628
+ - Request attributes `user` and `session` are no longer set directly on the request object ([154ee10](https://github.com/dropseed/plain/commit/154ee10375))
629
+ - 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))
630
+ - Removed `plain.auth.middleware.AuthenticationMiddleware` from default middleware configuration ([154ee10](https://github.com/dropseed/plain/commit/154ee10375))
631
+
632
+ ### Upgrade instructions
633
+
634
+ - No changes required
635
+
636
+ ## [0.71.0](https://github.com/dropseed/plain/releases/plain@0.71.0) (2025-09-30)
637
+
638
+ ### What's changed
639
+
640
+ - Renamed `HttpRequest` to `Request` throughout the codebase for consistency and simplicity ([cd46ff20](https://github.com/dropseed/plain/commit/cd46ff2003))
641
+ - Renamed `HttpHeaders` to `RequestHeaders` for naming consistency ([cd46ff20](https://github.com/dropseed/plain/commit/cd46ff2003))
642
+ - 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))
643
+ - Added `request.get_preferred_type()` method to select the most preferred media type from Accept header ([b105ba4d](https://github.com/dropseed/plain/commit/b105ba4dd0))
644
+ - Moved helper functions in `http/request.py` to be static methods of `QueryDict` ([0e1b0133](https://github.com/dropseed/plain/commit/0e1b0133c5))
645
+
646
+ ### Upgrade instructions
647
+
648
+ - Replace all imports and usage of `HttpRequest` with `Request`
649
+ - Replace all imports and usage of `HttpHeaders` with `RequestHeaders`
650
+ - 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`
651
+ - Configuring these settings via the `PLAIN_` prefixed environment variable will need to be updated accordingly
652
+
653
+ ## [0.70.0](https://github.com/dropseed/plain/releases/plain@0.70.0) (2025-09-30)
654
+
655
+ ### What's changed
656
+
657
+ - Added comprehensive type annotations throughout the codebase for improved IDE support and type checking ([365414c](https://github.com/dropseed/plain/commit/365414cc6f))
658
+ - 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))
659
+
660
+ ### Upgrade instructions
661
+
662
+ - No changes required
663
+
664
+ ## [0.69.0](https://github.com/dropseed/plain/releases/plain@0.69.0) (2025-09-29)
665
+
666
+ ### What's changed
667
+
668
+ - 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))
669
+ - Added `plain dev` alias prompt that suggests adding `p` as a shell alias for convenience ([d913b44](https://github.com/dropseed/plain/commit/d913b44fab))
670
+
671
+ ### Upgrade instructions
672
+
673
+ - Replace imports of `FieldDoesNotExist`, `FieldError`, `ObjectDoesNotExist`, `MultipleObjectsReturned`, `EmptyResultSet`, or `FullResultSet` from `plain.exceptions` to `plain.models.exceptions`
674
+ - If you're using `ObjectDoesNotExist` in views, update your import from `plain.exceptions.ObjectDoesNotExist` to `plain.models.exceptions.ObjectDoesNotExist`
675
+
676
+ ## [0.68.1](https://github.com/dropseed/plain/releases/plain@0.68.1) (2025-09-25)
677
+
678
+ ### What's changed
679
+
680
+ - Preflight checks are now sorted by name for consistent ordering ([cb8e160](https://github.com/dropseed/plain/commit/cb8e160934))
681
+
682
+ ### Upgrade instructions
683
+
684
+ - No changes required
685
+
3
686
  ## [0.68.0](https://github.com/dropseed/plain/releases/plain@0.68.0) (2025-09-25)
4
687
 
5
688
  ### What's changed
@@ -11,7 +694,7 @@
11
694
 
12
695
  ### Upgrade instructions
13
696
 
14
- - Use `plain preflight check` instead of `plain preflight` to run all checks
697
+ - Update any uses of the `plain preflight` command to `plain preflight check`, and remove the `--database` and `--fail-level` options which no longer exist
15
698
  - Custom preflight checks should be class based, extending `PreflightCheck` and implementing the `run()` method
16
699
  - 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
17
700
  - Preflight results should use `PreflightResult` (optionally with `warning=True`) instead of `preflight.Warning` or `preflight.Error`