plain 0.19.1__py3-none-any.whl → 0.21.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.
plain/assets/compile.py CHANGED
@@ -5,7 +5,7 @@ import shutil
5
5
 
6
6
  from plain.runtime import settings
7
7
 
8
- from .finders import find_assets
8
+ from .finders import iter_assets
9
9
  from .fingerprints import AssetsFingerprintsManifest
10
10
 
11
11
  FINGERPRINT_LENGTH = 7
@@ -54,7 +54,8 @@ def get_compiled_path():
54
54
  def compile_assets(*, target_dir, keep_original, fingerprint, compress):
55
55
  manifest = AssetsFingerprintsManifest()
56
56
 
57
- for url_path, asset in find_assets().items():
57
+ for asset in iter_assets():
58
+ url_path = asset.url_path
58
59
  resolved_path, compiled_paths = compile_asset(
59
60
  asset=asset,
60
61
  target_dir=target_dir,
plain/assets/finders.py CHANGED
@@ -8,9 +8,7 @@ APP_ASSETS_DIR = APP_PATH / "assets"
8
8
  SKIP_ASSETS = (".DS_Store", ".gitignore")
9
9
 
10
10
 
11
- def find_assets():
12
- assets_map = {}
13
-
11
+ def iter_assets():
14
12
  class Asset:
15
13
  def __init__(self, *, url_path, absolute_path):
16
14
  self.url_path = url_path
@@ -19,7 +17,7 @@ def find_assets():
19
17
  def __str__(self):
20
18
  return self.url_path
21
19
 
22
- def iter_directory(path):
20
+ def _iter_assets_dir(path):
23
21
  for root, _, files in os.walk(path):
24
22
  for f in files:
25
23
  if f in SKIP_ASSETS:
@@ -28,14 +26,17 @@ def find_assets():
28
26
  url_path = os.path.relpath(abs_path, path)
29
27
  yield url_path, abs_path
30
28
 
29
+ for asset_dir in iter_asset_dirs():
30
+ for url_path, abs_path in _iter_assets_dir(asset_dir):
31
+ yield Asset(url_path=url_path, absolute_path=abs_path)
32
+
33
+
34
+ def iter_asset_dirs():
31
35
  # Iterate the installed package assets, in order
32
36
  for pkg in packages.get_package_configs():
33
- pkg_assets_dir = os.path.join(pkg.path, "assets")
34
- for url_path, abs_path in iter_directory(pkg_assets_dir):
35
- assets_map[url_path] = Asset(url_path=url_path, absolute_path=abs_path)
37
+ asset_dir = os.path.join(pkg.path, "assets")
38
+ if os.path.exists(asset_dir):
39
+ yield asset_dir
36
40
 
37
41
  # The app/assets take priority over everything
38
- for url_path, abs_path in iter_directory(APP_ASSETS_DIR):
39
- assets_map[url_path] = Asset(url_path=url_path, absolute_path=abs_path)
40
-
41
- return assets_map
42
+ yield APP_ASSETS_DIR
plain/assets/views.py CHANGED
@@ -17,7 +17,7 @@ from plain.urls import reverse
17
17
  from plain.views import View
18
18
 
19
19
  from .compile import FINGERPRINT_LENGTH, get_compiled_path
20
- from .finders import find_assets
20
+ from .finders import iter_assets
21
21
  from .fingerprints import get_fingerprinted_url_path
22
22
 
23
23
 
@@ -80,8 +80,9 @@ class AssetView(View):
80
80
 
81
81
  def get_debug_asset_path(self, path):
82
82
  """Make a "live" check to find the uncompiled asset in the filesystem"""
83
- if asset := find_assets().get(path):
84
- return asset.absolute_path
83
+ for asset in iter_assets():
84
+ if asset.url_path == path:
85
+ return asset.absolute_path
85
86
 
86
87
  def check_asset_path(self, path):
87
88
  if not path:
plain/http/README.md CHANGED
@@ -1 +1,3 @@
1
1
  # HTTP
2
+
3
+ The `plain.http` package provides classes and utilities for handling HTTP requests and responses in Plain applications. It includes essential components like `HttpRequest`, `Response`, and tools for parsing multipart form data.
@@ -14,11 +14,16 @@ logger = logging.getLogger("plain.request")
14
14
 
15
15
 
16
16
  # These middleware classes are always used by Plain.
17
- BUILTIN_MIDDLEWARE = [
18
- "plain.internal.middleware.headers.DefaultHeadersMiddleware",
19
- "plain.internal.middleware.https.HttpsRedirectMiddleware",
17
+ BUILTIN_BEFORE_MIDDLEWARE = [
18
+ "plain.internal.middleware.headers.DefaultHeadersMiddleware", # Runs after response, to set missing headers
19
+ "plain.internal.middleware.https.HttpsRedirectMiddleware", # Runs before response, to redirect to HTTPS quickly
20
+ "plain.csrf.middleware.CsrfViewMiddleware", # Runs before and after get_response...
21
+ ]
22
+
23
+ BUILTIN_AFTER_MIDDLEWARE = [
24
+ # Want this to run first (when reversed) so the slash middleware
25
+ # can immediately redirect to the slash-appended path if there is one.
20
26
  "plain.internal.middleware.slash.RedirectSlashMiddleware",
21
- "plain.csrf.middleware.CsrfViewMiddleware",
22
27
  ]
23
28
 
24
29
 
@@ -34,7 +39,9 @@ class BaseHandler:
34
39
  get_response = self._get_response
35
40
  handler = convert_exception_to_response(get_response)
36
41
 
37
- middlewares = reversed(BUILTIN_MIDDLEWARE + settings.MIDDLEWARE)
42
+ middlewares = reversed(
43
+ BUILTIN_BEFORE_MIDDLEWARE + settings.MIDDLEWARE + BUILTIN_AFTER_MIDDLEWARE
44
+ )
38
45
 
39
46
  for middleware_path in middlewares:
40
47
  middleware = import_string(middleware_path)
plain/preflight/README.md CHANGED
@@ -1,3 +1,5 @@
1
1
  # Checks
2
2
 
3
- Static system checks to catch misconfigurations.
3
+ Static system checks to catch misconfigurations in your Plain application.
4
+
5
+ Preflight checks help identify issues with your settings or environment before deployment.
plain/views/objects.py CHANGED
@@ -80,6 +80,8 @@ class CreateView(ObjectTemplateViewMixin, FormView):
80
80
  View for creating a new object, with a response rendered by a template.
81
81
  """
82
82
 
83
+ template_name_suffix = "_form"
84
+
83
85
  def post(self) -> Response:
84
86
  """
85
87
  Handle POST requests: instantiate a form instance with the passed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain
3
- Version: 0.19.1
3
+ Version: 0.21.0
4
4
  Summary: A web framework for building products with Python.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-File: LICENSE
@@ -9,11 +9,11 @@ plain/validators.py,sha256=2tZh2Bvp955gejltwVtFGwfqw5-9VAOhKqos3Me4paY,19923
9
9
  plain/wsgi.py,sha256=R6k5FiAElvGDApEbMPTT0MPqSD7n2e2Az5chQqJZU0I,236
10
10
  plain/assets/README.md,sha256=048BzyQ2-BcsRiv6NiuLHHijOw96RK-e6lJ_Eq7g2pc,2857
11
11
  plain/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- plain/assets/compile.py,sha256=lsnciN85YjHe6d8VIKJi1L8r7NGHNzMOe9L87wObM5I,3287
13
- plain/assets/finders.py,sha256=WEKAnXTmpuQ7UKLZz7vHPrKFdDOkuZSP6_JTKmIxrKg,1268
12
+ plain/assets/compile.py,sha256=_FSWTg2JBFKLnUoOjpioV4EtiH8DH7F_3zYhM6zI4JU,3303
13
+ plain/assets/finders.py,sha256=wMa0GUi4S5SUXKcWSqEesMgU4NbXXDrC4SMJwDakwNc,1215
14
14
  plain/assets/fingerprints.py,sha256=1NKAnnXVlncY5iimXztr0NL3RIjBKsNlZRIe6nmItJc,931
15
15
  plain/assets/urls.py,sha256=ZTIoM1Zq35JaXZ3wFhXhfGa7VoITDNlH9i5RS0R5xow,933
16
- plain/assets/views.py,sha256=2Y2KVJinlaMBB2ZyMAVPj_ejuMv3cCO079TN8lSsbd8,9237
16
+ plain/assets/views.py,sha256=WaWLUjLGXY60gJV0RK34PNrEssJU-N0dFoISHt4nyFU,9271
17
17
  plain/cli/README.md,sha256=TvWCnNwb1rNthPzJglCRMKacN5H_RLeEjYBMe62Uz4M,2461
18
18
  plain/cli/__init__.py,sha256=9ByBOIdM8DebChjNz-RH2atdz4vWe8somlwNEsbhwh4,40
19
19
  plain/cli/cli.py,sha256=UNWIVnx2r2qn-eZejh2F_UA9C80HDNFysDd1rAWh2K4,14593
@@ -30,7 +30,7 @@ plain/forms/boundfield.py,sha256=LhydhCVR0okrli0-QBMjGjAJ8-06gTCXVEaBZhBouQk,174
30
30
  plain/forms/exceptions.py,sha256=XCLDRl5snIEDu5-8mLB0NnU_tegcBfyIHMiJxqvbxnc,164
31
31
  plain/forms/fields.py,sha256=86ZE9jac6Zyg5vKsYGgyOUOIQLKxO--UomGXwA65tk4,35103
32
32
  plain/forms/forms.py,sha256=CiONLo9VhE7E1-u-UejX4XWxxwu6MvR-lVPaVAY7VQM,10441
33
- plain/http/README.md,sha256=00zLFQ-FPjYXu3A8QsLhCCXxaT0ImvI5I-8xd3dp8WA,7
33
+ plain/http/README.md,sha256=HjEtoAhn14OoMdgb-wK-uc8No7C4d4gZUhzseOp7Fg4,236
34
34
  plain/http/__init__.py,sha256=DIsDRbBsCGa4qZgq-fUuQS0kkxfbTU_3KpIM9VvH04w,1067
35
35
  plain/http/cookie.py,sha256=11FnSG3Plo6T3jZDbPoCw7SKh9ExdBio3pTmIO03URg,597
36
36
  plain/http/multipartparser.py,sha256=k6BhpilFENQQ1cuGix6aa-jGwbhBVms2A2O01-s3_4c,27304
@@ -47,7 +47,7 @@ plain/internal/files/uploadedfile.py,sha256=JRB7T3quQjg-1y3l1ASPxywtSQZhaeMc45uF
47
47
  plain/internal/files/uploadhandler.py,sha256=eEnd5onstypjHYtg367PnVWwCaF1kAPlLPSV7goIf_E,7198
48
48
  plain/internal/files/utils.py,sha256=xN4HTJXDRdcoNyrL1dFd528MBwodRlHZM8DGTD_oBIg,2646
49
49
  plain/internal/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- plain/internal/handlers/base.py,sha256=_1aRNrNgqdx8kkUlXYRJNOTnZ_Z236JNYNcTdp7RRjc,4228
50
+ plain/internal/handlers/base.py,sha256=M9P3f5JaMmGxzxW7b6p72zAHxFXHuNl57aRcmRCMoWo,4609
51
51
  plain/internal/handlers/exception.py,sha256=DH9gh1FyqgetFpMaB8yLIVE6phBTVPKQLA1GIn9MOeI,4555
52
52
  plain/internal/handlers/wsgi.py,sha256=estA1QKHTk3ZqziWxenHsw5UO2cwPp3Zr0XjkDeM5TY,7561
53
53
  plain/internal/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -63,7 +63,7 @@ plain/packages/README.md,sha256=Vq1Nw3mmEmZ2IriQavuVi4BjcQC2nb8k7YIbnm8QjIg,799
63
63
  plain/packages/__init__.py,sha256=DnHN1wwHXiXib4Y9BV__x9WrbUaTovoTIxW-tVyScTU,106
64
64
  plain/packages/config.py,sha256=-je13ViDkXMEQXCSi0G539dG5_HPoFBKaK7cBEd_NAY,11070
65
65
  plain/packages/registry.py,sha256=C1yv-JlzMs4HE-AYam_EdiTKNQwE8IN4qgt22PKxHDE,17920
66
- plain/preflight/README.md,sha256=fgcfVRD6rq7IO8AffQhk49c-6akxaE8MQidRp69InDQ,59
66
+ plain/preflight/README.md,sha256=-PKVd0RBMh4ROiMkegPS2PgvT1Kq9qqN1KfNkmUSdFc,177
67
67
  plain/preflight/__init__.py,sha256=H-TNRvaddPtOGmv4RXoc1fxDV1AOb7_K3u7ECF8mV58,607
68
68
  plain/preflight/files.py,sha256=wbHCNgps7o1c1zQNBd8FDCaVaqX90UwuvLgEQ_DbUpY,510
69
69
  plain/preflight/messages.py,sha256=HwatjA6MRFfzFAnSOa_uAw1Pvk_CLuNfW3IYi71_1Mk,2322
@@ -135,11 +135,11 @@ plain/views/csrf.py,sha256=7q6l5xzLWhRnMY64aNj0hR6G-3pxI2yhRwG6k_5j00E,144
135
135
  plain/views/errors.py,sha256=Y4oGX4Z6D2COKcDEfINvXE1acE8Ad15KwNNWPs5BCfc,967
136
136
  plain/views/exceptions.py,sha256=b4euI49ZUKS9O8AGAcFfiDpstzkRAuuj_uYQXzWNHME,138
137
137
  plain/views/forms.py,sha256=RhlaUcZCkeqokY_fvv-NOS-kgZAG4XhDLOPbf9K_Zlc,2691
138
- plain/views/objects.py,sha256=fRfS6KNehIGqkbPw4nSafj8HStxYExHmbggolBbzcxs,7921
138
+ plain/views/objects.py,sha256=LfYEbBWLTmwvEcJlcsWlD0DO29QWIYRt2h8quvq46cE,7957
139
139
  plain/views/redirect.py,sha256=KLnlktzK6ZNMTlaEiZpMKQMEP5zeTgGLJ9BIkIJfwBo,1733
140
140
  plain/views/templates.py,sha256=nF9CcdhhjAyp3LB0RrSYnBaHpHzMfPSw719RCdcXk7o,2007
141
- plain-0.19.1.dist-info/METADATA,sha256=RlzXMJklCiL5RItFRnMBVVGWkv5DJ4mZWNWAQiTrToY,2518
142
- plain-0.19.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
143
- plain-0.19.1.dist-info/entry_points.txt,sha256=DHHprvufgd7xypiBiqMANYRnpJ9xPPYhYbnPGwOkWqE,40
144
- plain-0.19.1.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
145
- plain-0.19.1.dist-info/RECORD,,
141
+ plain-0.21.0.dist-info/METADATA,sha256=LtYn44-bRq4_6avgmAO4ZCrSVHbEKo4upBXusnOOLr8,2518
142
+ plain-0.21.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
143
+ plain-0.21.0.dist-info/entry_points.txt,sha256=DHHprvufgd7xypiBiqMANYRnpJ9xPPYhYbnPGwOkWqE,40
144
+ plain-0.21.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
145
+ plain-0.21.0.dist-info/RECORD,,
File without changes