plain 0.49.0__py3-none-any.whl → 0.51.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/CHANGELOG.md ADDED
@@ -0,0 +1,45 @@
1
+ # plain changelog
2
+
3
+ ## [0.51.0](https://github.com/dropseed/plain/releases/plain@0.51.0) (2025-06-24)
4
+
5
+ ### What's changed
6
+
7
+ - New `plain changelog` CLI sub-command to quickly view a package’s changelog from the terminal. Supports `--from`/`--to` flags to limit the version range ([50f0de7](https://github.com/dropseed/plain/commit/50f0de721f263ec6274852bd8838f4e5037b27dc)).
8
+
9
+ ### Upgrade instructions
10
+
11
+ - No changes required
12
+
13
+ ## [0.50.0](https://github.com/dropseed/plain/releases/plain@0.50.0) (2025-06-23)
14
+
15
+ ### What's changed
16
+
17
+ - The URL inspection command has moved; run `plain urls list` instead of the old `plain urls` command ([6146fcb](https://github.com/dropseed/plain/commit/6146fcba536c551277d625bd750c385431ea18eb))
18
+ - `plain preflight` gains a simpler `--database` flag that enables database checks for your default database. The previous behaviour that accepted one or more database aliases has been removed ([d346d81](https://github.com/dropseed/plain/commit/d346d81567d2cc45bbed93caba18a195de10c572))
19
+ - Settings overhaul: use a single `DATABASE` setting instead of `DATABASES`/`DATABASE_ROUTERS` ([d346d81](https://github.com/dropseed/plain/commit/d346d81567d2cc45bbed93caba18a195de10c572))
20
+
21
+ ### Upgrade instructions
22
+
23
+ - Update any scripts or documentation that call `plain urls …`:
24
+ - Replace `plain urls --flat` with `plain urls list --flat`
25
+ - If you invoke preflight checks in CI or locally:
26
+ - Replace `plain preflight --database <alias>` (or multiple aliases) with the new boolean flag: `plain preflight --database`
27
+ - In `settings.py` migrate to the new database configuration:
28
+
29
+ ```python
30
+ # Before
31
+ DATABASES = {
32
+ "default": {
33
+ "ENGINE": "plain.backends.sqlite3",
34
+ "NAME": BASE_DIR / "db.sqlite3",
35
+ }
36
+ }
37
+
38
+ # After
39
+ DATABASE = {
40
+ "ENGINE": "plain.backends.sqlite3",
41
+ "NAME": BASE_DIR / "db.sqlite3",
42
+ }
43
+ ```
44
+
45
+ Remove any `DATABASES` and `DATABASE_ROUTERS` settings – they are no longer read.
plain/cli/README.md CHANGED
@@ -52,7 +52,7 @@ __all__ = [
52
52
  ]
53
53
  ```
54
54
 
55
- ### `plain urls`
55
+ ### `plain urls list`
56
56
 
57
57
  List all the URL patterns in your app.
58
58
 
plain/cli/changelog.py ADDED
@@ -0,0 +1,76 @@
1
+ import re
2
+ from importlib.util import find_spec
3
+ from pathlib import Path
4
+
5
+ import click
6
+ from packaging.version import Version
7
+
8
+ from .output import style_markdown
9
+
10
+
11
+ @click.command("changelog")
12
+ @click.argument("package_label")
13
+ @click.option("--from", "from_version", help="Show entries from this version onwards")
14
+ @click.option("--to", "to_version", help="Show entries up to this version")
15
+ def changelog(package_label, from_version, to_version):
16
+ """Show changelog entries for a package."""
17
+ module_name = package_label.replace("-", ".")
18
+ spec = find_spec(module_name)
19
+ if not spec:
20
+ raise click.ClickException(f"Package {package_label} not found")
21
+
22
+ if spec.origin:
23
+ package_path = Path(spec.origin).resolve().parent
24
+ elif spec.submodule_search_locations:
25
+ package_path = Path(list(spec.submodule_search_locations)[0]).resolve()
26
+ else:
27
+ raise click.ClickException(f"Package {package_label} not found")
28
+
29
+ changelog_path = package_path / "CHANGELOG.md"
30
+ if not changelog_path.exists():
31
+ raise click.ClickException(f"Changelog not found for {package_label}")
32
+
33
+ content = changelog_path.read_text()
34
+
35
+ entries = []
36
+ current_version = None
37
+ current_lines = []
38
+ version_re = re.compile(r"^## \[([^\]]+)\]")
39
+
40
+ for line in content.splitlines(keepends=True):
41
+ m = version_re.match(line)
42
+ if m:
43
+ if current_version is not None:
44
+ entries.append((current_version, current_lines))
45
+ current_version = m.group(1)
46
+ current_lines = [line]
47
+ else:
48
+ if current_version is not None:
49
+ current_lines.append(line)
50
+
51
+ if current_version is not None:
52
+ entries.append((current_version, current_lines))
53
+
54
+ def version_found(version):
55
+ return any(Version(v) == Version(version) for v, _ in entries)
56
+
57
+ if from_version and not version_found(from_version):
58
+ click.secho(
59
+ f"Warning: version {from_version} not found in changelog",
60
+ fg="yellow",
61
+ err=True,
62
+ )
63
+
64
+ selected_lines = []
65
+ for version, lines in entries:
66
+ v = Version(version)
67
+ if from_version and v <= Version(from_version):
68
+ continue
69
+ if to_version and v > Version(to_version):
70
+ continue
71
+ selected_lines.extend(lines)
72
+
73
+ if not selected_lines:
74
+ return
75
+
76
+ click.echo(style_markdown("".join(selected_lines)))
plain/cli/core.py CHANGED
@@ -7,6 +7,7 @@ import plain.runtime
7
7
  from plain.exceptions import ImproperlyConfigured
8
8
 
9
9
  from .build import build
10
+ from .changelog import changelog
10
11
  from .chores import chores
11
12
  from .docs import docs
12
13
  from .formatting import PlainContext
@@ -32,6 +33,7 @@ plain_cli.add_command(chores)
32
33
  plain_cli.add_command(build)
33
34
  plain_cli.add_command(utils)
34
35
  plain_cli.add_command(urls)
36
+ plain_cli.add_command(changelog)
35
37
  plain_cli.add_command(setting)
36
38
  plain_cli.add_command(shell)
37
39
  plain_cli.add_command(run)
plain/cli/docs.py CHANGED
@@ -7,6 +7,8 @@ import click
7
7
 
8
8
  from plain.packages import packages_registry
9
9
 
10
+ from .output import iterate_markdown
11
+
10
12
 
11
13
  @click.command()
12
14
  @click.option("--llm", "llm", is_flag=True)
@@ -59,43 +61,7 @@ def docs(module, llm, open):
59
61
  if open:
60
62
  click.launch(str(readme_path))
61
63
  else:
62
-
63
- def _iterate_markdown(content):
64
- """
65
- Iterator that does basic markdown for a Click pager.
66
-
67
- Headings are yellow and bright, code blocks are indented.
68
- """
69
-
70
- in_code_block = False
71
- for line in content.splitlines():
72
- if line.startswith("```"):
73
- in_code_block = not in_code_block
74
-
75
- if in_code_block:
76
- yield click.style(line, dim=True)
77
- elif line.startswith("# "):
78
- yield click.style(line, fg="yellow", bold=True)
79
- elif line.startswith("## "):
80
- yield click.style(line, fg="yellow", bold=True)
81
- elif line.startswith("### "):
82
- yield click.style(line, fg="yellow", bold=True)
83
- elif line.startswith("#### "):
84
- yield click.style(line, fg="yellow", bold=True)
85
- elif line.startswith("##### "):
86
- yield click.style(line, fg="yellow", bold=True)
87
- elif line.startswith("###### "):
88
- yield click.style(line, fg="yellow", bold=True)
89
- elif line.startswith("**") and line.endswith("**"):
90
- yield click.style(line, bold=True)
91
- elif line.startswith("> "):
92
- yield click.style(line, italic=True)
93
- else:
94
- yield line
95
-
96
- yield "\n"
97
-
98
- click.echo_via_pager(_iterate_markdown(readme_path.read_text()))
64
+ click.echo_via_pager(iterate_markdown(readme_path.read_text()))
99
65
 
100
66
 
101
67
  class LLMDocs:
plain/cli/output.py ADDED
@@ -0,0 +1,41 @@
1
+ import click
2
+
3
+
4
+ def style_markdown(content):
5
+ return "".join(iterate_markdown(content))
6
+
7
+
8
+ def iterate_markdown(content):
9
+ """
10
+ Iterator that does basic markdown for a Click pager.
11
+
12
+ Headings are yellow and bright, code blocks are indented.
13
+ """
14
+
15
+ in_code_block = False
16
+ for line in content.splitlines():
17
+ if line.startswith("```"):
18
+ in_code_block = not in_code_block
19
+
20
+ if in_code_block:
21
+ yield click.style(line, dim=True)
22
+ elif line.startswith("# "):
23
+ yield click.style(line, fg="yellow", bold=True)
24
+ elif line.startswith("## "):
25
+ yield click.style(line, fg="yellow", bold=True)
26
+ elif line.startswith("### "):
27
+ yield click.style(line, fg="yellow", bold=True)
28
+ elif line.startswith("#### "):
29
+ yield click.style(line, fg="yellow", bold=True)
30
+ elif line.startswith("##### "):
31
+ yield click.style(line, fg="yellow", bold=True)
32
+ elif line.startswith("###### "):
33
+ yield click.style(line, fg="yellow", bold=True)
34
+ elif line.startswith("**") and line.endswith("**"):
35
+ yield click.style(line, bold=True)
36
+ elif line.startswith("> "):
37
+ yield click.style(line, italic=True)
38
+ else:
39
+ yield line
40
+
41
+ yield "\n"
plain/cli/preflight.py CHANGED
@@ -19,11 +19,10 @@ from plain.packages import packages_registry
19
19
  )
20
20
  @click.option(
21
21
  "--database",
22
- "databases",
23
- multiple=True,
24
- help="Run database related checks against these aliases.",
22
+ is_flag=True,
23
+ help="Run database related checks as part of preflight.",
25
24
  )
26
- def preflight_checks(package_label, deploy, fail_level, databases):
25
+ def preflight_checks(package_label, deploy, fail_level, database):
27
26
  """
28
27
  Use the system check framework to validate entire Plain project.
29
28
  Raise CommandError for any serious message (error or critical errors).
@@ -42,7 +41,7 @@ def preflight_checks(package_label, deploy, fail_level, databases):
42
41
  all_issues = preflight.run_checks(
43
42
  package_configs=package_configs,
44
43
  include_deployment_checks=include_deployment_checks,
45
- databases=databases,
44
+ database=database,
46
45
  )
47
46
 
48
47
  header, body, footer = "", "", ""
plain/cli/urls.py CHANGED
@@ -3,9 +3,15 @@ import sys
3
3
  import click
4
4
 
5
5
 
6
- @click.command()
6
+ @click.group()
7
+ def urls():
8
+ """URL related commands"""
9
+ pass
10
+
11
+
12
+ @urls.command("list")
7
13
  @click.option("--flat", is_flag=True, help="List all URLs in a flat list")
8
- def urls(flat):
14
+ def list_urls(flat):
9
15
  """Print all URL patterns under settings.URLS_ROUTER"""
10
16
  from plain.runtime import settings
11
17
  from plain.urls import URLResolver, get_resolver
@@ -42,7 +42,7 @@ class CheckRegistry:
42
42
  self,
43
43
  package_configs=None,
44
44
  include_deployment_checks=False,
45
- databases=None,
45
+ database=False,
46
46
  ):
47
47
  """
48
48
  Run all registered checks and return list of Errors and Warnings.
@@ -51,7 +51,7 @@ class CheckRegistry:
51
51
  checks = self.get_checks(include_deployment_checks)
52
52
 
53
53
  for check in checks:
54
- new_errors = check(package_configs=package_configs, databases=databases)
54
+ new_errors = check(package_configs=package_configs, database=database)
55
55
  if not is_iterable(new_errors):
56
56
  raise TypeError(
57
57
  f"The function {check!r} did not return a list. All functions "
plain/runtime/README.md CHANGED
@@ -79,28 +79,21 @@ from os import environ
79
79
 
80
80
  from . import database_url
81
81
 
82
- # Make DATABASES a required setting
83
- DATABASES: dict
82
+ # Make DATABASE a required setting
83
+ DATABASE: dict
84
84
 
85
- # Automatically configure DATABASES if a DATABASE_URL was given in the environment
85
+ # Automatically configure DATABASE if a DATABASE_URL was given in the environment
86
86
  if "DATABASE_URL" in environ:
87
- DATABASES = {
88
- "default": database_url.parse_database_url(
89
- environ["DATABASE_URL"],
90
- # Enable persistent connections by default
91
- conn_max_age=int(environ.get("DATABASE_CONN_MAX_AGE", 600)),
92
- conn_health_checks=environ.get(
93
- "DATABASE_CONN_HEALTH_CHECKS", "true"
94
- ).lower()
95
- in [
96
- "true",
97
- "1",
98
- ],
99
- )
100
- }
101
-
102
- # Classes used to implement DB routing behavior.
103
- DATABASE_ROUTERS = []
87
+ DATABASE = database_url.parse_database_url(
88
+ environ["DATABASE_URL"],
89
+ # Enable persistent connections by default
90
+ conn_max_age=int(environ.get("DATABASE_CONN_MAX_AGE", 600)),
91
+ conn_health_checks=environ.get("DATABASE_CONN_HEALTH_CHECKS", "true").lower()
92
+ in [
93
+ "true",
94
+ "1",
95
+ ],
96
+ )
104
97
  ```
105
98
 
106
99
  ### .env files
plain/test/client.py CHANGED
@@ -6,7 +6,7 @@ from http.cookies import SimpleCookie
6
6
  from io import BytesIO, IOBase
7
7
  from urllib.parse import unquote_to_bytes, urljoin, urlparse, urlsplit
8
8
 
9
- from plain.http import HttpHeaders, HttpRequest, QueryDict
9
+ from plain.http import HttpHeaders, QueryDict
10
10
  from plain.internal import internalcode
11
11
  from plain.internal.handlers.base import BaseHandler
12
12
  from plain.internal.handlers.wsgi import WSGIRequest
@@ -775,57 +775,20 @@ class Client(RequestFactory):
775
775
  @property
776
776
  def session(self):
777
777
  """Return the current session variables."""
778
- from plain.sessions import SessionStore
778
+ from plain.sessions.test import get_client_session
779
779
 
780
- cookie = self.cookies.get(settings.SESSION_COOKIE_NAME)
781
- if cookie:
782
- return SessionStore(cookie.value)
783
- session = SessionStore()
784
- session.save()
785
- self.cookies[settings.SESSION_COOKIE_NAME] = session.session_key
786
- return session
780
+ return get_client_session(self)
787
781
 
788
782
  def force_login(self, user):
789
- self._login(user)
783
+ from plain.auth.test import login_client
790
784
 
791
- def _login(self, user):
792
- from plain.auth import login
793
- from plain.sessions import SessionStore
794
-
795
- # Create a fake request to store login details.
796
- request = HttpRequest()
797
- if self.session:
798
- request.session = self.session
799
- else:
800
- request.session = SessionStore()
801
- login(request, user)
802
- # Save the session values.
803
- request.session.save()
804
- # Set the cookie to represent the session.
805
- session_cookie = settings.SESSION_COOKIE_NAME
806
- self.cookies[session_cookie] = request.session.session_key
807
- cookie_data = {
808
- "max-age": None,
809
- "path": "/",
810
- "domain": settings.SESSION_COOKIE_DOMAIN,
811
- "secure": settings.SESSION_COOKIE_SECURE or None,
812
- "expires": None,
813
- }
814
- self.cookies[session_cookie].update(cookie_data)
785
+ login_client(self, user)
815
786
 
816
787
  def logout(self):
817
788
  """Log out the user by removing the cookies and session object."""
818
- from plain.auth import get_user, logout
819
- from plain.sessions import SessionStore
789
+ from plain.auth.test import logout_client
820
790
 
821
- request = HttpRequest()
822
- if self.session:
823
- request.session = self.session
824
- request.user = get_user(request)
825
- else:
826
- request.session = SessionStore()
827
- logout(request)
828
- self.cookies = SimpleCookie()
791
+ logout_client(self)
829
792
 
830
793
  def _parse_json(self, response, **extra):
831
794
  if not hasattr(response, "_json"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain
3
- Version: 0.49.0
3
+ Version: 0.51.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
@@ -1,3 +1,4 @@
1
+ plain/CHANGELOG.md,sha256=lE0zfshrzDi6rsj59KWtZdcM9cqkCtqf7XrC4Tb7JUA,1996
1
2
  plain/README.md,sha256=gik6DBZcJAITcm4WRq_L53AxkjY45eQLafyTCSf0CKE,3986
2
3
  plain/__main__.py,sha256=GK39854Lc_LO_JP8DzY9Y2MIQ4cQEl7SXFJy244-lC8,110
3
4
  plain/debug.py,sha256=abPkJY4aSbBYGEYSZST_ZY3ohXPGDdz9uWQBYRqfd3M,730
@@ -17,22 +18,24 @@ plain/assets/views.py,sha256=T_0Qh6v9qBerEBYbhToigwOzsij-x1z_R-1zETQcIh0,9447
17
18
  plain/chores/README.md,sha256=Da8Nw8ZF7PlAE_iVb0AqJGbLOu0F6HC0cj1K451KBak,1946
18
19
  plain/chores/__init__.py,sha256=r9TXtQCH-VbvfnIJ5F8FxgQC35GRWFOfmMZN3q9niLg,67
19
20
  plain/chores/registry.py,sha256=V3WjuekRI22LFvJbqSkUXQtiOtuE2ZK8gKV1TRvxRUI,1866
20
- plain/cli/README.md,sha256=nkcpS_mWPZ6JbnlKh4fq-b7AlmItAQsT78XAqRlwqNg,2017
21
+ plain/cli/README.md,sha256=GzBry6mEilhM80SfVUg02ydGwAk0m-s6FAqQR1nRsMM,2022
21
22
  plain/cli/__init__.py,sha256=6w9T7K2WrPwh6DcaMb2oNt_CWU6Bc57nUTO2Bt1p38Y,63
22
23
  plain/cli/build.py,sha256=dKUYBNegvb6QNckR7XZ7CJJtINwZcmDvbUdv2dWwjf8,3226
24
+ plain/cli/changelog.py,sha256=VRcL0v_r8tPSe-6fGGsa-OCgdhLMrwj6TnpmPilQb6Y,2441
23
25
  plain/cli/chores.py,sha256=xXSSFvr8T5jWfLWqe6E8YVMw1BkQxyOHHVuY0x9RH0A,2412
24
- plain/cli/core.py,sha256=h8gjeBYQzYTzpmeDMAJTdVDOEoNCNcvnxml-KIsiRPo,2925
25
- plain/cli/docs.py,sha256=2CpTv5k-TNWf593tPiglvUVXWBGdfPmbGf8vl5AfJwU,8995
26
+ plain/cli/core.py,sha256=D3t83ujjjHayblM-RuttrGoNf8hMV9-l3zQsbhVAjWU,2991
27
+ plain/cli/docs.py,sha256=KCJCP_OVFb34zOkA6x7X6-iGFzx2tv4ZgXAM99TjWNg,7443
26
28
  plain/cli/formatting.py,sha256=1hZH13y1qwHcU2K2_Na388nw9uvoeQH8LrWL-O9h8Yc,2207
27
29
  plain/cli/help.py,sha256=otRSGxOJ5V8JMjpdZ8XYqUbdlYdJvxOMzQroLOWw-l0,801
28
- plain/cli/preflight.py,sha256=NKyYjcoDjigzfJIDhf7A7degYadaUI05Bw7U9OQ73vs,4170
30
+ plain/cli/output.py,sha256=Fe3xS6Va4Bi1ZNrqi0nh09THTsdCyMW2b9SPY5I4n-o,1318
31
+ plain/cli/preflight.py,sha256=FWFwMZ0W_t8ObTTRMnBmaiGN8PqdEAWgmSEPGDwZFpA,4148
29
32
  plain/cli/print.py,sha256=XraUYrgODOJquIiEv78wSCYGRBplHXtXSS9QtFG5hqY,217
30
33
  plain/cli/registry.py,sha256=yKVMSDjW8g10nlV9sPXFGJQmhC_U-k4J4kM7N2OQVLA,1467
31
34
  plain/cli/scaffold.py,sha256=mcywA9DzfwoBSqWl5-Zpgcy1mTNUGEgdvoxXUrGcEVk,1351
32
35
  plain/cli/settings.py,sha256=9cx4bue664I2P7kUedlf4YhCPB0tSKSE4Q8mGyzEv2o,1995
33
36
  plain/cli/shell.py,sha256=iIwvlTdTBjLBBUdXMAmIRWSoynszOZI79-mrBg4RegU,1373
34
37
  plain/cli/startup.py,sha256=wLaFuyUb4ewWhtehBCGicrRCXIIGCRbeCT3ce9hUv-A,1022
35
- plain/cli/urls.py,sha256=CS9NFpwZBWveAR8F3YsoUNySDEK_PwF73oSgLDfkOdI,3776
38
+ plain/cli/urls.py,sha256=7FOvLjfV1GsYKnb7SGlIgEfchQcrkWdYU1nY6aazGBI,3855
36
39
  plain/cli/utils.py,sha256=VwlIh0z7XxzVV8I3qM2kZo07fkJFPoeeVZa1ODG616k,258
37
40
  plain/csrf/README.md,sha256=nxCpPk1HF5eAM-7paxg9D-9RVCU9jXsSPAVHkJvA_DU,717
38
41
  plain/csrf/middleware.py,sha256=U3B9R7ciO_UAf7O3jdNtVu6QZ_3Yrm8isRdnW6bVKX4,17401
@@ -79,10 +82,10 @@ plain/preflight/README.md,sha256=9fE0Ql2JNd3CI420eg1sP_xmaim-6Ejlzi_hfk3tVS0,151
79
82
  plain/preflight/__init__.py,sha256=j4-yPnrM5hmjumrdkBLOQjFHzRHpA6wCjiFpMNBjIqY,619
80
83
  plain/preflight/files.py,sha256=D_pBSwRXpXy2-3FWywweozuxrhIaR8w5hpPA2d6XMPs,522
81
84
  plain/preflight/messages.py,sha256=B6VyXzu7HTJHaPVK4G1L_1HVHG87CT7JPtcDk8QYSeE,2322
82
- plain/preflight/registry.py,sha256=wHLq6LSMkKunkxElBmNwzMzQx3tc6OGYeKyOOi0tuyQ,2333
85
+ plain/preflight/registry.py,sha256=vcqzaE1MIneNL_ydKPy_1zrSThnzsrWARSClLCJ-4b8,2331
83
86
  plain/preflight/security.py,sha256=oxUZBp2M0bpBfUoLYepIxoex2Y90nyjlrL8XU8UTHYY,2438
84
87
  plain/preflight/urls.py,sha256=cQ-WnFa_5oztpKdtwhuIGb7pXEml__bHsjs1SWO2YNI,1468
85
- plain/runtime/README.md,sha256=yPcrJKnFEqkrb0KlhLZi2VInV-LCl6ENOZs7mOHlhi0,4753
88
+ plain/runtime/README.md,sha256=1h30eRTg5-lY-G7GF_4TdUiUcOLVzKR15mSrmyeU8eI,4584
86
89
  plain/runtime/__init__.py,sha256=8GtvKROf3HUCtneDYXTbEioPcCtwnV76dP57n2PnjuE,2343
87
90
  plain/runtime/global_settings.py,sha256=MpJ6vtBMO2EYALaKXrtgcGoxLh9Y549zwwErC5D5K7I,5343
88
91
  plain/runtime/user_settings.py,sha256=OzMiEkE6ZQ50nxd1WIqirXPiNuMAQULklYHEzgzLWgA,11027
@@ -101,7 +104,7 @@ plain/templates/jinja/filters.py,sha256=t_u8BkWtEpJFLbLywONxWKrenSzOvDJhfOLwlZiX
101
104
  plain/templates/jinja/globals.py,sha256=VMpuMZvwWOmb5MbzKK-ox-QEX_WSsXFxq0mm8biJgaU,558
102
105
  plain/test/README.md,sha256=fv4YzziU2QxgcNHSgv7aDUO45sDOofVuCNrV1NPbWzo,1106
103
106
  plain/test/__init__.py,sha256=MhNHtp7MYBl9kq-pMRGY11kJ6kU1I6vOkjNkit1TYRg,94
104
- plain/test/client.py,sha256=lqzOf8EJo_u54dW_oiPy0m5mW-Nt3-CWyrBh9_MJnms,26930
107
+ plain/test/client.py,sha256=XjLjkeDl1rQRaFoeiCvvD5GXfxIxpuic2OnxjoX05tA,25573
105
108
  plain/test/encoding.py,sha256=YJBOIE-BQRA5yl4zHnQy-9l67mJDTFmfy1DQXK0Wk-Q,3199
106
109
  plain/test/exceptions.py,sha256=b-GHicg87Gh73W3g8QGWuSHi9PrQFVsxgWvEXDLt8gQ,290
107
110
  plain/urls/README.md,sha256=ijFGmrkUY9buBqO_i1GZaN3V55vl9xwEADtHOx_ZHPY,3724
@@ -146,8 +149,8 @@ plain/views/forms.py,sha256=ESZOXuo6IeYixp1RZvPb94KplkowRiwO2eGJCM6zJI0,2400
146
149
  plain/views/objects.py,sha256=GGbcfg_9fPZ-PiaBwIHG2e__8GfWDR7JQtQ15wTyiHg,5970
147
150
  plain/views/redirect.py,sha256=daq2cQIkdDF78bt43sjuZxRAyJm_t_SKw6tyPmiXPIc,1985
148
151
  plain/views/templates.py,sha256=ivkI7LU7BXDQ0d4Geab96Is4-Cp03KbIntXRT1J8e6I,2139
149
- plain-0.49.0.dist-info/METADATA,sha256=h5KgVsVtWFjd4CveudNI0w7_TsFeroqviAiWssBGNwE,4297
150
- plain-0.49.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
151
- plain-0.49.0.dist-info/entry_points.txt,sha256=1Ys2lsSeMepD1vz8RSrJopna0RQfUd951vYvCRsvl6A,45
152
- plain-0.49.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
153
- plain-0.49.0.dist-info/RECORD,,
152
+ plain-0.51.0.dist-info/METADATA,sha256=xzYeAOLD7gvPsfMUMhQJIR0nsBc6VAUZ08bZ1Hyodao,4297
153
+ plain-0.51.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
154
+ plain-0.51.0.dist-info/entry_points.txt,sha256=1Ys2lsSeMepD1vz8RSrJopna0RQfUd951vYvCRsvl6A,45
155
+ plain-0.51.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
156
+ plain-0.51.0.dist-info/RECORD,,
File without changes