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.
- plain/CHANGELOG.md +684 -0
- plain/README.md +1 -1
- plain/assets/compile.py +25 -12
- plain/assets/finders.py +24 -17
- plain/assets/fingerprints.py +10 -7
- plain/assets/urls.py +1 -1
- plain/assets/views.py +47 -33
- plain/chores/README.md +25 -23
- plain/chores/__init__.py +2 -1
- plain/chores/core.py +27 -0
- plain/chores/registry.py +23 -53
- plain/cli/README.md +185 -16
- plain/cli/__init__.py +2 -1
- plain/cli/agent.py +236 -0
- plain/cli/build.py +7 -8
- plain/cli/changelog.py +11 -5
- plain/cli/chores.py +32 -34
- plain/cli/core.py +112 -28
- plain/cli/docs.py +52 -11
- plain/cli/formatting.py +40 -17
- plain/cli/install.py +10 -54
- plain/cli/{agent/llmdocs.py → llmdocs.py} +21 -9
- plain/cli/output.py +6 -2
- plain/cli/preflight.py +175 -102
- plain/cli/print.py +4 -4
- plain/cli/registry.py +95 -26
- plain/cli/request.py +206 -0
- plain/cli/runtime.py +45 -0
- plain/cli/scaffold.py +2 -7
- plain/cli/server.py +153 -0
- plain/cli/settings.py +53 -49
- plain/cli/shell.py +15 -12
- plain/cli/startup.py +9 -8
- plain/cli/upgrade.py +17 -104
- plain/cli/urls.py +12 -7
- plain/cli/utils.py +3 -3
- plain/csrf/README.md +65 -40
- plain/csrf/middleware.py +53 -43
- plain/debug.py +5 -2
- plain/exceptions.py +22 -114
- plain/forms/README.md +453 -24
- plain/forms/__init__.py +55 -4
- plain/forms/boundfield.py +15 -8
- plain/forms/exceptions.py +1 -1
- plain/forms/fields.py +346 -143
- plain/forms/forms.py +75 -45
- plain/http/README.md +356 -9
- plain/http/__init__.py +41 -26
- plain/http/cookie.py +15 -7
- plain/http/exceptions.py +65 -0
- plain/http/middleware.py +32 -0
- plain/http/multipartparser.py +99 -88
- plain/http/request.py +362 -250
- plain/http/response.py +99 -197
- plain/internal/__init__.py +8 -1
- plain/internal/files/base.py +35 -19
- plain/internal/files/locks.py +19 -11
- plain/internal/files/move.py +8 -3
- plain/internal/files/temp.py +25 -6
- plain/internal/files/uploadedfile.py +47 -28
- plain/internal/files/uploadhandler.py +64 -58
- plain/internal/files/utils.py +24 -10
- plain/internal/handlers/base.py +34 -23
- plain/internal/handlers/exception.py +68 -65
- plain/internal/handlers/wsgi.py +65 -54
- plain/internal/middleware/headers.py +37 -11
- plain/internal/middleware/hosts.py +11 -13
- plain/internal/middleware/https.py +17 -7
- plain/internal/middleware/slash.py +14 -9
- plain/internal/reloader.py +77 -0
- plain/json.py +2 -1
- plain/logs/README.md +161 -62
- plain/logs/__init__.py +1 -1
- plain/logs/{loggers.py → app.py} +71 -67
- plain/logs/configure.py +63 -14
- plain/logs/debug.py +17 -6
- plain/logs/filters.py +15 -0
- plain/logs/formatters.py +7 -4
- plain/packages/README.md +105 -23
- plain/packages/config.py +15 -7
- plain/packages/registry.py +40 -15
- plain/paginator.py +31 -21
- plain/preflight/README.md +208 -23
- plain/preflight/__init__.py +5 -24
- plain/preflight/checks.py +12 -0
- plain/preflight/files.py +19 -13
- plain/preflight/registry.py +80 -58
- plain/preflight/results.py +37 -0
- plain/preflight/security.py +65 -71
- plain/preflight/settings.py +54 -0
- plain/preflight/urls.py +10 -48
- plain/runtime/README.md +115 -47
- plain/runtime/__init__.py +10 -6
- plain/runtime/global_settings.py +43 -33
- plain/runtime/secret.py +20 -0
- plain/runtime/user_settings.py +110 -38
- plain/runtime/utils.py +1 -1
- plain/server/LICENSE +35 -0
- plain/server/README.md +155 -0
- plain/server/__init__.py +9 -0
- plain/server/app.py +52 -0
- plain/server/arbiter.py +555 -0
- plain/server/config.py +118 -0
- plain/server/errors.py +31 -0
- plain/server/glogging.py +292 -0
- plain/server/http/__init__.py +12 -0
- plain/server/http/body.py +283 -0
- plain/server/http/errors.py +155 -0
- plain/server/http/message.py +400 -0
- plain/server/http/parser.py +70 -0
- plain/server/http/unreader.py +88 -0
- plain/server/http/wsgi.py +421 -0
- plain/server/pidfile.py +92 -0
- plain/server/sock.py +240 -0
- plain/server/util.py +317 -0
- plain/server/workers/__init__.py +6 -0
- plain/server/workers/base.py +304 -0
- plain/server/workers/sync.py +212 -0
- plain/server/workers/thread.py +399 -0
- plain/server/workers/workertmp.py +50 -0
- plain/signals/README.md +170 -1
- plain/signals/__init__.py +0 -1
- plain/signals/dispatch/dispatcher.py +49 -27
- plain/signing.py +131 -35
- plain/skills/README.md +36 -0
- plain/skills/plain-docs/SKILL.md +25 -0
- plain/skills/plain-install/SKILL.md +26 -0
- plain/skills/plain-request/SKILL.md +39 -0
- plain/skills/plain-shell/SKILL.md +24 -0
- plain/skills/plain-upgrade/SKILL.md +35 -0
- plain/templates/README.md +211 -20
- plain/templates/jinja/__init__.py +14 -27
- plain/templates/jinja/environments.py +5 -4
- plain/templates/jinja/extensions.py +12 -5
- plain/templates/jinja/filters.py +7 -2
- plain/templates/jinja/globals.py +2 -2
- plain/test/README.md +184 -22
- plain/test/client.py +340 -222
- plain/test/encoding.py +9 -6
- plain/test/exceptions.py +7 -2
- plain/urls/README.md +157 -73
- plain/urls/converters.py +18 -15
- plain/urls/exceptions.py +2 -2
- plain/urls/patterns.py +56 -40
- plain/urls/resolvers.py +38 -28
- plain/urls/utils.py +5 -1
- plain/utils/README.md +250 -3
- plain/utils/cache.py +17 -11
- plain/utils/crypto.py +21 -5
- plain/utils/datastructures.py +89 -56
- plain/utils/dateparse.py +9 -6
- plain/utils/deconstruct.py +15 -7
- plain/utils/decorators.py +5 -1
- plain/utils/dotenv.py +373 -0
- plain/utils/duration.py +8 -4
- plain/utils/encoding.py +14 -7
- plain/utils/functional.py +66 -49
- plain/utils/hashable.py +5 -1
- plain/utils/html.py +36 -22
- plain/utils/http.py +16 -9
- plain/utils/inspect.py +14 -6
- plain/utils/ipv6.py +7 -3
- plain/utils/itercompat.py +6 -1
- plain/utils/module_loading.py +7 -3
- plain/utils/regex_helper.py +37 -23
- plain/utils/safestring.py +14 -6
- plain/utils/text.py +41 -23
- plain/utils/timezone.py +33 -22
- plain/utils/tree.py +35 -19
- plain/validators.py +94 -52
- plain/views/README.md +156 -79
- plain/views/__init__.py +0 -1
- plain/views/base.py +25 -18
- plain/views/errors.py +13 -5
- plain/views/exceptions.py +4 -1
- plain/views/forms.py +6 -6
- plain/views/objects.py +52 -49
- plain/views/redirect.py +18 -15
- plain/views/templates.py +5 -3
- plain/wsgi.py +3 -1
- {plain-0.66.0.dist-info → plain-0.101.2.dist-info}/METADATA +4 -2
- plain-0.101.2.dist-info/RECORD +201 -0
- {plain-0.66.0.dist-info → plain-0.101.2.dist-info}/WHEEL +1 -1
- plain-0.101.2.dist-info/entry_points.txt +2 -0
- plain/AGENTS.md +0 -18
- plain/cli/agent/__init__.py +0 -20
- plain/cli/agent/docs.py +0 -80
- plain/cli/agent/md.py +0 -87
- plain/cli/agent/prompt.py +0 -45
- plain/cli/agent/request.py +0 -181
- plain/csrf/views.py +0 -31
- plain/logs/utils.py +0 -46
- plain/preflight/messages.py +0 -81
- plain/templates/AGENTS.md +0 -3
- plain-0.66.0.dist-info/RECORD +0 -168
- plain-0.66.0.dist-info/entry_points.txt +0 -4
- {plain-0.66.0.dist-info → plain-0.101.2.dist-info}/licenses/LICENSE +0 -0
plain/views/objects.py
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
1
2
|
from functools import cached_property
|
|
2
3
|
from typing import Any
|
|
3
4
|
|
|
4
|
-
from plain.exceptions import ImproperlyConfigured
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
from plain.exceptions import ImproperlyConfigured
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from plain.models.exceptions import ObjectDoesNotExist
|
|
9
|
+
except ImportError:
|
|
10
|
+
ObjectDoesNotExist = None # type: ignore[misc, assignment]
|
|
11
|
+
|
|
12
|
+
from plain.forms import BaseForm, Form
|
|
13
|
+
from plain.http import NotFoundError404
|
|
7
14
|
|
|
8
15
|
from .forms import FormView
|
|
9
16
|
from .templates import TemplateView
|
|
@@ -15,10 +22,10 @@ class CreateView(FormView):
|
|
|
15
22
|
"""
|
|
16
23
|
|
|
17
24
|
# TODO? would rather you have to specify this...
|
|
18
|
-
def get_success_url(self, form):
|
|
25
|
+
def get_success_url(self, form: BaseForm) -> str:
|
|
19
26
|
"""Return the URL to redirect to after processing a valid form."""
|
|
20
27
|
if self.success_url:
|
|
21
|
-
url = self.success_url.format(**self.object.__dict__)
|
|
28
|
+
url = str(self.success_url).format(**self.object.__dict__)
|
|
22
29
|
else:
|
|
23
30
|
try:
|
|
24
31
|
url = self.object.get_absolute_url()
|
|
@@ -29,36 +36,45 @@ class CreateView(FormView):
|
|
|
29
36
|
)
|
|
30
37
|
return url
|
|
31
38
|
|
|
32
|
-
def form_valid(self, form):
|
|
39
|
+
def form_valid(self, form: BaseForm) -> Any:
|
|
33
40
|
"""If the form is valid, save the associated model."""
|
|
34
|
-
self.object = form.save()
|
|
41
|
+
self.object = form.save() # type: ignore[attr-defined]
|
|
35
42
|
return super().form_valid(form)
|
|
36
43
|
|
|
37
44
|
|
|
38
|
-
class
|
|
45
|
+
class DetailView(TemplateView, ABC):
|
|
46
|
+
"""
|
|
47
|
+
Render a "detail" view of an object.
|
|
48
|
+
|
|
49
|
+
By default this is a model instance looked up from `self.queryset`, but the
|
|
50
|
+
view will support display of *any* object by overriding `self.get_object()`.
|
|
51
|
+
"""
|
|
52
|
+
|
|
39
53
|
context_object_name = ""
|
|
40
54
|
|
|
41
55
|
@cached_property
|
|
42
56
|
def object(self) -> Any:
|
|
43
57
|
try:
|
|
44
58
|
obj = self.get_object()
|
|
45
|
-
except
|
|
46
|
-
raise
|
|
59
|
+
except Exception as e:
|
|
60
|
+
# If ObjectDoesNotExist is available and this is that exception, raise 404
|
|
61
|
+
if ObjectDoesNotExist and isinstance(e, ObjectDoesNotExist):
|
|
62
|
+
raise NotFoundError404
|
|
63
|
+
# Otherwise, let other exceptions bubble up
|
|
64
|
+
raise
|
|
47
65
|
|
|
48
66
|
# Also raise 404 if get_object() returns None
|
|
49
67
|
if not obj:
|
|
50
|
-
raise
|
|
68
|
+
raise NotFoundError404
|
|
51
69
|
|
|
52
70
|
return obj
|
|
53
71
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
f"get_object() is not implemented on {self.__class__.__name__}"
|
|
57
|
-
)
|
|
72
|
+
@abstractmethod
|
|
73
|
+
def get_object(self) -> Any: ...
|
|
58
74
|
|
|
59
|
-
def get_template_context(self) -> dict:
|
|
75
|
+
def get_template_context(self) -> dict[str, Any]:
|
|
60
76
|
"""Insert the single object into the context dict."""
|
|
61
|
-
context = super().get_template_context()
|
|
77
|
+
context = super().get_template_context()
|
|
62
78
|
context["object"] = (
|
|
63
79
|
self.object
|
|
64
80
|
) # Some templates can benefit by always knowing a primary "object" can be present
|
|
@@ -67,24 +83,13 @@ class ObjectTemplateViewMixin:
|
|
|
67
83
|
return context
|
|
68
84
|
|
|
69
85
|
|
|
70
|
-
class DetailView
|
|
71
|
-
"""
|
|
72
|
-
Render a "detail" view of an object.
|
|
73
|
-
|
|
74
|
-
By default this is a model instance looked up from `self.queryset`, but the
|
|
75
|
-
view will support display of *any* object by overriding `self.get_object()`.
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
pass
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
class UpdateView(ObjectTemplateViewMixin, FormView):
|
|
86
|
+
class UpdateView(DetailView, FormView):
|
|
82
87
|
"""View for updating an object, with a response rendered by a template."""
|
|
83
88
|
|
|
84
|
-
def get_success_url(self, form):
|
|
89
|
+
def get_success_url(self, form: BaseForm) -> str:
|
|
85
90
|
"""Return the URL to redirect to after processing a valid form."""
|
|
86
91
|
if self.success_url:
|
|
87
|
-
url = self.success_url.format(**self.object.__dict__)
|
|
92
|
+
url = str(self.success_url).format(**self.object.__dict__)
|
|
88
93
|
else:
|
|
89
94
|
try:
|
|
90
95
|
url = self.object.get_absolute_url()
|
|
@@ -95,47 +100,47 @@ class UpdateView(ObjectTemplateViewMixin, FormView):
|
|
|
95
100
|
)
|
|
96
101
|
return url
|
|
97
102
|
|
|
98
|
-
def form_valid(self, form):
|
|
103
|
+
def form_valid(self, form: BaseForm) -> Any:
|
|
99
104
|
"""If the form is valid, save the associated model."""
|
|
100
|
-
form.save()
|
|
105
|
+
form.save() # type: ignore[attr-defined]
|
|
101
106
|
return super().form_valid(form)
|
|
102
107
|
|
|
103
|
-
def get_form_kwargs(self):
|
|
108
|
+
def get_form_kwargs(self) -> dict[str, Any]:
|
|
104
109
|
"""Return the keyword arguments for instantiating the form."""
|
|
105
110
|
kwargs = super().get_form_kwargs()
|
|
106
111
|
kwargs.update({"instance": self.object})
|
|
107
112
|
return kwargs
|
|
108
113
|
|
|
109
114
|
|
|
110
|
-
class DeleteView(
|
|
115
|
+
class DeleteView(DetailView, FormView):
|
|
111
116
|
"""
|
|
112
117
|
View for deleting an object retrieved with self.get_object(), with a
|
|
113
118
|
response rendered by a template.
|
|
114
119
|
"""
|
|
115
120
|
|
|
116
121
|
class EmptyDeleteForm(Form):
|
|
117
|
-
def __init__(self, instance
|
|
122
|
+
def __init__(self, instance: Any, **kwargs: Any) -> None:
|
|
118
123
|
self.instance = instance
|
|
119
|
-
super().__init__(
|
|
124
|
+
super().__init__(**kwargs)
|
|
120
125
|
|
|
121
|
-
def save(self):
|
|
126
|
+
def save(self) -> None:
|
|
122
127
|
self.instance.delete()
|
|
123
128
|
|
|
124
129
|
form_class = EmptyDeleteForm
|
|
125
130
|
|
|
126
|
-
def get_form_kwargs(self):
|
|
131
|
+
def get_form_kwargs(self) -> dict[str, Any]:
|
|
127
132
|
"""Return the keyword arguments for instantiating the form."""
|
|
128
133
|
kwargs = super().get_form_kwargs()
|
|
129
134
|
kwargs.update({"instance": self.object})
|
|
130
135
|
return kwargs
|
|
131
136
|
|
|
132
|
-
def form_valid(self, form):
|
|
137
|
+
def form_valid(self, form: BaseForm) -> Any:
|
|
133
138
|
"""If the form is valid, save the associated model."""
|
|
134
|
-
form.save()
|
|
139
|
+
form.save() # type: ignore[attr-defined]
|
|
135
140
|
return super().form_valid(form)
|
|
136
141
|
|
|
137
142
|
|
|
138
|
-
class ListView(TemplateView):
|
|
143
|
+
class ListView(TemplateView, ABC):
|
|
139
144
|
"""
|
|
140
145
|
Render some list of objects, set by `self.get_queryset()`, with a response
|
|
141
146
|
rendered by a template.
|
|
@@ -144,17 +149,15 @@ class ListView(TemplateView):
|
|
|
144
149
|
context_object_name = ""
|
|
145
150
|
|
|
146
151
|
@cached_property
|
|
147
|
-
def objects(self):
|
|
152
|
+
def objects(self) -> Any:
|
|
148
153
|
return self.get_objects()
|
|
149
154
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
f"get_objects() is not implemented on {self.__class__.__name__}"
|
|
153
|
-
)
|
|
155
|
+
@abstractmethod
|
|
156
|
+
def get_objects(self) -> Any: ...
|
|
154
157
|
|
|
155
|
-
def get_template_context(self) -> dict:
|
|
158
|
+
def get_template_context(self) -> dict[str, Any]:
|
|
156
159
|
"""Insert the single object into the context dict."""
|
|
157
|
-
context = super().get_template_context()
|
|
160
|
+
context = super().get_template_context()
|
|
158
161
|
context["objects"] = self.objects
|
|
159
162
|
if self.context_object_name:
|
|
160
163
|
context[self.context_object_name] = self.objects
|
plain/views/redirect.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from plain.http import
|
|
1
|
+
from plain.http import RedirectResponse
|
|
2
2
|
from plain.urls import reverse
|
|
3
3
|
|
|
4
4
|
from .base import View
|
|
@@ -13,8 +13,12 @@ class RedirectView(View):
|
|
|
13
13
|
preserve_query_params = False
|
|
14
14
|
|
|
15
15
|
def __init__(
|
|
16
|
-
self,
|
|
17
|
-
|
|
16
|
+
self,
|
|
17
|
+
url: str | None = None,
|
|
18
|
+
status_code: int | None = None,
|
|
19
|
+
url_name: str | None = None,
|
|
20
|
+
preserve_query_params: bool | None = None,
|
|
21
|
+
) -> None:
|
|
18
22
|
# Allow attributes to be set in RedirectView.as_view(url="...", status_code=301, etc.)
|
|
19
23
|
self.url = url or self.url
|
|
20
24
|
self.status_code = status_code if status_code is not None else self.status_code
|
|
@@ -25,7 +29,7 @@ class RedirectView(View):
|
|
|
25
29
|
else self.preserve_query_params
|
|
26
30
|
)
|
|
27
31
|
|
|
28
|
-
def get_redirect_url(self):
|
|
32
|
+
def get_redirect_url(self) -> str:
|
|
29
33
|
"""
|
|
30
34
|
Return the URL redirect to. Keyword arguments from the URL pattern
|
|
31
35
|
match generating the redirect request are provided as kwargs to this
|
|
@@ -38,29 +42,28 @@ class RedirectView(View):
|
|
|
38
42
|
else:
|
|
39
43
|
raise ValueError("RedirectView requires either url or url_name to be set")
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
url = f"{url}?{args}"
|
|
45
|
+
if self.preserve_query_params and self.request.query_string:
|
|
46
|
+
url = f"{url}?{self.request.query_string}"
|
|
44
47
|
return url
|
|
45
48
|
|
|
46
|
-
def get(self):
|
|
49
|
+
def get(self) -> RedirectResponse:
|
|
47
50
|
url = self.get_redirect_url()
|
|
48
|
-
return
|
|
51
|
+
return RedirectResponse(url, status_code=self.status_code)
|
|
49
52
|
|
|
50
|
-
def head(self):
|
|
53
|
+
def head(self) -> RedirectResponse:
|
|
51
54
|
return self.get()
|
|
52
55
|
|
|
53
|
-
def post(self):
|
|
56
|
+
def post(self) -> RedirectResponse:
|
|
54
57
|
return self.get()
|
|
55
58
|
|
|
56
|
-
def options(self):
|
|
59
|
+
def options(self) -> RedirectResponse:
|
|
57
60
|
return self.get()
|
|
58
61
|
|
|
59
|
-
def delete(self):
|
|
62
|
+
def delete(self) -> RedirectResponse:
|
|
60
63
|
return self.get()
|
|
61
64
|
|
|
62
|
-
def put(self):
|
|
65
|
+
def put(self) -> RedirectResponse:
|
|
63
66
|
return self.get()
|
|
64
67
|
|
|
65
|
-
def patch(self):
|
|
68
|
+
def patch(self) -> RedirectResponse:
|
|
66
69
|
return self.get()
|
plain/views/templates.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
1
3
|
from plain.exceptions import ImproperlyConfigured
|
|
2
4
|
from plain.http import Response
|
|
3
5
|
from plain.runtime import settings
|
|
@@ -13,11 +15,11 @@ class TemplateView(View):
|
|
|
13
15
|
|
|
14
16
|
template_name: str | None = None
|
|
15
17
|
|
|
16
|
-
def __init__(self, template_name=None):
|
|
18
|
+
def __init__(self, template_name: str | None = None) -> None:
|
|
17
19
|
# Allow template_name to be passed in as_view()
|
|
18
20
|
self.template_name = template_name or self.template_name
|
|
19
21
|
|
|
20
|
-
def get_template_context(self) -> dict:
|
|
22
|
+
def get_template_context(self) -> dict[str, Any]:
|
|
21
23
|
return {
|
|
22
24
|
"request": self.request,
|
|
23
25
|
"template_names": self.get_template_names(),
|
|
@@ -58,5 +60,5 @@ class TemplateView(View):
|
|
|
58
60
|
def render_template(self) -> str:
|
|
59
61
|
return self.get_template().render(self.get_template_context())
|
|
60
62
|
|
|
61
|
-
def get(self) -> Response:
|
|
63
|
+
def get(self) -> Response | Any:
|
|
62
64
|
return Response(self.render_template())
|
plain/wsgi.py
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plain
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.101.2
|
|
4
4
|
Summary: A web framework for building products with Python.
|
|
5
5
|
Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
6
7
|
License-File: LICENSE
|
|
7
8
|
Requires-Python: >=3.13
|
|
8
9
|
Requires-Dist: click>=8.0.0
|
|
9
10
|
Requires-Dist: jinja2>=3.1.2
|
|
10
11
|
Requires-Dist: opentelemetry-api>=1.34.1
|
|
11
12
|
Requires-Dist: opentelemetry-semantic-conventions>=0.55b1
|
|
13
|
+
Requires-Dist: watchfiles>=0.18.0
|
|
12
14
|
Description-Content-Type: text/markdown
|
|
13
15
|
|
|
14
16
|
# Plain
|
|
@@ -44,7 +46,7 @@ The `plain` package includes everything you need to start handling web requests
|
|
|
44
46
|
- [plain.cache](/plain-cache/plain/cache/README.md) - A database-driven general purpose cache.
|
|
45
47
|
- [plain.email](/plain-email/plain/email/README.md) - Send emails with SMTP or custom backends.
|
|
46
48
|
- [plain.sessions](/plain-sessions/plain/sessions/README.md) - User sessions and cookies.
|
|
47
|
-
- [plain.
|
|
49
|
+
- [plain.jobs](/plain-jobs/plain/jobs/README.md) - Background jobs stored in the database.
|
|
48
50
|
- [plain.api](/plain-api/plain/api/README.md) - Build APIs with Plain views.
|
|
49
51
|
|
|
50
52
|
## Auth Packages
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
plain/CHANGELOG.md,sha256=hvYn3NacP4SzrolTGeNiW9GT4__mq84UI2pxdZtpMfw,55077
|
|
2
|
+
plain/README.md,sha256=VvzhXNvf4I6ddmjBP9AExxxFXxs7RwyoxdgFm-W5dsg,4072
|
|
3
|
+
plain/__main__.py,sha256=GK39854Lc_LO_JP8DzY9Y2MIQ4cQEl7SXFJy244-lC8,110
|
|
4
|
+
plain/debug.py,sha256=C2OnFHtRGMrpCiHSt-P2r58JypgQZ62qzDBpV4mhtFM,855
|
|
5
|
+
plain/exceptions.py,sha256=zV_HXXrxA11YwP0CVHLTPd_5YA7N311V32lFrO3LtB4,4523
|
|
6
|
+
plain/json.py,sha256=SC0CWPBhlQs3F_xlMcvZGUGxVBEMqA378uqIC3Q00aI,1297
|
|
7
|
+
plain/paginator.py,sha256=uModWWSnXISNt1Ecb5C17yoaKiTcHltFHLrfqQ-lio0,6240
|
|
8
|
+
plain/signing.py,sha256=aFwfZew9Ot7_26F88wSOU82MdNUQ3i1A7kI1qKS1q-4,11634
|
|
9
|
+
plain/validators.py,sha256=JBeycZFilWs69ai-QQb_4snpDgs1fjMGT0ICwVB1mvE,21297
|
|
10
|
+
plain/wsgi.py,sha256=MWQ09DFNV2GxX752hYJMWka9LTEwzCp6XEC_4TdXF9g,287
|
|
11
|
+
plain/assets/README.md,sha256=iRZHHoXZCEFooXoDYSomF12XTcDFl7oNbRHpAFwxTM8,4349
|
|
12
|
+
plain/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
plain/assets/compile.py,sha256=a-e_nKHJLN3fOp9nw1MF7f7oP6q5qX8oYelowXKb_EE,3587
|
|
14
|
+
plain/assets/finders.py,sha256=Ldcn3bB3opab1AhRHef1arMEjOYDXH9TAt8sLYyieo0,1689
|
|
15
|
+
plain/assets/fingerprints.py,sha256=efOh65ueJxEP73teil_e_5wvn6K8kCzCi3RgPdT9pik,1515
|
|
16
|
+
plain/assets/urls.py,sha256=Qe0ctXYAQjAlLIKuX6JeLVBOFqzJxggR0RSGkRXmX78,1173
|
|
17
|
+
plain/assets/views.py,sha256=wVhFn4wIYzYwZN26HmgFgbNXHs4CmGZkc7tWB6mPQHk,10383
|
|
18
|
+
plain/chores/README.md,sha256=7Dv5MCyqPaohQxAk74HRzKiTvt_yR-IOhbu7R5bdz6M,2437
|
|
19
|
+
plain/chores/__init__.py,sha256=wEdt-oAKS1kz7Ln-puhcCt8XGNdfCP4S3wHESaPU8nI,100
|
|
20
|
+
plain/chores/core.py,sha256=BxsCSJDQvMjYsAH4QhEoW9ZUEAUIwJgTYyHovPGSLjk,578
|
|
21
|
+
plain/chores/registry.py,sha256=IRpx3f6Z1qlqcEpHTe6O6JocNmaplLu7BVOqGrafSXU,1221
|
|
22
|
+
plain/cli/README.md,sha256=8OmOhvKvgFkndwGn8lW6q62mvIB6Zq_NAhEhBf7PVV0,6305
|
|
23
|
+
plain/cli/__init__.py,sha256=o-dmnnNmXM3fZrKwW1qcoAPlcfG5pcFTFYWEBCocf8A,117
|
|
24
|
+
plain/cli/agent.py,sha256=ApEeJRWt_oTksuURvmSTHHe1_eIKWe_2AtqYV20U8hc,8212
|
|
25
|
+
plain/cli/build.py,sha256=UxgyAris4xtOZYS4FLMIOQLQ9DflHZkkenUJ650kZuA,3142
|
|
26
|
+
plain/cli/changelog.py,sha256=ckuP99HtnUSJXf_AELWgmD9S0XjldCzh5urxPiDpRcI,3647
|
|
27
|
+
plain/cli/chores.py,sha256=jhLKxFs_YpyQDvo5chNGiKnFc2_KK5atq53EpkGmMo0,2542
|
|
28
|
+
plain/cli/core.py,sha256=_Kg_YnYeDZB3EKlzdejl4eJepzRd2aF1LSs0Ei2uCI8,6923
|
|
29
|
+
plain/cli/docs.py,sha256=wC9ShvzCwJZoymV8G_Rs4AaPEU-_Eh-EkI0OFYJxKKA,2599
|
|
30
|
+
plain/cli/formatting.py,sha256=t0kxJ-r-his8kGcY38g38p699CfFGUgqEI1tJkEbjGs,3802
|
|
31
|
+
plain/cli/install.py,sha256=28lXobloqqN50duuKlUqalAmNHUJdz-JlYYmdpXpzCs,1260
|
|
32
|
+
plain/cli/llmdocs.py,sha256=xI2ta85zSEmVJePqrecxPd4EDhRSSY29pwSGor1DNJc,5599
|
|
33
|
+
plain/cli/output.py,sha256=uZTHZR-Axeoi2r6fgcDCpDA7iQSRrktBtTf1yBT5djI,1426
|
|
34
|
+
plain/cli/preflight.py,sha256=zWnw9RFmN0CQQByAB2vWLbwlDNrQzUQTtKKySVzRucE,7036
|
|
35
|
+
plain/cli/print.py,sha256=s_yNxtA4vg-AWn4C9TtFH-gOMnzMsXuEr7ak4-oOFPI,265
|
|
36
|
+
plain/cli/registry.py,sha256=Xk6uwVT0j0GeweFtYd4k4PnxXs6-jDLjEl-fFd0_e5Y,3849
|
|
37
|
+
plain/cli/request.py,sha256=vHtVN50in7Z3OQFxr-ezHRPYPn46koWQ3-2ITbDY22Y,6680
|
|
38
|
+
plain/cli/runtime.py,sha256=xpGBlLV70VC541DpyKL4cwqiL2xr8xz_cCuSZ3RC33s,1124
|
|
39
|
+
plain/cli/scaffold.py,sha256=v0bbtelz8-j2LP48W0uXvL1xgZ9ce6IfAYDxqKXqesk,1203
|
|
40
|
+
plain/cli/server.py,sha256=2MIy5TwzqhZMzy-wPUlNqAhOTlsnR1ZYh6Ja9eghXJM,3637
|
|
41
|
+
plain/cli/settings.py,sha256=aVGttxVIpVmxE-vfOW4r3JCLWlhZEA65SwHl6SfUSv8,1916
|
|
42
|
+
plain/cli/shell.py,sha256=QOh2g4bkkdWdR6VxUQogqgh1ehHFPqi5gAS9DsviRvY,1946
|
|
43
|
+
plain/cli/startup.py,sha256=sdnIpCP1ruyMtZFoVf1sff9sb5IE44pyoAuGc7nYTXI,1105
|
|
44
|
+
plain/cli/upgrade.py,sha256=rQMSIgkWBdO3F9Fgv2279y6cKeZE52kPoAbrUmVrybk,2375
|
|
45
|
+
plain/cli/urls.py,sha256=hKzRfXxZxUT4ePDMThEvy-X9XNqfIeVhrxK2vAEqjbI,3976
|
|
46
|
+
plain/cli/utils.py,sha256=CuEAN41fmxr0KS_Rek_9zWri6frh8MkJUrmN-JVAfEo,292
|
|
47
|
+
plain/csrf/README.md,sha256=plU22iqc2XOxrZ1ipRlrZf6evIxGZBluudRGJqUJzic,5130
|
|
48
|
+
plain/csrf/middleware.py,sha256=A4Ko6K0rBYo3IdizRuZZgoALqOIsbTbdd5QkFOi5KiA,6038
|
|
49
|
+
plain/forms/README.md,sha256=IDRkWVxjipTvhhOW6fnVeNj-MJ7CKGZ-P71QfE0mlqE,13445
|
|
50
|
+
plain/forms/__init__.py,sha256=gZrZY-_se_8PRgu3MwkSaYQ3S9YC-neZugMI0U1VvIg,1075
|
|
51
|
+
plain/forms/boundfield.py,sha256=Wkzo_4w_G4d372oxCGGDhwhggaA7boPmoHbRgDhOjNA,1991
|
|
52
|
+
plain/forms/exceptions.py,sha256=MuMUF-33Qsc_HWk5zI3rcWzdvXzQbEOKAZvJKkbrL58,320
|
|
53
|
+
plain/forms/fields.py,sha256=RE3erdMUyN5wPPT7HXuQ9UJNfi5uT-Od1r1GTzefBz0,42313
|
|
54
|
+
plain/forms/forms.py,sha256=ZMTCpZUzq3kwP7L-RkStfuw9FqkH90a6DsH_8n4AXfU,11976
|
|
55
|
+
plain/http/README.md,sha256=PFLkg8aljvdzZeXYiG9zxIZzE4_DwqjFHpgC_eu_XYA,9428
|
|
56
|
+
plain/http/__init__.py,sha256=ny0Rr4coLrQG7OvV1J2yLI1HlgvwJBboWiXlBvkIaP4,1429
|
|
57
|
+
plain/http/cookie.py,sha256=x13G3LIr0jxnPK1NQRptmi0DrAq9PsivQnQTm4LKaW0,2191
|
|
58
|
+
plain/http/exceptions.py,sha256=XJUckCrDhrTCAacmH2Qt-1xr0UZ1-LgpEYizyeL5kpQ,1446
|
|
59
|
+
plain/http/middleware.py,sha256=TPs585IIFjgp-5uUAJtIoigH6uwTS3FJqwFSsQdayd4,960
|
|
60
|
+
plain/http/multipartparser.py,sha256=Jm7dQzIL8ulYRh1MBjmQuUWF6KBhgZBLAVBBBZOTeaA,28133
|
|
61
|
+
plain/http/request.py,sha256=8HFHUw1UMEoXwkVY1rxqekZuq0mQ4HWbbkri6uZwxaY,28584
|
|
62
|
+
plain/http/response.py,sha256=b1jFpOtVmJMFI3oQ9NMGXK45BAsxz_r6udM8tsbSQI0,22079
|
|
63
|
+
plain/internal/__init__.py,sha256=n2AgdfNelt_tp8CS9JDzHMy_aiTUMPGZiFFwKmNz2fg,262
|
|
64
|
+
plain/internal/reloader.py,sha256=n7B-F-WeUXp37pAnvzKX9tcEbUxHSlYqa4gItyA_zko,2662
|
|
65
|
+
plain/internal/files/__init__.py,sha256=VctFgox4Q1AWF3klPaoCC5GIw5KeLafYjY5JmN8mAVw,63
|
|
66
|
+
plain/internal/files/base.py,sha256=fp8lo-4ec3RofJCClIkR3yZE-zyW_gDy9NeWTlV3ID8,4713
|
|
67
|
+
plain/internal/files/locks.py,sha256=jvLL9kroOo50kUo8dbuajDiFvgSL5NH6x5hudRPPjiQ,4022
|
|
68
|
+
plain/internal/files/move.py,sha256=qE1nAVdJO8PJyxcZyoPORFYNPLf2EEt_dyOyk7cg9HE,3338
|
|
69
|
+
plain/internal/files/temp.py,sha256=Y7Kb4j26NqZQuNqWMe91d3KJ63DP289prM31iRyAN3w,2969
|
|
70
|
+
plain/internal/files/uploadedfile.py,sha256=LohB2bBjfh3BwN9qCo_JtdnZe3knUBtT_vHAMlXErWE,4940
|
|
71
|
+
plain/internal/files/uploadhandler.py,sha256=bOTa-no1e2Q1ZCMSywhYaH7II8uOj9lQUB9j9FgGky8,7537
|
|
72
|
+
plain/internal/files/utils.py,sha256=ERcjMX5Qalpt9EKOonkfOc2Lw8fGgpu2eXLOCAd9aiY,3003
|
|
73
|
+
plain/internal/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
|
+
plain/internal/handlers/base.py,sha256=9H4bWTq0Q-X_RXOHOYgR5Vgmw2RstBZ-sUXxbeJK6Js,6541
|
|
75
|
+
plain/internal/handlers/exception.py,sha256=oGA5Gg1GHc0eTOxOMayKlQOMytuACWcWWmZRstHG7qw,5070
|
|
76
|
+
plain/internal/handlers/wsgi.py,sha256=UAeny1rKCCClPZKE6JGemEEFKKbfeMBKd4RzHyS0DZs,8950
|
|
77
|
+
plain/internal/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
78
|
+
plain/internal/middleware/headers.py,sha256=6ortXSnoZ8c7d-s2pWdajLaVIjQ3Glw9HMrFObXG7Kk,2002
|
|
79
|
+
plain/internal/middleware/hosts.py,sha256=ZGG4TVSVLv7LBm5ckZEvfqeBFRAANbP0F9d3SYmUoO8,5890
|
|
80
|
+
plain/internal/middleware/https.py,sha256=-R1Aa9Auai3GyhQHUggaUQI_TuMR_35J9u3xE9HX2xQ,1117
|
|
81
|
+
plain/internal/middleware/slash.py,sha256=6Srrmyaleu8PIRbHeodCmc8oa51gDDdX_OwPz5H1DEQ,3073
|
|
82
|
+
plain/logs/README.md,sha256=dw8Za2nOaqV116D2LMIzJUpGYnn5nW67rXzYYxq0h1Q,7195
|
|
83
|
+
plain/logs/__init__.py,sha256=QzurbfNXbx04QjZBsYxnIc3pwD9uN_mnuDArksEDsw8,54
|
|
84
|
+
plain/logs/app.py,sha256=T5ofCgMPpE3glf1GluZ0xu3yzzgGTm-r9kVggM-jITc,5605
|
|
85
|
+
plain/logs/configure.py,sha256=nz1bAbg4XDyJWpbdsvTKTJ6geUeTex4z__PP-GzWRN8,2717
|
|
86
|
+
plain/logs/debug.py,sha256=vz6GYy5QJTBLYHyIsYvPq5BOziPJSzo0pxqTid4beDs,1372
|
|
87
|
+
plain/logs/filters.py,sha256=7e90DSsqDg6BibywiEnh1x-R9JqcOkdQuMF2uQyurEs,457
|
|
88
|
+
plain/logs/formatters.py,sha256=8EULZzGY7xUXM4X9ZOwG3QURwkVlHpjMkL6UEBt9Gsg,2529
|
|
89
|
+
plain/packages/README.md,sha256=ZbEKfx_zwB0ihvQGe6GrjpDvVfqvHfzxSoTZEdiJXfM,4852
|
|
90
|
+
plain/packages/__init__.py,sha256=OpQny0xLplPdPpozVUUkrW2gB-IIYyDT1b4zMzOcCC4,160
|
|
91
|
+
plain/packages/config.py,sha256=0c53dWlaTHNPdIOHP7-TWwz0xcIpLQBY8d7NOWNasBs,3167
|
|
92
|
+
plain/packages/registry.py,sha256=PIPmFFrTnk8O0tdMZAy4Ogk61IeSxd-TIohWxmjRsU4,9036
|
|
93
|
+
plain/preflight/README.md,sha256=-Z2pMt3en6H-92HFw6uHNYN4hypSv77ww93GfttNhvM,7521
|
|
94
|
+
plain/preflight/__init__.py,sha256=6jDCcm5QosjKne_HKcTZdUv5X_jk_NCYxrzupJEsoTE,467
|
|
95
|
+
plain/preflight/checks.py,sha256=kJcr-Hq5bsjKw1BUYR6r6nFg3Ecgrd1DS5SudUr4rSU,289
|
|
96
|
+
plain/preflight/files.py,sha256=OjD76e-l_cDXJGHMk21LsoPp6V_HxD5v0zyvOKkEDu0,840
|
|
97
|
+
plain/preflight/registry.py,sha256=87FvZRsbbbuFJGKJ2PC5-o9aZ1MIKgLPYOTR3ghlzK4,2920
|
|
98
|
+
plain/preflight/results.py,sha256=V2LeyZeL8tM4ixnGZjsHuI7kYCIbaoaWHP_t0BjH5yA,1121
|
|
99
|
+
plain/preflight/security.py,sha256=mTVRACvAmGuK9LvPSFuuW0XHdhRRREmLzfkDcoh6snE,3067
|
|
100
|
+
plain/preflight/settings.py,sha256=Qr_aOdxDh6_XL6HwAKflDICdeawmd3oGcGU2wmESELo,2083
|
|
101
|
+
plain/preflight/urls.py,sha256=Asw_vq-70NRqr15yuBAYL0JCZ04liumORYT3I3KmF_k,437
|
|
102
|
+
plain/runtime/README.md,sha256=AXj420OhD7ecdoVQ4I-7XY7VzlXY35_wBNm4yoN4Prk,5989
|
|
103
|
+
plain/runtime/__init__.py,sha256=qwZuhx4hpJsW9YkgtGzumm0YXY-dK29X0V_p9ugJags,2605
|
|
104
|
+
plain/runtime/global_settings.py,sha256=3b4Sy6vC4Z4Ho75zT-fBHOHv9DTOu0BfioLH2l5j36U,6457
|
|
105
|
+
plain/runtime/secret.py,sha256=UTlKNhM4ut_IHtQ8T0eXSvhrI-O7r_X20fEdpSIb3EI,435
|
|
106
|
+
plain/runtime/user_settings.py,sha256=sHfPlCgMDKDcqgaHLwOu9_M8h0uVTXLLbmkAdJpTHbs,14054
|
|
107
|
+
plain/runtime/utils.py,sha256=sHOv9SWCalBtg32GtZofimM2XaQtf_jAyyf6RQuOlGc,851
|
|
108
|
+
plain/server/LICENSE,sha256=Xt_dw4qYwQI9qSi2u8yMZeb4HuMRp5tESRKhtvvJBgA,1707
|
|
109
|
+
plain/server/README.md,sha256=HQEIDN8zJ10tYXopKrFTjTXGPsIJNFL75BLGbz55suU,5622
|
|
110
|
+
plain/server/__init__.py,sha256=DtRgEcr4IxF4mrtCHloIprk_Q4k1oju4F2VHoyvu4ow,212
|
|
111
|
+
plain/server/app.py,sha256=ozaqdb-a_T3ps7T5EJwIPM63F_497J4o7kw9Pbq7Ga0,1229
|
|
112
|
+
plain/server/arbiter.py,sha256=ChlA_qQPT8sAVsOkD5f_d18Q8cpoR-uSoa92iBxolG4,17461
|
|
113
|
+
plain/server/config.py,sha256=-T1w8dbUwwLd898P1HNufe8Kw8VJDYJaeKY-UuKzvTo,3221
|
|
114
|
+
plain/server/errors.py,sha256=sKl_OJ5Uw-a_r_dZ2o4I8JaKeTrjvY_LR12F6B_p4-g,956
|
|
115
|
+
plain/server/glogging.py,sha256=9FS-kRPja3BfNAdjyCghoS2st8VXHUc1--4dvQ3Ph18,9662
|
|
116
|
+
plain/server/pidfile.py,sha256=3BrA5DgFqAp3jWQdZjRdnVS4vdTytg209jHN4JCGDNI,2548
|
|
117
|
+
plain/server/sock.py,sha256=PXmlVNTv4lJR8Rfe0t7VeXqm0MtZgudNM_84NkwsR58,7098
|
|
118
|
+
plain/server/util.py,sha256=BetOuZ344wXu6VwgbRDcp1SIWBSCDY1L8m38L_y7eU4,8873
|
|
119
|
+
plain/server/http/__init__.py,sha256=kQwTk1l3hYJwVrzr1p-XNAbWYe0icsD7l0ZyGRXMbOI,300
|
|
120
|
+
plain/server/http/body.py,sha256=fxl9qV8uIYxwXbsJxcmsVX2aRfIb5jpSJxKm9Ug69B0,8352
|
|
121
|
+
plain/server/http/errors.py,sha256=hoy9NnXLWWbYJ4DkMnM0lcFEqaggI-KfCVgaAYIB7Dw,3827
|
|
122
|
+
plain/server/http/message.py,sha256=9bntA2glNchIJUK6O4NNNCCkrtr2xsDUqldvPTnP0gk,15135
|
|
123
|
+
plain/server/http/parser.py,sha256=8z1WZNsEvKh7qSePy3YkSSsRySGj8uz7Hz1N10bk2DQ,1803
|
|
124
|
+
plain/server/http/unreader.py,sha256=jD2PGZ574FGmQOZlqWfs1VWzp-ttfIso_GzYaId6KYQ,2238
|
|
125
|
+
plain/server/http/wsgi.py,sha256=ERn8JQeoFIA9g7Os1gPIRg32p_CYqtcipYvnIx9U1is,13923
|
|
126
|
+
plain/server/workers/__init__.py,sha256=sLq8nrIIf9Wjw5_qQsh6cnHnY7eIqCpzSedKrNmmn7s,145
|
|
127
|
+
plain/server/workers/base.py,sha256=aeZIfZ2pBjlnYdVuCIBsDUXGAg-tJ1vIQQTfYwQk0sQ,9721
|
|
128
|
+
plain/server/workers/sync.py,sha256=xzE-t-6LW1DtGmwhIRVBgTnc3SwBe1CgL81MJQ7WFnY,7292
|
|
129
|
+
plain/server/workers/thread.py,sha256=xx0lq0JKI4UPn4RUjTETdOEOyWWVR_X0n34JIY82yek,13860
|
|
130
|
+
plain/server/workers/workertmp.py,sha256=egGReVvldlOBQfQGcpLpjt0zvPwR4C_N-UJKG-U_6w4,1299
|
|
131
|
+
plain/signals/README.md,sha256=5HR6of7tgwBiZQqIdZMrwgiMjUH9qjY8inl-tSmR8Lo,5500
|
|
132
|
+
plain/signals/__init__.py,sha256=VDhotllLUQVg3eA1LuAJM9pwGTaf_bzRGzc4mJhd-sY,98
|
|
133
|
+
plain/signals/dispatch/__init__.py,sha256=FzEygqV9HsM6gopio7O2Oh_X230nA4d5Q9s0sUjMq0E,292
|
|
134
|
+
plain/signals/dispatch/dispatcher.py,sha256=ofpu8wMEx8O-I9SO9Rkk1ABH09-71QnmGZlt8vsZAw8,12317
|
|
135
|
+
plain/signals/dispatch/license.txt,sha256=o9EhDhsC4Q5HbmD-IfNGVTEkXtNE33r5rIt3lleJ8gc,1727
|
|
136
|
+
plain/skills/README.md,sha256=WUhXiLU42pIdcXiT-zugnsOXj4OjiCmec_XcM85KAyo,1434
|
|
137
|
+
plain/skills/plain-docs/SKILL.md,sha256=CoOEhTsOpNczBuGxnHbGIVZ9Yahreq0RoXzqhVwtajY,560
|
|
138
|
+
plain/skills/plain-install/SKILL.md,sha256=lPhUMmKAQpjrVMp73T5pBkwkIaJjWTxAqtyS8Hio8mM,746
|
|
139
|
+
plain/skills/plain-request/SKILL.md,sha256=C37GEWRIpJFr-fbnEb08ENOJg-A7WUZxoYPneFAkHO4,771
|
|
140
|
+
plain/skills/plain-shell/SKILL.md,sha256=njxD1dXVmSVZkcUnEm9_62hn_P6JMQmCpVOEzq29RvY,400
|
|
141
|
+
plain/skills/plain-upgrade/SKILL.md,sha256=79otYHv68Tfk3j08kRbg7o9eiNzzFZFyXCfLuIlT2Ho,927
|
|
142
|
+
plain/templates/README.md,sha256=zhAayenfxtwq6r1-NjoaD-wjaazyhm76BCacGF24ACc,8803
|
|
143
|
+
plain/templates/__init__.py,sha256=bX76FakE9T7mfK3N0deN85HlwHNQpeigytSC9Z8LcOs,451
|
|
144
|
+
plain/templates/core.py,sha256=mbcH0yTeFOI3XOg9dYSroXRIcdv9sETEy4HzY-ugwco,1258
|
|
145
|
+
plain/templates/jinja/__init__.py,sha256=7odJxZfn1p2zhzuuehdcLPIZm8jZDXMYAKnu-fpt2r8,2199
|
|
146
|
+
plain/templates/jinja/environments.py,sha256=vadQQ7UhZOJPbeyI3ErKYE4_IwpWyABSDYS_aq5PA10,2141
|
|
147
|
+
plain/templates/jinja/extensions.py,sha256=qFSNUoV1rxdmKORvQhu698KxbSayltcnaGVbA9YMviE,1566
|
|
148
|
+
plain/templates/jinja/filters.py,sha256=g70cw1jzvYco2v-u4SeceOWBX_qxHI5k9AODMn8ewsY,1590
|
|
149
|
+
plain/templates/jinja/globals.py,sha256=2UwXclm0q_VILYvkQzTmoFaMS30FVZPmk9QZ8wKB7QA,572
|
|
150
|
+
plain/test/README.md,sha256=0XEKluidRikGk2V3wQJgvVChxRh4eXOeUSklTQS-msc,5844
|
|
151
|
+
plain/test/__init__.py,sha256=MhNHtp7MYBl9kq-pMRGY11kJ6kU1I6vOkjNkit1TYRg,94
|
|
152
|
+
plain/test/client.py,sha256=79M2aUYCqcegIW_DazP1Vx-TczzNC-pnMFPHZEvyNRU,30853
|
|
153
|
+
plain/test/encoding.py,sha256=txj_FCbC4GxH-JCkopW5LaZz8cGsrKQiculjFkjkzuY,3372
|
|
154
|
+
plain/test/exceptions.py,sha256=VHet3oylks4JdWWAiVUrhPMdDr1Dx0uuQE6irXS-e-U,392
|
|
155
|
+
plain/urls/README.md,sha256=O-3CFXJnliMJ5bUmvq75Tbi1_Yx2vdbVMgEIVZSGPxE,6896
|
|
156
|
+
plain/urls/__init__.py,sha256=DFO2OL1IllHW5USPIb5uYvvzf_G-Bl0Qu1zrRLHmWyM,542
|
|
157
|
+
plain/urls/converters.py,sha256=7_1eiQcmhLf57O3AioC279_BrclSqi1ZNESXOPed7Y4,1410
|
|
158
|
+
plain/urls/exceptions.py,sha256=eRLlvH11txmTUlBITXtJ_FDz0W7Cn0Ikmciuoj6flF4,132
|
|
159
|
+
plain/urls/patterns.py,sha256=CSuJEOCOjBwIFeJ2BTZbb2Fw-pgbFnWOj8dsszwH4KE,9036
|
|
160
|
+
plain/urls/resolvers.py,sha256=XhURKhoeZ562htjv1TF6Ja5Zh5JSggn05teB_-1S3uI,13280
|
|
161
|
+
plain/urls/routers.py,sha256=B1fX-FQTxmr-b_YeHQUMPuilLVqOi6-RqgPgu6MtFDY,2831
|
|
162
|
+
plain/urls/utils.py,sha256=VP91p0ilpWUimQSfiILUKjBnWolKXgYvgZD9X374R1g,1326
|
|
163
|
+
plain/utils/README.md,sha256=MyNOfltVv24C5m13dEFnKEV3Adq7uwjYoHv3RGEsLxw,7080
|
|
164
|
+
plain/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
165
|
+
plain/utils/cache.py,sha256=e5bfuEqNfna3dZTE9ZDGKwQKtbRJFRSJeEXXKq2LbGo,5642
|
|
166
|
+
plain/utils/crypto.py,sha256=JU8ZrCz8gKusmBoPvbZEg9W9Am3K6GAfI_uijvg7u3c,2819
|
|
167
|
+
plain/utils/datastructures.py,sha256=cZGG7181A2BakVfBma89Pek2VbrSyYpBEh52Ws19x6I,11937
|
|
168
|
+
plain/utils/dateparse.py,sha256=Z330Erc5FEXkes5ndI6drkvL-2sDf4z6-3SUR_WrfQk,5569
|
|
169
|
+
plain/utils/deconstruct.py,sha256=FnNtkOoEPtMYOWhveIJkVlCbKeZX7snutJJpK2sMa04,2164
|
|
170
|
+
plain/utils/decorators.py,sha256=IoJ-oH3JtJaLH8ndeP6uU06BbkOAzMmtUdabG9FkIdw,455
|
|
171
|
+
plain/utils/dotenv.py,sha256=3ZW4S7u-GId1XHSwcLinp6Mqs5od4qXe3K0N2KexDNE,11417
|
|
172
|
+
plain/utils/duration.py,sha256=QBFh-iLvRXuw0N0UUdFqabeJvZVqkgFME_c2gRSLwhI,1340
|
|
173
|
+
plain/utils/encoding.py,sha256=40siECldXUFyZ_IkyQCeOkyQuXb7i4Rpys3nFWFHnuc,4482
|
|
174
|
+
plain/utils/functional.py,sha256=ujpUXAeo1M4sTTBMouJZi2dq3N8SflNzmD6ER7Vh3z4,14833
|
|
175
|
+
plain/utils/hashable.py,sha256=1Kh_SFxsaR2d3xQMNEtHb4eKSHugtNt66iZ3ZvKjt50,811
|
|
176
|
+
plain/utils/html.py,sha256=pjmEuhoVt_nikyjzwfJNFfnZaKeC9xe1vHZwsX-fHGs,4255
|
|
177
|
+
plain/utils/http.py,sha256=SlcrPXgCUGlZirceKWE3uCO2Z32p6v2k-CBncAd7HS4,5847
|
|
178
|
+
plain/utils/inspect.py,sha256=3RyZG4J9A16Lx3eDcn5vyRiTowixMID4cI5QJu8sSDc,1478
|
|
179
|
+
plain/utils/ipv6.py,sha256=TLOQVN0aqKGM4eS_HwarTgO-bGIql-k5AipDPgtQdCA,1352
|
|
180
|
+
plain/utils/itercompat.py,sha256=2v8UaAMgRCju_ZUH3CKg6Q4XYUaQPqZ7_cRKSgUYs8w,258
|
|
181
|
+
plain/utils/module_loading.py,sha256=JRltNNz7XoQpaMdd7RYHuEWVN2ycsrLJ4Yw7XTp97uQ,1776
|
|
182
|
+
plain/utils/regex_helper.py,sha256=zoPaCHo8EfT_Y7EgXknv9dpXkSaQTKSfC6iT-E0H7kA,13390
|
|
183
|
+
plain/utils/safestring.py,sha256=6YR1yimQVmSsk8tNiYxKuhsSIiOP2PFV1jSKc6--x_c,2131
|
|
184
|
+
plain/utils/text.py,sha256=cuACozKwAeR3x5POAOvNt3KYwn3jSbJJYnEVR-OFmuY,10169
|
|
185
|
+
plain/utils/timesince.py,sha256=a_-ZoPK_s3Pt998CW4rWp0clZ1XyK2x04hCqak2giII,5928
|
|
186
|
+
plain/utils/timezone.py,sha256=2q9ayPO_991CHlyYFHcRMngbWskYSieGVni6FnKXrSw,6877
|
|
187
|
+
plain/utils/tree.py,sha256=FbgAJ_eH4WsBEDWrxuo1SHXaMCBgZ3M_SH5eL4QKAow,4858
|
|
188
|
+
plain/views/README.md,sha256=7C3tn3zvbwT38x1dRWpspTQcUbtUrejFFhqB4xp83U4,9944
|
|
189
|
+
plain/views/__init__.py,sha256=M-R2AgHnlGk75KdL4ZN_Cz2HuSOg2mV8gGnPhhvhsYA,371
|
|
190
|
+
plain/views/base.py,sha256=pWm_P0Dlbk7uZ1pyOOI7r0T4ojAAs_pnCBRkkYdZaP0,4487
|
|
191
|
+
plain/views/errors.py,sha256=3Vvl_Xg7fnVQMPazHup8s5Cu4CneLa05qycWccY9HoU,1501
|
|
192
|
+
plain/views/exceptions.py,sha256=-YKH1Jd9Zm_yXiz797PVjJB6VWaPCTXClHIUkG2fq78,198
|
|
193
|
+
plain/views/forms.py,sha256=j5WAMLeW1efU9M0q1W6SFHMDMBZfkFfW4WRLKwrXjqk,2435
|
|
194
|
+
plain/views/objects.py,sha256=qKK8lYQKK7DTBPrMUebZ2HevgU9MmyWeXFWG1lT5ZbM,5393
|
|
195
|
+
plain/views/redirect.py,sha256=rt5RF1Rs2yYFLole3Mznu5iU9aeumu49VAaX4WCd_xk,2139
|
|
196
|
+
plain/views/templates.py,sha256=ElyqgpbkoJt72yU1gF7b626TB3R8viDAf-LYloulUBA,1925
|
|
197
|
+
plain-0.101.2.dist-info/METADATA,sha256=EeQAZpll3Jn51d0GwuHSbstJjL_78xe-43GS_fSsQpU,4550
|
|
198
|
+
plain-0.101.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
199
|
+
plain-0.101.2.dist-info/entry_points.txt,sha256=1Ys2lsSeMepD1vz8RSrJopna0RQfUd951vYvCRsvl6A,45
|
|
200
|
+
plain-0.101.2.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
|
|
201
|
+
plain-0.101.2.dist-info/RECORD,,
|
plain/AGENTS.md
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# Plain AGENTS.md
|
|
2
|
-
|
|
3
|
-
Plain is a Python web framework that was originally forked from Django. While it still has a lot in common with Django, there are also significant changes -- don't solely rely on knowledge of Django when working with Plain.
|
|
4
|
-
|
|
5
|
-
## Commands
|
|
6
|
-
|
|
7
|
-
The `plain` CLI is the main entrypoint for the framework. If `plain` is not available by itself, try `uv run plain`.
|
|
8
|
-
|
|
9
|
-
- `plain shell -c <command>`: Run a Python command with Plain configured.
|
|
10
|
-
- `plain run <filename>`: Run a Python script with Plain configured.
|
|
11
|
-
- `plain agent docs <package>`: Show README.md and symbolicated source files for a specific package.
|
|
12
|
-
- `plain agent docs --list`: List packages with docs available.
|
|
13
|
-
- `plain agent request <path> --user <user_id>`: Make an authenticated request to the application and inspect the output.
|
|
14
|
-
- `plain --help`: List all available commands (including those from installed packages).
|
|
15
|
-
|
|
16
|
-
## Code style
|
|
17
|
-
|
|
18
|
-
- Imports should be at the top of the file, unless there is a specific reason to import later (e.g. to avoid circular imports).
|
plain/cli/agent/__init__.py
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
|
|
3
|
-
from .docs import docs
|
|
4
|
-
from .md import md
|
|
5
|
-
from .request import request
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@click.group("agent", invoke_without_command=True)
|
|
9
|
-
@click.pass_context
|
|
10
|
-
def agent(ctx):
|
|
11
|
-
"""Tools for coding agents."""
|
|
12
|
-
if ctx.invoked_subcommand is None:
|
|
13
|
-
# If no subcommand provided, show all AGENTS.md files
|
|
14
|
-
ctx.invoke(md, show_all=True, show_list=False, package="")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# Add commands to the group
|
|
18
|
-
agent.add_command(docs)
|
|
19
|
-
agent.add_command(md)
|
|
20
|
-
agent.add_command(request)
|