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/cli/agent/docs.py DELETED
@@ -1,80 +0,0 @@
1
- import importlib.util
2
- import pkgutil
3
- from pathlib import Path
4
-
5
- import click
6
-
7
- from .llmdocs import LLMDocs
8
-
9
-
10
- @click.command()
11
- @click.argument("package", default="", required=False)
12
- @click.option(
13
- "--list",
14
- "show_list",
15
- is_flag=True,
16
- help="List available packages",
17
- )
18
- def docs(package, show_list):
19
- """Show LLM-friendly documentation and source for a package."""
20
-
21
- if show_list:
22
- # List available packages using same discovery logic as md command
23
- try:
24
- available_packages = []
25
-
26
- # Check for plain.* subpackages (including core plain)
27
- try:
28
- import plain
29
-
30
- # Check core plain package (namespace package)
31
- plain_spec = importlib.util.find_spec("plain")
32
- if plain_spec and plain_spec.submodule_search_locations:
33
- available_packages.append("plain")
34
-
35
- # Check other plain.* subpackages
36
- for importer, modname, ispkg in pkgutil.iter_modules(
37
- plain.__path__, "plain."
38
- ):
39
- if ispkg:
40
- available_packages.append(modname)
41
- except Exception:
42
- pass
43
-
44
- if available_packages:
45
- for pkg in sorted(available_packages):
46
- click.echo(f"- {pkg}")
47
- else:
48
- click.echo("No packages found.")
49
- except Exception as e:
50
- click.echo(f"Error listing packages: {e}")
51
- return
52
-
53
- if not package:
54
- raise click.UsageError(
55
- "Package name required. Usage: plain agent docs [package-name]"
56
- )
57
-
58
- # Convert hyphens to dots (e.g., plain-models -> plain.models)
59
- package = package.replace("-", ".")
60
-
61
- # Automatically prefix if we need to
62
- if not package.startswith("plain"):
63
- package = f"plain.{package}"
64
-
65
- try:
66
- # Get the path for this specific package
67
- spec = importlib.util.find_spec(package)
68
- if not spec or not spec.origin:
69
- raise click.UsageError(f"Package {package} not found")
70
-
71
- package_path = Path(spec.origin).parent
72
- paths = [package_path]
73
-
74
- # Generate docs for this specific package
75
- source_docs = LLMDocs(paths)
76
- source_docs.load()
77
- source_docs.print(relative_to=package_path.parent)
78
-
79
- except Exception as e:
80
- raise click.UsageError(f"Error loading documentation for {package}: {e}")
plain/cli/agent/md.py DELETED
@@ -1,87 +0,0 @@
1
- import importlib.util
2
- import pkgutil
3
- from pathlib import Path
4
-
5
- import click
6
-
7
- from ..output import iterate_markdown
8
-
9
-
10
- def _get_packages_with_agents():
11
- """Get dict mapping package names to AGENTS.md paths."""
12
- agents_files = {}
13
-
14
- # Check for plain.* subpackages (including core plain)
15
- try:
16
- import plain
17
-
18
- # Check core plain package (namespace package)
19
- plain_spec = importlib.util.find_spec("plain")
20
- if plain_spec and plain_spec.submodule_search_locations:
21
- # For namespace packages, use the first search location
22
- plain_path = Path(plain_spec.submodule_search_locations[0])
23
- agents_path = plain_path / "AGENTS.md"
24
- if agents_path.exists():
25
- agents_files["plain"] = agents_path
26
-
27
- # Check other plain.* subpackages
28
- for importer, modname, ispkg in pkgutil.iter_modules(plain.__path__, "plain."):
29
- if ispkg:
30
- try:
31
- spec = importlib.util.find_spec(modname)
32
- if spec and spec.origin:
33
- package_path = Path(spec.origin).parent
34
- # Look for AGENTS.md at package root
35
- agents_path = package_path / "AGENTS.md"
36
- if agents_path.exists():
37
- agents_files[modname] = agents_path
38
- except Exception:
39
- continue
40
- except Exception:
41
- pass
42
-
43
- return agents_files
44
-
45
-
46
- @click.command("md")
47
- @click.argument("package", default="", required=False)
48
- @click.option(
49
- "--all",
50
- "show_all",
51
- is_flag=True,
52
- help="Show AGENTS.md for all packages that have them",
53
- )
54
- @click.option(
55
- "--list",
56
- "show_list",
57
- is_flag=True,
58
- help="List packages with AGENTS.md files",
59
- )
60
- def md(package, show_all, show_list):
61
- """Show AGENTS.md for a package."""
62
-
63
- agents_files = _get_packages_with_agents()
64
-
65
- if show_list:
66
- for pkg in sorted(agents_files.keys()):
67
- click.echo(f"- {pkg}")
68
-
69
- return
70
-
71
- if show_all:
72
- for pkg in sorted(agents_files.keys()):
73
- agents_path = agents_files[pkg]
74
- for line in iterate_markdown(agents_path.read_text()):
75
- click.echo(line, nl=False)
76
- print()
77
-
78
- return
79
-
80
- if not package:
81
- raise click.UsageError(
82
- "Package name or --all required. Use --list to see available packages."
83
- )
84
-
85
- agents_path = agents_files[package]
86
- for line in iterate_markdown(agents_path.read_text()):
87
- click.echo(line, nl=False)
plain/cli/agent/prompt.py DELETED
@@ -1,45 +0,0 @@
1
- import os
2
- import shlex
3
- import subprocess
4
-
5
- import click
6
-
7
-
8
- def is_agent_environment():
9
- """Check if we're running inside a coding agent."""
10
- return bool(
11
- os.environ.get("CLAUDECODE")
12
- or os.environ.get("CODEX_SANDBOX")
13
- or os.environ.get("CURSOR_ENVIRONMENT")
14
- )
15
-
16
-
17
- def prompt_agent(
18
- prompt: str, agent_command: str | None = None, print_only: bool = False
19
- ) -> bool:
20
- if is_agent_environment():
21
- click.echo(prompt)
22
- return True
23
-
24
- if print_only or not agent_command:
25
- click.echo(prompt)
26
- if not print_only:
27
- click.secho(
28
- "\nCopy the prompt above to a coding agent. To run an agent automatically, use --agent-command or set the PLAIN_AGENT_COMMAND environment variable.",
29
- dim=True,
30
- italic=True,
31
- err=True,
32
- )
33
- return True
34
- else:
35
- cmd = shlex.split(agent_command)
36
- cmd.append(prompt)
37
- result = subprocess.run(cmd, check=False)
38
- if result.returncode != 0:
39
- click.secho(
40
- f"Agent command failed with exit code {result.returncode}",
41
- fg="red",
42
- err=True,
43
- )
44
- return False
45
- return True
plain/csrf/views.py DELETED
@@ -1,31 +0,0 @@
1
- from plain.views import TemplateView
2
-
3
-
4
- class CsrfFailureView(TemplateView):
5
- template_name = "403.html"
6
-
7
- def get_response(self):
8
- response = super().get_response()
9
- response.status_code = 403
10
- return response
11
-
12
- def post(self):
13
- return self.get()
14
-
15
- def put(self):
16
- return self.get()
17
-
18
- def patch(self):
19
- return self.get()
20
-
21
- def delete(self):
22
- return self.get()
23
-
24
- def head(self):
25
- return self.get()
26
-
27
- def options(self):
28
- return self.get()
29
-
30
- def trace(self):
31
- return self.get()
plain/logs/utils.py DELETED
@@ -1,46 +0,0 @@
1
- import logging
2
-
3
- request_logger = logging.getLogger("plain.request")
4
-
5
-
6
- def log_response(
7
- message,
8
- *args,
9
- response=None,
10
- request=None,
11
- logger=request_logger,
12
- level=None,
13
- exception=None,
14
- ):
15
- """
16
- Log errors based on Response status.
17
-
18
- Log 5xx responses as errors and 4xx responses as warnings (unless a level
19
- is given as a keyword argument). The Response status_code and the
20
- request are passed to the logger's extra parameter.
21
- """
22
- # Check if the response has already been logged. Multiple requests to log
23
- # the same response can be received in some cases, e.g., when the
24
- # response is the result of an exception and is logged when the exception
25
- # is caught, to record the exception.
26
- if getattr(response, "_has_been_logged", False):
27
- return
28
-
29
- if level is None:
30
- if response.status_code >= 500:
31
- level = "error"
32
- elif response.status_code >= 400:
33
- level = "warning"
34
- else:
35
- level = "info"
36
-
37
- getattr(logger, level)(
38
- message,
39
- *args,
40
- extra={
41
- "status_code": response.status_code,
42
- "request": request,
43
- },
44
- exc_info=exception,
45
- )
46
- response._has_been_logged = True
plain/templates/AGENTS.md DELETED
@@ -1,3 +0,0 @@
1
- # Plain Templates AGENTS.md
2
-
3
- - Plain templates use Jinja2.
@@ -1,169 +0,0 @@
1
- plain/AGENTS.md,sha256=5XMGBpJgbCNIpp60DPXB7bpAtFk8FAzqiZke95T965o,1038
2
- plain/CHANGELOG.md,sha256=w-r_nifYj7nhHF3pbn3fJC0r3j9PhqYVBoTKeFTnDiU,18152
3
- plain/README.md,sha256=5BJyKhf0TDanWVbOQyZ3zsi5Lov9xk-LlJYCDWofM6Y,4078
4
- plain/__main__.py,sha256=GK39854Lc_LO_JP8DzY9Y2MIQ4cQEl7SXFJy244-lC8,110
5
- plain/debug.py,sha256=XdjnXcbPGsi0J2SpHGaLthhYU5AjhBlkHdemaP4sbYY,758
6
- plain/exceptions.py,sha256=QepC5UG5IBGW3h2cimOqGtjslAzvYdLYIn6xHdyco-Y,5868
7
- plain/json.py,sha256=McJdsbMT1sYwkGRG--f2NSZz0hVXPMix9x3nKaaak2o,1262
8
- plain/paginator.py,sha256=iXiOyt2r_YwNrkqCRlaU7V-M_BKaaQ8XZElUBVa6yeU,5844
9
- plain/signing.py,sha256=i8Bf12c96u_1BZYjETiixhsLAWMAt_y4CIYZOsI6IVA,8295
10
- plain/validators.py,sha256=TePzFHzwR4JXUAZ_Y2vC6mkKgVxHX3QBXI6Oex0rV8c,19236
11
- plain/wsgi.py,sha256=R6k5FiAElvGDApEbMPTT0MPqSD7n2e2Az5chQqJZU0I,236
12
- plain/assets/README.md,sha256=iRZHHoXZCEFooXoDYSomF12XTcDFl7oNbRHpAFwxTM8,4349
13
- plain/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- plain/assets/compile.py,sha256=DT85ygnNcY2_7VeozdsQlBvA-DzV7enUIMO_igJ1PjY,3296
15
- plain/assets/finders.py,sha256=2k8QZAbfUbc1LykxbzdazTSB6xNxJZnsZaGhWbSFZZs,1452
16
- plain/assets/fingerprints.py,sha256=D-x0o49sUuWfx86BssDyo87yJCjWrV0go6JGPagvMAE,1365
17
- plain/assets/urls.py,sha256=zQUA8bAlh9qVqskPJJrqWd9DjvetOi5jPSqy4vUX0J4,1161
18
- plain/assets/views.py,sha256=T_0Qh6v9qBerEBYbhToigwOzsij-x1z_R-1zETQcIh0,9447
19
- plain/chores/README.md,sha256=xTYKOBnfcLBpVeZgJQ6c35vdxHYaKkfJB8B-6sB3lcs,2054
20
- plain/chores/__init__.py,sha256=r9TXtQCH-VbvfnIJ5F8FxgQC35GRWFOfmMZN3q9niLg,67
21
- plain/chores/registry.py,sha256=2777muLuIF3ybqHKIsi7X_ulRvb8D7hNh3NotchBufA,1358
22
- plain/cli/README.md,sha256=5C7vsH0ISxu7q5H6buC25MBOILkI_rzdySitswpQgJw,1032
23
- plain/cli/__init__.py,sha256=6w9T7K2WrPwh6DcaMb2oNt_CWU6Bc57nUTO2Bt1p38Y,63
24
- plain/cli/build.py,sha256=Lo6AYghJz0DM9fIVUSiBSOKa5vR0XCOxZWEjza6sc8Q,3172
25
- plain/cli/changelog.py,sha256=j-k1yZk9mpm-fLZgeWastiyIisxNSuAJfXTQ2B6WQmk,3457
26
- plain/cli/chores.py,sha256=xXSSFvr8T5jWfLWqe6E8YVMw1BkQxyOHHVuY0x9RH0A,2412
27
- plain/cli/core.py,sha256=Nq7fsKfV2Oz9DJUwEGCMO52P8HnbxIng1pnQnFiqm0g,3100
28
- plain/cli/docs.py,sha256=YEEE-Th1CSxiL-wj5fF-ZagqkqAZYkEPRMO1OYUsQrU,1066
29
- plain/cli/formatting.py,sha256=JaOiIOxIQpCRgMNGw9xpnU_fMf6hROl7o8lA5aX114w,2580
30
- plain/cli/install.py,sha256=mffSYBmSJSj44OPBfu53nBQoyoz4jk69DvppubIB0mU,2791
31
- plain/cli/output.py,sha256=Fe3xS6Va4Bi1ZNrqi0nh09THTsdCyMW2b9SPY5I4n-o,1318
32
- plain/cli/preflight.py,sha256=FU4EVFXDpkvgOFKpXcp0sUYOHc0WmcRGwo8G2oqv9Gs,8500
33
- plain/cli/print.py,sha256=XraUYrgODOJquIiEv78wSCYGRBplHXtXSS9QtFG5hqY,217
34
- plain/cli/registry.py,sha256=CPS05AZAWtnHOUxqeaYqlJ2BaFeHYTxpeMAGX09oYs4,962
35
- plain/cli/scaffold.py,sha256=mcywA9DzfwoBSqWl5-Zpgcy1mTNUGEgdvoxXUrGcEVk,1351
36
- plain/cli/settings.py,sha256=9cx4bue664I2P7kUedlf4YhCPB0tSKSE4Q8mGyzEv2o,1995
37
- plain/cli/shell.py,sha256=PMHdwcRv48qXDToeq82aZaNth-cKc3V2pQ1yISrNMvY,1802
38
- plain/cli/startup.py,sha256=wLaFuyUb4ewWhtehBCGicrRCXIIGCRbeCT3ce9hUv-A,1022
39
- plain/cli/upgrade.py,sha256=0k33jNKvF_FSBcWNq_yEUgidGWrWlOURNfV8EaGE75U,5555
40
- plain/cli/urls.py,sha256=ghCW36aRszxmTo06A50FIvYopb6kQ07QekkDzM6_A1o,3824
41
- plain/cli/utils.py,sha256=VwlIh0z7XxzVV8I3qM2kZo07fkJFPoeeVZa1ODG616k,258
42
- plain/cli/agent/__init__.py,sha256=Ipp65kuIF14TVxNqsj71MsWUePaKHUcdP3QmaYyNcg0,480
43
- plain/cli/agent/docs.py,sha256=ubX3ZeRHxVaetLk9fjiN9mJ07GZExC-CHUvQoX2DD7c,2464
44
- plain/cli/agent/llmdocs.py,sha256=AUpNDb1xSOsSpzGOiFvpzUe4f7PUGMiR9cI13aVZouo,5038
45
- plain/cli/agent/md.py,sha256=7r1II8ckubBFOZNGPASWaPmJdgByWFPINLqIOzRetLQ,2581
46
- plain/cli/agent/prompt.py,sha256=rugYyQHV7JDNqGrx3_PPShwwqYlnEVbxw8RsczOo8tg,1253
47
- plain/cli/agent/request.py,sha256=uUbZoAhSSjOLtzgAAzacvqCS_27H-AvoeqIxpzjUjAA,5800
48
- plain/csrf/README.md,sha256=ApWpB-qlEf0LkOKm9Yr-6f_lB9XJEvGFDo_fraw8ghI,2391
49
- plain/csrf/middleware.py,sha256=KF8ngFadWdS0MHXC1dTLx-K3VtD6Xs-3RDjFqpiiEjQ,5053
50
- plain/csrf/views.py,sha256=HwQqfI6KPelHP9gSXhjfZaTLQic71PKsoZ6DPhr1rKI,572
51
- plain/forms/README.md,sha256=7MJQxNBoKkg0rW16qF6bGpUBxZrMrWjl2DZZk6gjzAU,2258
52
- plain/forms/__init__.py,sha256=UxqPwB8CiYPCQdHmUc59jadqaXqDmXBH8y4bt9vTPms,226
53
- plain/forms/boundfield.py,sha256=LhydhCVR0okrli0-QBMjGjAJ8-06gTCXVEaBZhBouQk,1741
54
- plain/forms/exceptions.py,sha256=NYk1wjYDkk-lA_XMJQDItOebQcL_m_r2eNRc2mkLQkg,315
55
- plain/forms/fields.py,sha256=OyL4eZIgJ_XMLPHGar17hLepFmwHV-hSnb_n7s18yUU,34709
56
- plain/forms/forms.py,sha256=hF7Dl8rEaiBTZhFQyfbh1Zf54BSEka8RYpBiGqkTa8I,10441
57
- plain/http/README.md,sha256=hkjTJJ2_WEGm7vaIxjjNHrzD6EN5VI6pjDJPIR9l1jo,760
58
- plain/http/__init__.py,sha256=PfmXBIq7onLO_bbOrVdj5rJeHxqJMYqrIobVKupUzUA,1003
59
- plain/http/cookie.py,sha256=THd7nOl-2ugeBPKgOhbD87aM2oxUbNH8HWrarUn0fpM,1955
60
- plain/http/multipartparser.py,sha256=Z1dFJNAd8N5RHUuF67jh1jBfZOFepORsre_3ee6CgOQ,27266
61
- plain/http/request.py,sha256=4VkejuFitAwlmHs45hV6g-BfZxKM-D9vqnNTTljzj28,23864
62
- plain/http/response.py,sha256=FM3otFkKEEkAaV_pVB3JUSMhMk7x_zf5JcDWKhOKviM,23223
63
- plain/internal/__init__.py,sha256=fVBaYLCXEQc-7riHMSlw3vMTTuF7-0Bj2I8aGzv0o0w,171
64
- plain/internal/files/__init__.py,sha256=VctFgox4Q1AWF3klPaoCC5GIw5KeLafYjY5JmN8mAVw,63
65
- plain/internal/files/base.py,sha256=2z19tik2_xgXlI6nfVZ4woSF9WB0RSUzsvOfi1Bz8Wg,4113
66
- plain/internal/files/locks.py,sha256=z03q7IZD4tPMK3s1HKF3w_uetkFj6w6FTheLUxZsfB0,3616
67
- plain/internal/files/move.py,sha256=jfdD29QhamxZjXRgqmZS4dJoJ4sK6M7QK1Km-69jWeo,3238
68
- plain/internal/files/temp.py,sha256=UJJnCI8dqPIC8XXHU3-jG2-0svbkrgGlBs4yhciLm4c,2506
69
- plain/internal/files/uploadedfile.py,sha256=JRB7T3quQjg-1y3l1ASPxywtSQZhaeMc45uFPIxvl7c,4192
70
- plain/internal/files/uploadhandler.py,sha256=63_QUwAwfq3bevw79i0S7zt2EB2UBoO7MaauvezaVMY,7198
71
- plain/internal/files/utils.py,sha256=xN4HTJXDRdcoNyrL1dFd528MBwodRlHZM8DGTD_oBIg,2646
72
- plain/internal/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
- plain/internal/handlers/base.py,sha256=YAfb43PPtkVtBzAlS7UsaCPh10a9h_K7qdIUoNg6LdE,6100
74
- plain/internal/handlers/exception.py,sha256=TbPYtgZ7ITJahUKhQWkptHK28Lb4zh_nOviNctC2EYs,4815
75
- plain/internal/handlers/wsgi.py,sha256=dgPT29t_F9llB-c5RYU3SHxGuZNaZ83xRjOfuOmtOl8,8209
76
- plain/internal/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- plain/internal/middleware/headers.py,sha256=ENIW1Gwat54hv-ejgp2R8QTZm-PlaI7k44WU01YQrNk,964
78
- plain/internal/middleware/hosts.py,sha256=vKdjElDk1-Ju6FUXtm5t0AfPPN-DPhjS31PkRrhM6vc,5799
79
- plain/internal/middleware/https.py,sha256=bjysNX6_2l4Rp4DpzF2XYjH-m6gfHNq2x-MN2hHGW78,804
80
- plain/internal/middleware/slash.py,sha256=qBTJ-yvOM0d8gUISUC7Fx22LG6aj76uhOiNHjvTkAAs,2840
81
- plain/logs/README.md,sha256=rzOHfngjizLgXL21g0svC1Cdya2s_gBA_E-IljtHpy8,4069
82
- plain/logs/__init__.py,sha256=gFVMcNn5D6z0JrvUJgGsOeYj1NKNtEXhw0MvPDtkN6w,58
83
- plain/logs/configure.py,sha256=G5kLP-92hOWE7vlWG3lhSbzOKXobavFbqjohevJF1Jg,1322
84
- plain/logs/debug.py,sha256=QBXA_M498uGtqFnwHN08z6fItiGR4A732JyIWG2b39Q,1048
85
- plain/logs/formatters.py,sha256=sHB4yo7806YN_V6cCzs1WOGMIZLq5q_eOndRqODI-T4,2380
86
- plain/logs/loggers.py,sha256=kV2uZDxA5XU4GJF8dAOqny5LmbC8nPKZmakS-xX4x1Y,4625
87
- plain/logs/utils.py,sha256=9UzdCCQXJinGDs71Ngw297mlWkhgZStSd67ya4NOW98,1257
88
- plain/packages/README.md,sha256=iNqMtwFDVNf2TqKUzLKQW5Y4_GsssmdB4cVerzu27Ro,2674
89
- plain/packages/__init__.py,sha256=OpQny0xLplPdPpozVUUkrW2gB-IIYyDT1b4zMzOcCC4,160
90
- plain/packages/config.py,sha256=2U7b1cp_kqIuLdSeHGCLrSUV77TdfGRsww3PcXOazaA,2910
91
- plain/packages/registry.py,sha256=fKijA6s1Y9W-9FnR9AyVFuBth-9v3XlHWJdhI8i7JtI,8472
92
- plain/preflight/README.md,sha256=vR43F_ls81hRSo7J2NNZ4VOMoRaJ1bS5JwA6l4ez36g,1782
93
- plain/preflight/__init__.py,sha256=-uBIVLD1DlJUVypQsEcrOtaNAhECbOpKhyoz0c_WMhA,416
94
- plain/preflight/checks.py,sha256=hEJbP5KHQmdmfcr7cHt45tmdwmjomd8nvnCmQYxxCTo,245
95
- plain/preflight/files.py,sha256=k1Gsy8QJGbatMe_1ylSaDs7azDnh6qv4CftFpOnbDr8,779
96
- plain/preflight/registry.py,sha256=65yiz9Wm8dOTMs9h15txNu7SRace6mbLI-sfn6GxMBQ,2427
97
- plain/preflight/results.py,sha256=wgZgISGt9KGZzgmM_HdFUl6ZmRHQlKhvQClP7KbGgcc,949
98
- plain/preflight/security.py,sha256=eqvJTe691WihtLN8hi2tj5wxH8ZgcsY5QFbYkorkNS0,2910
99
- plain/preflight/urls.py,sha256=QVBcZCv891ZeLNVXTZS0w6bb54w5UOpZXP21Li7gt3o,339
100
- plain/runtime/README.md,sha256=sTqXXJkckwqkk9O06XMMSNRokAYjrZBnB50JD36BsYI,4873
101
- plain/runtime/__init__.py,sha256=byFYnHrpUCwkpkHtdNhxr9iUdLDCWJjy92HPj30Ilck,2478
102
- plain/runtime/global_settings.py,sha256=44pNJmndS_vkUmX7t83thRcrfrQ9qXdkT8SAlLOXyG4,5695
103
- plain/runtime/user_settings.py,sha256=OzMiEkE6ZQ50nxd1WIqirXPiNuMAQULklYHEzgzLWgA,11027
104
- plain/runtime/utils.py,sha256=p5IuNTzc7Kq-9Ym7etYnt_xqHw5TioxfSkFeq1bKdgk,832
105
- plain/signals/README.md,sha256=XefXqROlDhzw7Z5l_nx6Mhq6n9jjQ-ECGbH0vvhKWYg,272
106
- plain/signals/__init__.py,sha256=eAs0kLqptuP6I31dWXeAqRNji3svplpAV4Ez6ktjwXM,131
107
- plain/signals/dispatch/__init__.py,sha256=FzEygqV9HsM6gopio7O2Oh_X230nA4d5Q9s0sUjMq0E,292
108
- plain/signals/dispatch/dispatcher.py,sha256=VxSlqn9PCOTghPPJLOqZPs6FNQZfV2BJpMfFMSg6Dtc,11531
109
- plain/signals/dispatch/license.txt,sha256=o9EhDhsC4Q5HbmD-IfNGVTEkXtNE33r5rIt3lleJ8gc,1727
110
- plain/templates/AGENTS.md,sha256=o6H_qEZ2eY5IrNmSZG7o7ZYfqdD0SkJm_2VPBaaOo5w,59
111
- plain/templates/README.md,sha256=QAQxoygpc0CE13fh4eH4ZILwl2xc-oMdGKtiZLLrNCk,2565
112
- plain/templates/__init__.py,sha256=bX76FakE9T7mfK3N0deN85HlwHNQpeigytSC9Z8LcOs,451
113
- plain/templates/core.py,sha256=mbcH0yTeFOI3XOg9dYSroXRIcdv9sETEy4HzY-ugwco,1258
114
- plain/templates/jinja/__init__.py,sha256=o49OQ36-DKEKY2jxPpwMj8_CSqBYMPWVqpBfRjP_4wU,1910
115
- plain/templates/jinja/environments.py,sha256=9plifzvQj--aTN1cCpJ2WdzQxZJpzB8S_4hghgQRQT0,2064
116
- plain/templates/jinja/extensions.py,sha256=AEmmmHDbdRW8fhjYDzq9eSSNbp9WHsXenD8tPthjc0s,1351
117
- plain/templates/jinja/filters.py,sha256=ft5XUr4OLeQayn-MSxrycpFLyyN_yEo7j5WhWMwpTOs,1445
118
- plain/templates/jinja/globals.py,sha256=VMpuMZvwWOmb5MbzKK-ox-QEX_WSsXFxq0mm8biJgaU,558
119
- plain/test/README.md,sha256=tNzaVjma0sgowIrViJguCgVy8A2d8mUKApZO2RxTYyU,1140
120
- plain/test/__init__.py,sha256=MhNHtp7MYBl9kq-pMRGY11kJ6kU1I6vOkjNkit1TYRg,94
121
- plain/test/client.py,sha256=OcL8wQDOu6PUNYvwcmslT5IGt81ffcPsXn05n-2n9oA,25128
122
- plain/test/encoding.py,sha256=YJBOIE-BQRA5yl4zHnQy-9l67mJDTFmfy1DQXK0Wk-Q,3199
123
- plain/test/exceptions.py,sha256=b-GHicg87Gh73W3g8QGWuSHi9PrQFVsxgWvEXDLt8gQ,290
124
- plain/urls/README.md,sha256=026RkCK6I0GdqK3RE2QBLcCLIsiwtyKxgI2F0KBX95E,3882
125
- plain/urls/__init__.py,sha256=DFO2OL1IllHW5USPIb5uYvvzf_G-Bl0Qu1zrRLHmWyM,542
126
- plain/urls/converters.py,sha256=s2JZVOdzZC16lgobsI93hygcdH5L0Kj4742WEkXsVcs,1193
127
- plain/urls/exceptions.py,sha256=q4iPh3Aa-zHbA-tw8v6WyX1J1n5WdAady2xvxFuyXB0,114
128
- plain/urls/patterns.py,sha256=3dCLwUaink5j0z5NOqcvzSX7o-eSRTzmYLsnMVmc-7o,8303
129
- plain/urls/resolvers.py,sha256=rk-K4ztP0DxC3h85ANWnzyVAWKhksmdotqP0bWKd9zg,12608
130
- plain/urls/routers.py,sha256=B1fX-FQTxmr-b_YeHQUMPuilLVqOi6-RqgPgu6MtFDY,2831
131
- plain/urls/utils.py,sha256=lKxTX_A3XJpIH7FjlNYju108stY6-8Sw2uVdiSsxOKQ,1249
132
- plain/utils/README.md,sha256=3RTH9t4SBLkYLMlnhpWwp72IjgQhOjYYxpT1gHwRUdE,232
133
- plain/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
134
- plain/utils/cache.py,sha256=iuvOTIfI1s857iVOAPNLK5lkzlrl0fIiBYaiUXWQu40,5303
135
- plain/utils/crypto.py,sha256=kONJB9aFFDHnbFixfigJkzaU-qBAtktCEzbhoHdodoA,2480
136
- plain/utils/datastructures.py,sha256=g4UYTbxIb_n8F9JWMP4dHPwUz71591fHreGATPO4qEc,10240
137
- plain/utils/dateparse.py,sha256=u9_tF85YteXSjW9KQzNg_pcCEFDZS3EGorCddcWU0vE,5351
138
- plain/utils/deconstruct.py,sha256=7NwEFIDCiadAArUBFmiErzDgfIgDWeKqqQFDXwSgQoQ,1830
139
- plain/utils/decorators.py,sha256=mLHOo2jLdvYRo2z8lkeVn2vQErlj7xC6XoLwZBYf_z8,358
140
- plain/utils/duration.py,sha256=l0Gc41-DeyyAmpdy2XG-YO5UKxMf1NDpWIlQuD5hAn0,1162
141
- plain/utils/encoding.py,sha256=T0Shb2xRAR3NPwwoqhpUOB55gDprWzqu72aRiiulv9Y,4251
142
- plain/utils/functional.py,sha256=eJksrhVdkC8HKF56qtVyTOsOnkZB2jMUnXSTGzjJMF4,13331
143
- plain/utils/hashable.py,sha256=uLWobCCh7VcEPJ7xzVGPgigNVuTazYJbyzRzHTCI_wo,739
144
- plain/utils/html.py,sha256=SR8oNrungB5gxJaHbvAaCw_bAiqLQOk09fj-iIXY0i0,3679
145
- plain/utils/http.py,sha256=_YrXfauKOiEDr2beFK4UY2A2Am1Xz1BpZCho1A6I3W4,5471
146
- plain/utils/inspect.py,sha256=O3VMH5f4aGOrVpXJBKtQOxx01XrKnjjz6VO_MCV0xkE,1140
147
- plain/utils/ipv6.py,sha256=pISQ2AIlG8xXlxpphn388q03fq-fOrlu4GZR0YYjQXw,1267
148
- plain/utils/itercompat.py,sha256=lacIDjczhxbwG4ON_KfG1H6VNPOGOpbRhnVhbedo2CY,184
149
- plain/utils/module_loading.py,sha256=11a1JbASB-KbahQe2Dlhiw_2VD71lKKZYmo3y_wfJeI,1640
150
- plain/utils/regex_helper.py,sha256=pAdh_xG52BOyXLsiuIMPFgduUAoWOEje1ZpjhcefxiA,12769
151
- plain/utils/safestring.py,sha256=sawOehuWjr4bkF5jXXCcziILQGoqUcA_eEfsURrAyN0,1801
152
- plain/utils/text.py,sha256=42hJv06sadbWfsaAHNhqCQaP1W9qZ69trWDTS-Xva7k,9496
153
- plain/utils/timesince.py,sha256=a_-ZoPK_s3Pt998CW4rWp0clZ1XyK2x04hCqak2giII,5928
154
- plain/utils/timezone.py,sha256=6u0sE-9RVp0_OCe0Y1KiYYQoq5THWLokZFQYY8jf78g,6221
155
- plain/utils/tree.py,sha256=wdWzmfsgc26YDF2wxhAY3yVxXTixQYqYDKE9mL3L3ZY,4383
156
- plain/views/README.md,sha256=caUSKUhCSs5hdxHC5wIVzKkumPXiuNoOFRnIs3CUHfo,7215
157
- plain/views/__init__.py,sha256=a-N1nkklVohJTtz0yD1MMaS0g66HviEjsKydNVVjvVc,392
158
- plain/views/base.py,sha256=CC9UvMZeAjVvi90vGjoZzsQ0jnhbg3-7qCKQ8-Pb6cg,4184
159
- plain/views/errors.py,sha256=jbNCJIzowwCsEvqyJ3opMeZpPDqTyhtrbqb0VnAm2HE,1263
160
- plain/views/exceptions.py,sha256=b4euI49ZUKS9O8AGAcFfiDpstzkRAuuj_uYQXzWNHME,138
161
- plain/views/forms.py,sha256=ESZOXuo6IeYixp1RZvPb94KplkowRiwO2eGJCM6zJI0,2400
162
- plain/views/objects.py,sha256=v3Vgvdoc1s0QW6JNWWrO5XXy9zF7vgwndgxX1eOSQoE,4999
163
- plain/views/redirect.py,sha256=Xpb3cB7nZYvKgkNqcAxf9Jwm2SWcQ0u2xz4oO5M3vP8,1909
164
- plain/views/templates.py,sha256=oAlebEyfES0rzBhfyEJzFmgLkpkbleA6Eip-8zDp-yk,1863
165
- plain-0.68.0.dist-info/METADATA,sha256=mE7UvxxqukxfFjudAuB0gaGa7gagrESPTRmByQOVb9M,4488
166
- plain-0.68.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
167
- plain-0.68.0.dist-info/entry_points.txt,sha256=wvMzY-iREvfqRgyLm77htPp4j_8CQslLoZA15_AnNo8,171
168
- plain-0.68.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
169
- plain-0.68.0.dist-info/RECORD,,
@@ -1,5 +0,0 @@
1
- [console_scripts]
2
- plain = plain.cli.core:cli
3
- plain-build = plain.cli.build:build
4
- plain-changelog = plain.cli.changelog:changelog
5
- plain-upgrade = plain.cli.upgrade:upgrade