plain 0.50.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 +30 -18
- plain/cli/changelog.py +76 -0
- plain/cli/core.py +2 -0
- plain/cli/docs.py +3 -37
- plain/cli/output.py +41 -0
- {plain-0.50.0.dist-info → plain-0.51.0.dist-info}/METADATA +1 -1
- {plain-0.50.0.dist-info → plain-0.51.0.dist-info}/RECORD +10 -8
- {plain-0.50.0.dist-info → plain-0.51.0.dist-info}/WHEEL +0 -0
- {plain-0.50.0.dist-info → plain-0.51.0.dist-info}/entry_points.txt +0 -0
- {plain-0.50.0.dist-info → plain-0.51.0.dist-info}/licenses/LICENSE +0 -0
plain/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# plain changelog
|
2
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
|
+
|
3
13
|
## [0.50.0](https://github.com/dropseed/plain/releases/plain@0.50.0) (2025-06-23)
|
4
14
|
|
5
15
|
### What's changed
|
@@ -11,23 +21,25 @@
|
|
11
21
|
### Upgrade instructions
|
12
22
|
|
13
23
|
- Update any scripts or documentation that call `plain urls …`:
|
14
|
-
|
24
|
+
- Replace `plain urls --flat` with `plain urls list --flat`
|
15
25
|
- If you invoke preflight checks in CI or locally:
|
16
|
-
|
26
|
+
- Replace `plain preflight --database <alias>` (or multiple aliases) with the new boolean flag: `plain preflight --database`
|
17
27
|
- In `settings.py` migrate to the new database configuration:
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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/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"
|
@@ -1,4 +1,4 @@
|
|
1
|
-
plain/CHANGELOG.md,sha256=
|
1
|
+
plain/CHANGELOG.md,sha256=lE0zfshrzDi6rsj59KWtZdcM9cqkCtqf7XrC4Tb7JUA,1996
|
2
2
|
plain/README.md,sha256=gik6DBZcJAITcm4WRq_L53AxkjY45eQLafyTCSf0CKE,3986
|
3
3
|
plain/__main__.py,sha256=GK39854Lc_LO_JP8DzY9Y2MIQ4cQEl7SXFJy244-lC8,110
|
4
4
|
plain/debug.py,sha256=abPkJY4aSbBYGEYSZST_ZY3ohXPGDdz9uWQBYRqfd3M,730
|
@@ -21,11 +21,13 @@ plain/chores/registry.py,sha256=V3WjuekRI22LFvJbqSkUXQtiOtuE2ZK8gKV1TRvxRUI,1866
|
|
21
21
|
plain/cli/README.md,sha256=GzBry6mEilhM80SfVUg02ydGwAk0m-s6FAqQR1nRsMM,2022
|
22
22
|
plain/cli/__init__.py,sha256=6w9T7K2WrPwh6DcaMb2oNt_CWU6Bc57nUTO2Bt1p38Y,63
|
23
23
|
plain/cli/build.py,sha256=dKUYBNegvb6QNckR7XZ7CJJtINwZcmDvbUdv2dWwjf8,3226
|
24
|
+
plain/cli/changelog.py,sha256=VRcL0v_r8tPSe-6fGGsa-OCgdhLMrwj6TnpmPilQb6Y,2441
|
24
25
|
plain/cli/chores.py,sha256=xXSSFvr8T5jWfLWqe6E8YVMw1BkQxyOHHVuY0x9RH0A,2412
|
25
|
-
plain/cli/core.py,sha256=
|
26
|
-
plain/cli/docs.py,sha256=
|
26
|
+
plain/cli/core.py,sha256=D3t83ujjjHayblM-RuttrGoNf8hMV9-l3zQsbhVAjWU,2991
|
27
|
+
plain/cli/docs.py,sha256=KCJCP_OVFb34zOkA6x7X6-iGFzx2tv4ZgXAM99TjWNg,7443
|
27
28
|
plain/cli/formatting.py,sha256=1hZH13y1qwHcU2K2_Na388nw9uvoeQH8LrWL-O9h8Yc,2207
|
28
29
|
plain/cli/help.py,sha256=otRSGxOJ5V8JMjpdZ8XYqUbdlYdJvxOMzQroLOWw-l0,801
|
30
|
+
plain/cli/output.py,sha256=Fe3xS6Va4Bi1ZNrqi0nh09THTsdCyMW2b9SPY5I4n-o,1318
|
29
31
|
plain/cli/preflight.py,sha256=FWFwMZ0W_t8ObTTRMnBmaiGN8PqdEAWgmSEPGDwZFpA,4148
|
30
32
|
plain/cli/print.py,sha256=XraUYrgODOJquIiEv78wSCYGRBplHXtXSS9QtFG5hqY,217
|
31
33
|
plain/cli/registry.py,sha256=yKVMSDjW8g10nlV9sPXFGJQmhC_U-k4J4kM7N2OQVLA,1467
|
@@ -147,8 +149,8 @@ plain/views/forms.py,sha256=ESZOXuo6IeYixp1RZvPb94KplkowRiwO2eGJCM6zJI0,2400
|
|
147
149
|
plain/views/objects.py,sha256=GGbcfg_9fPZ-PiaBwIHG2e__8GfWDR7JQtQ15wTyiHg,5970
|
148
150
|
plain/views/redirect.py,sha256=daq2cQIkdDF78bt43sjuZxRAyJm_t_SKw6tyPmiXPIc,1985
|
149
151
|
plain/views/templates.py,sha256=ivkI7LU7BXDQ0d4Geab96Is4-Cp03KbIntXRT1J8e6I,2139
|
150
|
-
plain-0.
|
151
|
-
plain-0.
|
152
|
-
plain-0.
|
153
|
-
plain-0.
|
154
|
-
plain-0.
|
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
|
File without changes
|
File without changes
|