plain 0.79.0__py3-none-any.whl → 0.80.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.
Potentially problematic release.
This version of plain might be problematic. Click here for more details.
- plain/CHANGELOG.md +12 -0
- plain/csrf/middleware.py +2 -2
- plain/views/README.md +6 -5
- plain/views/errors.py +4 -1
- {plain-0.79.0.dist-info → plain-0.80.0.dist-info}/METADATA +1 -1
- {plain-0.79.0.dist-info → plain-0.80.0.dist-info}/RECORD +9 -9
- {plain-0.79.0.dist-info → plain-0.80.0.dist-info}/WHEEL +0 -0
- {plain-0.79.0.dist-info → plain-0.80.0.dist-info}/entry_points.txt +0 -0
- {plain-0.79.0.dist-info → plain-0.80.0.dist-info}/licenses/LICENSE +0 -0
plain/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# plain changelog
|
|
2
2
|
|
|
3
|
+
## [0.80.0](https://github.com/dropseed/plain/releases/plain@0.80.0) (2025-10-22)
|
|
4
|
+
|
|
5
|
+
### What's changed
|
|
6
|
+
|
|
7
|
+
- CSRF failures now raise `SuspiciousOperation` (HTTP 400) instead of `PermissionDenied` (HTTP 403) ([ad146bde3e](https://github.com/dropseed/plain/commit/ad146bde3e))
|
|
8
|
+
- 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))
|
|
9
|
+
- Updated error template documentation with best practices for self-contained `500.html` templates ([55cea3b522](https://github.com/dropseed/plain/commit/55cea3b522))
|
|
10
|
+
|
|
11
|
+
### Upgrade instructions
|
|
12
|
+
|
|
13
|
+
- 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.
|
|
14
|
+
|
|
3
15
|
## [0.79.0](https://github.com/dropseed/plain/releases/plain@0.79.0) (2025-10-22)
|
|
4
16
|
|
|
5
17
|
### What's changed
|
plain/csrf/middleware.py
CHANGED
|
@@ -5,7 +5,7 @@ from collections.abc import Callable
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
from urllib.parse import urlparse
|
|
7
7
|
|
|
8
|
-
from plain.exceptions import
|
|
8
|
+
from plain.exceptions import SuspiciousOperation
|
|
9
9
|
from plain.http import HttpMiddleware
|
|
10
10
|
from plain.runtime import settings
|
|
11
11
|
|
|
@@ -34,7 +34,7 @@ class CsrfViewMiddleware(HttpMiddleware):
|
|
|
34
34
|
allowed, reason = self.should_allow_request(request)
|
|
35
35
|
|
|
36
36
|
if not allowed:
|
|
37
|
-
raise
|
|
37
|
+
raise SuspiciousOperation(reason)
|
|
38
38
|
|
|
39
39
|
return self.get_response(request)
|
|
40
40
|
|
plain/views/README.md
CHANGED
|
@@ -251,16 +251,17 @@ class ExampleView(DetailView):
|
|
|
251
251
|
|
|
252
252
|
## Error views
|
|
253
253
|
|
|
254
|
-
HTTP errors are
|
|
255
|
-
|
|
256
|
-
For example:
|
|
254
|
+
HTTP errors are rendered using templates. Create templates for the errors users actually see:
|
|
257
255
|
|
|
258
256
|
- `templates/404.html` - Page not found
|
|
259
257
|
- `templates/403.html` - Forbidden
|
|
260
258
|
- `templates/500.html` - Server error
|
|
261
|
-
- `templates/error.html` - Generic fallback for all errors
|
|
262
259
|
|
|
263
|
-
|
|
260
|
+
Plain looks for `{status_code}.html`, then `{category}.html` (e.g., `4xx.html`), then returns a plain HTTP response. Most apps only need the three specific templates above.
|
|
261
|
+
|
|
262
|
+
Templates receive `status_code` and `exception` in context.
|
|
263
|
+
|
|
264
|
+
**Note:** `500.html` should be self-contained - avoid extending base templates or accessing database/session, since server errors can occur during middleware or template rendering. `404.html` and `403.html` can safely extend base templates since they occur during view execution after middleware runs.
|
|
264
265
|
|
|
265
266
|
## Redirect views
|
|
266
267
|
|
plain/views/errors.py
CHANGED
|
@@ -29,7 +29,10 @@ class ErrorView(TemplateView):
|
|
|
29
29
|
return context
|
|
30
30
|
|
|
31
31
|
def get_template_names(self) -> list[str]:
|
|
32
|
-
|
|
32
|
+
# Try specific status code first (e.g. "404.html")
|
|
33
|
+
# Then fall back to category (e.g. "4xx.html" or "5xx.html")
|
|
34
|
+
category = f"{str(self.status_code)[0]}xx"
|
|
35
|
+
return [f"{self.status_code}.html", f"{category}.html"]
|
|
33
36
|
|
|
34
37
|
def get_request_handler(self) -> Callable[[], Any]:
|
|
35
38
|
return self.get # All methods (post, patch, etc.) will use the get()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
plain/AGENTS.md,sha256=As6EFSWWHJ9lYIxb2LMRqNRteH45SRs7a_VFslzF53M,1046
|
|
2
|
-
plain/CHANGELOG.md,sha256=
|
|
2
|
+
plain/CHANGELOG.md,sha256=CZJXaqSX2G0nv_Bp-_VKzIuVGgDlwtFdD_cEek6ajpg,31725
|
|
3
3
|
plain/README.md,sha256=VvzhXNvf4I6ddmjBP9AExxxFXxs7RwyoxdgFm-W5dsg,4072
|
|
4
4
|
plain/__main__.py,sha256=GK39854Lc_LO_JP8DzY9Y2MIQ4cQEl7SXFJy244-lC8,110
|
|
5
5
|
plain/debug.py,sha256=C2OnFHtRGMrpCiHSt-P2r58JypgQZ62qzDBpV4mhtFM,855
|
|
@@ -49,7 +49,7 @@ plain/cli/agent/md.py,sha256=eRspArtBVQNqxIii6J7sPPZqBjc-qmAF49aLnwZoWAE,2778
|
|
|
49
49
|
plain/cli/agent/prompt.py,sha256=hMb4RXiMF68xSSHC3gXrCUjv5jZa7flQzL4FZvUMu1I,1261
|
|
50
50
|
plain/cli/agent/request.py,sha256=cBdN9w4msPqfaE13DHrvAE0lkSdkTdTkIjZzBht8Ydc,6432
|
|
51
51
|
plain/csrf/README.md,sha256=ApWpB-qlEf0LkOKm9Yr-6f_lB9XJEvGFDo_fraw8ghI,2391
|
|
52
|
-
plain/csrf/middleware.py,sha256=
|
|
52
|
+
plain/csrf/middleware.py,sha256=WDSsQOjkOxgk8JU-cNiPlcK5IRXemOfmDMXPH7Riv0U,4883
|
|
53
53
|
plain/forms/README.md,sha256=7MJQxNBoKkg0rW16qF6bGpUBxZrMrWjl2DZZk6gjzAU,2258
|
|
54
54
|
plain/forms/__init__.py,sha256=sK-Y1QC_7iueo1BSbYrGT0uq2LooB0U8_j5VksNyZ4c,236
|
|
55
55
|
plain/forms/boundfield.py,sha256=PEquPRn1BoVd4ZkIin8tjkBzRDMv-41wO8qHV0S1shg,1967
|
|
@@ -179,17 +179,17 @@ plain/utils/text.py,sha256=teav7elbqEtGnhKG3ajf-V9Hb-Gsg8uqDrogqWizqjI,10094
|
|
|
179
179
|
plain/utils/timesince.py,sha256=a_-ZoPK_s3Pt998CW4rWp0clZ1XyK2x04hCqak2giII,5928
|
|
180
180
|
plain/utils/timezone.py,sha256=M_I5yvs9NsHbtNBPJgHErvWw9vatzx4M96tRQs5gS3g,6823
|
|
181
181
|
plain/utils/tree.py,sha256=rj_JpZ2kVD3UExWoKnsRdVCoRjvzkuVOONcHzREjSyw,4766
|
|
182
|
-
plain/views/README.md,sha256
|
|
182
|
+
plain/views/README.md,sha256=Kuw6tMfFp0-fu2aDFM0iCKV-FzgZmkPwd78cYKDXaUA,7438
|
|
183
183
|
plain/views/__init__.py,sha256=a-N1nkklVohJTtz0yD1MMaS0g66HviEjsKydNVVjvVc,392
|
|
184
184
|
plain/views/base.py,sha256=yWh6S68PsYcH1dvRdibQIanBYkjo2iJ8IAbR2PTWQrk,4419
|
|
185
|
-
plain/views/errors.py,sha256=
|
|
185
|
+
plain/views/errors.py,sha256=og20lx5WGDiQ-thOAYtWNsfjuZiLLVydpk94k810j6A,1632
|
|
186
186
|
plain/views/exceptions.py,sha256=-YKH1Jd9Zm_yXiz797PVjJB6VWaPCTXClHIUkG2fq78,198
|
|
187
187
|
plain/views/forms.py,sha256=ESZOXuo6IeYixp1RZvPb94KplkowRiwO2eGJCM6zJI0,2400
|
|
188
188
|
plain/views/objects.py,sha256=5y0PoPPo07dQTTcJ_9kZcx0iI1O7regsooAIK4VqXQ0,5579
|
|
189
189
|
plain/views/redirect.py,sha256=mIpSAFcaEyeLDyv4Fr6g_ektduG4Wfa6s6L-rkdazmM,2154
|
|
190
190
|
plain/views/templates.py,sha256=9LgDMCv4C7JzLiyw8jHF-i4350ukwgixC_9y4faEGu0,1885
|
|
191
|
-
plain-0.
|
|
192
|
-
plain-0.
|
|
193
|
-
plain-0.
|
|
194
|
-
plain-0.
|
|
195
|
-
plain-0.
|
|
191
|
+
plain-0.80.0.dist-info/METADATA,sha256=jweqjIZtRoFGSJ0YCjb5dF9bcOAsPZaGbrdTCB4ktY4,4516
|
|
192
|
+
plain-0.80.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
193
|
+
plain-0.80.0.dist-info/entry_points.txt,sha256=1Ys2lsSeMepD1vz8RSrJopna0RQfUd951vYvCRsvl6A,45
|
|
194
|
+
plain-0.80.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
|
|
195
|
+
plain-0.80.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|