afterpython 0.4.0__py3-none-any.whl → 0.4.1__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.
- afterpython/builders/__init__.py +2 -0
- afterpython/builders/build_pdoc.py +7 -0
- afterpython/builders/comments_json.py +107 -0
- afterpython/cli/commands/build.py +2 -0
- afterpython/cli/commands/init.py +113 -51
- afterpython/const.py +1 -1
- afterpython/templates/afterpython-template.toml +6 -0
- afterpython/templates/ci-workflow-template.yml +10 -10
- afterpython/templates/deploy-workflow-template.yml +2 -2
- afterpython/templates/pdoc/custom.css +37 -0
- afterpython/templates/pdoc/frame.html.jinja2 +15 -1
- afterpython/templates/pdoc/syntax-highlighting.css +155 -0
- afterpython/templates/pdoc/theme.css +44 -0
- afterpython/templates/release-workflow-template.yml +1 -1
- afterpython/templates/ruff-template.toml +1 -1
- afterpython/tools/myst.py +36 -19
- {afterpython-0.4.0.dist-info → afterpython-0.4.1.dist-info}/METADATA +16 -15
- {afterpython-0.4.0.dist-info → afterpython-0.4.1.dist-info}/RECORD +20 -16
- {afterpython-0.4.0.dist-info → afterpython-0.4.1.dist-info}/WHEEL +1 -1
- {afterpython-0.4.0.dist-info → afterpython-0.4.1.dist-info}/entry_points.txt +0 -0
afterpython/builders/__init__.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from afterpython.builders.build_pdoc import build_pdoc
|
|
2
|
+
from afterpython.builders.comments_json import build_comments_json
|
|
2
3
|
from afterpython.builders.content_json import build_content_json
|
|
3
4
|
from afterpython.builders.faq_json import build_faq_json
|
|
4
5
|
from afterpython.builders.index_md import (
|
|
@@ -13,6 +14,7 @@ from afterpython.builders.metadata import build_metadata
|
|
|
13
14
|
from afterpython.builders.url_md import build_url_md
|
|
14
15
|
|
|
15
16
|
__all__ = (
|
|
17
|
+
"build_comments_json",
|
|
16
18
|
"build_content_json",
|
|
17
19
|
"build_faq_json",
|
|
18
20
|
"build_jupyter_notebooks",
|
|
@@ -19,9 +19,15 @@ def build_pdoc(base_path: str) -> None:
|
|
|
19
19
|
project logo appears in the top-left of every API page and links
|
|
20
20
|
back to the project website root (matches MyST's UX).
|
|
21
21
|
"""
|
|
22
|
+
from afterpython._io.toml import _from_tomlkit
|
|
23
|
+
from afterpython.tools._afterpython import read_afterpython
|
|
24
|
+
|
|
22
25
|
package_dir = find_package_directory()
|
|
23
26
|
output_dir = ap.paths.build_path / "api_reference"
|
|
24
27
|
template_dir = ap.paths.templates_path / "pdoc"
|
|
28
|
+
# e.g. "google"; unset leaves it to pdoc (a module's __docformat__, else restructuredtext)
|
|
29
|
+
website = _from_tomlkit(read_afterpython().get("website", {}))
|
|
30
|
+
docformat = website.get("api_reference_docformat")
|
|
25
31
|
|
|
26
32
|
click.echo("Building api_reference/...")
|
|
27
33
|
|
|
@@ -45,6 +51,7 @@ def build_pdoc(base_path: str) -> None:
|
|
|
45
51
|
f"{base_path}/",
|
|
46
52
|
"--template-directory",
|
|
47
53
|
str(template_dir),
|
|
54
|
+
*(["--docformat", str(docformat)] if docformat else []),
|
|
48
55
|
str(package_dir),
|
|
49
56
|
],
|
|
50
57
|
env=env,
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
import afterpython as ap
|
|
9
|
+
|
|
10
|
+
GISCUS_API = "https://giscus.app/api/discussions/categories"
|
|
11
|
+
DEFAULT_CATEGORY = "Announcements"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _read_comments_config() -> dict:
|
|
15
|
+
from afterpython._io.toml import _from_tomlkit
|
|
16
|
+
from afterpython.tools._afterpython import read_afterpython
|
|
17
|
+
|
|
18
|
+
website = _from_tomlkit(read_afterpython().get("website", {}))
|
|
19
|
+
return dict(website.get("comments", {}))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _get_github_repo() -> str | None:
|
|
23
|
+
"""Return "owner/repo" from pyproject.toml's repository URL, or the git remote."""
|
|
24
|
+
from afterpython.tools._git import get_github_url
|
|
25
|
+
from afterpython.tools.pyproject import read_metadata
|
|
26
|
+
|
|
27
|
+
url = str(read_metadata().urls.get("repository", "")) or get_github_url() or ""
|
|
28
|
+
match = re.search(r"github\.com[/:]([^/]+)/([^/]+?)(?:\.git)?/?$", url)
|
|
29
|
+
return f"{match[1]}/{match[2]}" if match else None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _fetch_giscus_categories(repo: str) -> dict:
|
|
33
|
+
"""Fetch the repo and category IDs giscus needs. Raises click.ClickException on failure."""
|
|
34
|
+
import httpx2
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
response = httpx2.get(GISCUS_API, params={"repo": repo}, timeout=10.0)
|
|
38
|
+
except httpx2.HTTPError as e:
|
|
39
|
+
raise click.ClickException(f"could not reach giscus.app ({e})") from e
|
|
40
|
+
try:
|
|
41
|
+
data = response.json()
|
|
42
|
+
except ValueError:
|
|
43
|
+
data = {}
|
|
44
|
+
if response.status_code != 200 or "repositoryId" not in data:
|
|
45
|
+
error = data.get("error") or f"HTTP {response.status_code}"
|
|
46
|
+
raise click.ClickException(error)
|
|
47
|
+
return data
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def build_comments_json():
|
|
51
|
+
"""Build comments.json for the giscus comment section on content pages.
|
|
52
|
+
|
|
53
|
+
Reads [website.comments] in afterpython.toml. The website template only
|
|
54
|
+
shows comments when comments.json exists, so a disabled or failed setup
|
|
55
|
+
just leaves it out. Never fails the build.
|
|
56
|
+
"""
|
|
57
|
+
stale = ap.paths.website_path / "static" / "comments.json"
|
|
58
|
+
stale.unlink(missing_ok=True)
|
|
59
|
+
|
|
60
|
+
config = _read_comments_config()
|
|
61
|
+
if not config.get("enabled", False):
|
|
62
|
+
click.echo("Comments are disabled, skip building comments.json")
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
def warn(reason: str):
|
|
66
|
+
click.secho(f"Warning: skip comments, {reason}", fg="yellow")
|
|
67
|
+
|
|
68
|
+
repo = _get_github_repo()
|
|
69
|
+
if not repo:
|
|
70
|
+
warn(
|
|
71
|
+
"no GitHub repository found "
|
|
72
|
+
"(set [project.urls] repository in pyproject.toml)"
|
|
73
|
+
)
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
category = str(config.get("category") or DEFAULT_CATEGORY)
|
|
77
|
+
try:
|
|
78
|
+
data = _fetch_giscus_categories(repo)
|
|
79
|
+
except click.ClickException as e:
|
|
80
|
+
warn(
|
|
81
|
+
f"giscus is not ready for {repo}: {e.message}\n"
|
|
82
|
+
f" 1. Enable Discussions: https://github.com/{repo}/settings\n"
|
|
83
|
+
" 2. Install the giscus app: https://github.com/apps/giscus\n"
|
|
84
|
+
" Or set [website.comments] enabled = false in afterpython.toml"
|
|
85
|
+
)
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
category_id = next(
|
|
89
|
+
(c["id"] for c in data.get("categories", []) if c["name"] == category), None
|
|
90
|
+
)
|
|
91
|
+
if not category_id:
|
|
92
|
+
names = ", ".join(c["name"] for c in data.get("categories", []))
|
|
93
|
+
warn(
|
|
94
|
+
f'Discussions category "{category}" not found in {repo} '
|
|
95
|
+
f"(available: {names or 'none'})"
|
|
96
|
+
)
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
click.echo(f"Building comments.json ({repo}, {category})...")
|
|
100
|
+
comments = {
|
|
101
|
+
"repo": repo,
|
|
102
|
+
"repoId": data["repositoryId"],
|
|
103
|
+
"category": category,
|
|
104
|
+
"categoryId": category_id,
|
|
105
|
+
}
|
|
106
|
+
with open(ap.paths.build_path / "comments.json", "w") as f:
|
|
107
|
+
json.dump(comments, f, indent=2)
|
|
@@ -17,6 +17,7 @@ from click.exceptions import Exit
|
|
|
17
17
|
|
|
18
18
|
import afterpython as ap
|
|
19
19
|
from afterpython.builders import (
|
|
20
|
+
build_comments_json,
|
|
20
21
|
build_content_json,
|
|
21
22
|
build_faq_json,
|
|
22
23
|
build_jupyter_notebooks,
|
|
@@ -137,6 +138,7 @@ def prebuild():
|
|
|
137
138
|
create_placeholder_index_md_files()
|
|
138
139
|
build_metadata()
|
|
139
140
|
build_faq_json()
|
|
141
|
+
build_comments_json()
|
|
140
142
|
build_marimo_readme(mode=_get_readme_py_mode())
|
|
141
143
|
build_markdown()
|
|
142
144
|
build_jupyter_notebooks()
|
afterpython/cli/commands/init.py
CHANGED
|
@@ -169,14 +169,62 @@ def init_py_typed():
|
|
|
169
169
|
click.echo(f"Created {py_typed_path}")
|
|
170
170
|
|
|
171
171
|
|
|
172
|
-
def _preflight_init(
|
|
172
|
+
def _preflight_init(website: bool) -> None:
|
|
173
173
|
"""Validate external prerequisites before any filesystem writes, so a
|
|
174
174
|
failure aborts cleanly instead of leaving a half-initialized project."""
|
|
175
|
-
if
|
|
176
|
-
from afterpython.tools.myst import
|
|
175
|
+
if website:
|
|
176
|
+
from afterpython.tools.myst import ensure_pnpm_12
|
|
177
177
|
from afterpython.utils import find_node_env
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
ensure_pnpm_12(find_node_env())
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _select_steps(yes: bool, skip_website: bool, ask_commit_types: bool) -> set[str]:
|
|
183
|
+
"""Ask which optional setup steps to run, as one checkbox list (all checked by default).
|
|
184
|
+
|
|
185
|
+
Without a terminal (CI, piped input) or with --yes, nothing is asked and the defaults are used.
|
|
186
|
+
"""
|
|
187
|
+
import sys
|
|
188
|
+
|
|
189
|
+
import questionary
|
|
190
|
+
|
|
191
|
+
# (step, label, checked by default)
|
|
192
|
+
options = [
|
|
193
|
+
(
|
|
194
|
+
"website",
|
|
195
|
+
"Project website (MyST, template, deploy workflow)",
|
|
196
|
+
not skip_website,
|
|
197
|
+
)
|
|
198
|
+
]
|
|
199
|
+
# only relevant when afterpython.toml is created, it's ignored otherwise
|
|
200
|
+
if ask_commit_types:
|
|
201
|
+
options.append(
|
|
202
|
+
(
|
|
203
|
+
"commit_types",
|
|
204
|
+
"Commit message check (conventional commit types, e.g. 'feat: add X')",
|
|
205
|
+
True,
|
|
206
|
+
)
|
|
207
|
+
)
|
|
208
|
+
options += [
|
|
209
|
+
("prek", "Pre-commit hooks (prek)", True),
|
|
210
|
+
("ruff", "ruff: lint & format", True),
|
|
211
|
+
("ty", "ty: type checking (`ap check`)", True),
|
|
212
|
+
("cliff", "git-cliff: changelog", True),
|
|
213
|
+
("release", "Release workflow (.github/workflows/release.yml)", True),
|
|
214
|
+
("dependabot", "Dependabot (auto-update GitHub Actions versions)", True),
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
if yes or not (sys.stdin.isatty() and sys.stdout.isatty()):
|
|
218
|
+
return {step for step, _, checked in options if checked}
|
|
219
|
+
|
|
220
|
+
choices = [
|
|
221
|
+
questionary.Choice(label, value=step, checked=checked)
|
|
222
|
+
for step, label, checked in options
|
|
223
|
+
]
|
|
224
|
+
selected = questionary.checkbox("Select what to set up", choices=choices).ask()
|
|
225
|
+
if selected is None: # Ctrl-C, before anything was written
|
|
226
|
+
raise click.Abort()
|
|
227
|
+
return set(selected)
|
|
180
228
|
|
|
181
229
|
|
|
182
230
|
@click.group(invoke_without_command=True)
|
|
@@ -184,7 +232,7 @@ def _preflight_init(skip_website: bool) -> None:
|
|
|
184
232
|
"--yes",
|
|
185
233
|
"-y",
|
|
186
234
|
is_flag=True,
|
|
187
|
-
help="
|
|
235
|
+
help="Set up everything without asking",
|
|
188
236
|
)
|
|
189
237
|
@click.option(
|
|
190
238
|
"--skip-website",
|
|
@@ -205,32 +253,27 @@ def init(ctx, yes, skip_website: bool):
|
|
|
205
253
|
from afterpython.tools.prek import init_prek, sync_hooks
|
|
206
254
|
from afterpython.tools.pyproject import init_pyproject
|
|
207
255
|
|
|
208
|
-
_preflight_init(skip_website)
|
|
209
|
-
|
|
210
256
|
paths = ctx.obj["paths"]
|
|
211
|
-
click.echo("Initializing afterpython...")
|
|
212
257
|
afterpython_path = paths.afterpython_path
|
|
213
258
|
static_path = paths.static_path
|
|
214
259
|
|
|
260
|
+
steps = _select_steps(
|
|
261
|
+
yes,
|
|
262
|
+
skip_website,
|
|
263
|
+
ask_commit_types=not (afterpython_path / "afterpython.toml").exists(),
|
|
264
|
+
)
|
|
265
|
+
_preflight_init(website="website" in steps)
|
|
266
|
+
|
|
267
|
+
click.echo("Initializing afterpython...")
|
|
215
268
|
try:
|
|
216
269
|
afterpython_path.mkdir(parents=True, exist_ok=True)
|
|
217
270
|
static_path.mkdir(parents=True, exist_ok=True)
|
|
218
271
|
|
|
219
272
|
init_pyproject()
|
|
220
273
|
|
|
221
|
-
|
|
222
|
-
commit_types = (
|
|
223
|
-
yes
|
|
224
|
-
or (afterpython_path / "afterpython.toml").exists()
|
|
225
|
-
or click.confirm(
|
|
226
|
-
"\nCheck commit messages against conventional commit types "
|
|
227
|
-
"(e.g. 'feat: add X', types listed in afterpython.toml)?",
|
|
228
|
-
default=True,
|
|
229
|
-
)
|
|
230
|
-
)
|
|
231
|
-
init_afterpython(commit_types=commit_types)
|
|
274
|
+
init_afterpython(commit_types="commit_types" in steps)
|
|
232
275
|
|
|
233
|
-
if
|
|
276
|
+
if "website" in steps:
|
|
234
277
|
# check=True so a failure inside `ap init website` aborts the parent
|
|
235
278
|
# run instead of silently continuing to write more files.
|
|
236
279
|
subprocess.run(["ap", "init", "website"], check=True)
|
|
@@ -239,42 +282,20 @@ def init(ctx, yes, skip_website: bool):
|
|
|
239
282
|
|
|
240
283
|
create_workflow("ci")
|
|
241
284
|
|
|
242
|
-
if
|
|
243
|
-
f"\nCreate .pre-commit-config.yaml in {afterpython_path}?", default=True
|
|
244
|
-
):
|
|
285
|
+
if "prek" in steps:
|
|
245
286
|
init_prek()
|
|
246
|
-
|
|
247
|
-
if yes or click.confirm(
|
|
248
|
-
f"\nCreate ruff.toml in {afterpython_path} (and point pyproject.toml's [tool.ruff] to it)?",
|
|
249
|
-
default=True,
|
|
250
|
-
):
|
|
287
|
+
if "ruff" in steps:
|
|
251
288
|
init_ruff()
|
|
252
|
-
|
|
253
|
-
if yes or click.confirm(
|
|
254
|
-
f"\nCreate ty.toml in {afterpython_path} (type checking with `ap check`)?",
|
|
255
|
-
default=True,
|
|
256
|
-
):
|
|
289
|
+
if "ty" in steps:
|
|
257
290
|
init_ty()
|
|
258
|
-
# whatever
|
|
291
|
+
# whatever was selected: keep ruff/ty hooks only for the tools that were set up
|
|
259
292
|
sync_hooks()
|
|
260
293
|
|
|
261
|
-
if
|
|
262
|
-
f"\nCreate cliff.toml in {afterpython_path} (changelog generation with git-cliff)?",
|
|
263
|
-
default=True,
|
|
264
|
-
):
|
|
294
|
+
if "cliff" in steps:
|
|
265
295
|
init_cliff()
|
|
266
|
-
|
|
267
|
-
if yes or click.confirm(
|
|
268
|
-
"\nCreate release workflow in .github/workflows/release.yml?",
|
|
269
|
-
default=True,
|
|
270
|
-
):
|
|
296
|
+
if "release" in steps:
|
|
271
297
|
create_workflow("release")
|
|
272
|
-
|
|
273
|
-
if yes or click.confirm(
|
|
274
|
-
"\nCreate Dependabot configuration (.github/dependabot.yml) "
|
|
275
|
-
"to auto-update GitHub Actions versions?",
|
|
276
|
-
default=True,
|
|
277
|
-
):
|
|
298
|
+
if "dependabot" in steps:
|
|
278
299
|
create_dependabot()
|
|
279
300
|
except BaseException:
|
|
280
301
|
if afterpython_path.exists():
|
|
@@ -327,12 +348,12 @@ def init_website_subcommand():
|
|
|
327
348
|
the website to an existing AfterPython project.
|
|
328
349
|
"""
|
|
329
350
|
from afterpython.tools.github_actions import create_workflow
|
|
330
|
-
from afterpython.tools.myst import
|
|
351
|
+
from afterpython.tools.myst import ensure_pnpm_12, init_myst
|
|
331
352
|
from afterpython.utils import find_node_env
|
|
332
353
|
|
|
333
354
|
# Pre-flight: same rationale as `ap init` — guard the standalone entry too,
|
|
334
355
|
# since this subcommand can be invoked directly via `ap init website`.
|
|
335
|
-
|
|
356
|
+
ensure_pnpm_12(find_node_env())
|
|
336
357
|
|
|
337
358
|
init_faq()
|
|
338
359
|
init_myst()
|
|
@@ -342,3 +363,44 @@ def init_website_subcommand():
|
|
|
342
363
|
# of a broken website install.
|
|
343
364
|
subprocess.run(["ap", "update", "website"], check=True)
|
|
344
365
|
create_workflow("deploy")
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
@init.command("content")
|
|
369
|
+
@click.option("--all", is_flag=True, help="Initialize all content types")
|
|
370
|
+
@click.option("--doc", is_flag=True, help="Initialize afterpython/doc/")
|
|
371
|
+
@click.option("--blog", is_flag=True, help="Initialize afterpython/blog/")
|
|
372
|
+
@click.option("--tutorial", is_flag=True, help="Initialize afterpython/tutorial/")
|
|
373
|
+
@click.option("--example", is_flag=True, help="Initialize afterpython/example/")
|
|
374
|
+
@click.option("--guide", is_flag=True, help="Initialize afterpython/guide/")
|
|
375
|
+
def init_content_subcommand(
|
|
376
|
+
all: bool, doc: bool, blog: bool, tutorial: bool, example: bool, guide: bool
|
|
377
|
+
):
|
|
378
|
+
"""Initialize content directories (MyST config) without touching the website
|
|
379
|
+
|
|
380
|
+
Content types that already have a myst.yml are skipped.
|
|
381
|
+
|
|
382
|
+
Examples:
|
|
383
|
+
ap init content --blog # afterpython/blog/
|
|
384
|
+
ap init content --blog --tutorial # afterpython/blog/ and afterpython/tutorial/
|
|
385
|
+
ap init content --all # every content type that is missing
|
|
386
|
+
"""
|
|
387
|
+
from afterpython._typing import tContentType
|
|
388
|
+
from afterpython.const import CONTENT_TYPES
|
|
389
|
+
from afterpython.tools.myst import init_myst
|
|
390
|
+
|
|
391
|
+
flags: dict[tContentType, bool] = {
|
|
392
|
+
"doc": doc,
|
|
393
|
+
"blog": blog,
|
|
394
|
+
"tutorial": tutorial,
|
|
395
|
+
"example": example,
|
|
396
|
+
"guide": guide,
|
|
397
|
+
}
|
|
398
|
+
if all:
|
|
399
|
+
content_types = CONTENT_TYPES
|
|
400
|
+
else:
|
|
401
|
+
content_types = {content_type for content_type, flag in flags.items() if flag}
|
|
402
|
+
if not content_types:
|
|
403
|
+
raise click.UsageError(
|
|
404
|
+
"Specify one or more of --doc/--blog/--tutorial/--example/--guide, or --all"
|
|
405
|
+
)
|
|
406
|
+
init_myst(content_types)
|
afterpython/const.py
CHANGED
|
@@ -13,6 +13,12 @@ announcement = ""
|
|
|
13
13
|
readme_py = "wasm" # marimo html export format: "wasm" or "static"
|
|
14
14
|
execute_readme_py = false # execute README.py cells at build time and embed outputs as a preview (wasm mode only)
|
|
15
15
|
api_reference = false # set to true to enable the pdoc-generated API reference
|
|
16
|
+
# api_reference_docformat = "google" # docstring format for pdoc: "google", "numpy", "restructuredtext" or "markdown"
|
|
17
|
+
|
|
18
|
+
[website.comments] # giscus comment section on blog posts, tutorials, examples and guides
|
|
19
|
+
enabled = true
|
|
20
|
+
# Discussions category for comments. Announcement format means only maintainers can start discussions there; visitors can only reply.
|
|
21
|
+
category = "Announcements"
|
|
16
22
|
|
|
17
23
|
# [website.blog]
|
|
18
24
|
# thumbnail = "blog_default_thumbnail.png" # inside blog/static/ folder, default thumbnail for blog posts
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
uses: actions/checkout@v7
|
|
28
28
|
|
|
29
29
|
- name: Install uv
|
|
30
|
-
uses: astral-sh/setup-uv@v10.
|
|
30
|
+
uses: astral-sh/setup-uv@v10.3.3
|
|
31
31
|
|
|
32
32
|
- name: Run ruff
|
|
33
33
|
# fails if ruff-check finds issues or ruff-format would change a file
|
|
@@ -66,7 +66,7 @@ jobs:
|
|
|
66
66
|
runs-on: ubuntu-latest
|
|
67
67
|
strategy:
|
|
68
68
|
matrix:
|
|
69
|
-
python-version: ['3.
|
|
69
|
+
python-version: ['3.13', '3.14', '3.15']
|
|
70
70
|
fail-fast: false
|
|
71
71
|
|
|
72
72
|
env:
|
|
@@ -78,7 +78,7 @@ jobs:
|
|
|
78
78
|
uses: actions/checkout@v7
|
|
79
79
|
|
|
80
80
|
- name: Install uv
|
|
81
|
-
uses: astral-sh/setup-uv@v10.
|
|
81
|
+
uses: astral-sh/setup-uv@v10.3.3
|
|
82
82
|
|
|
83
83
|
- name: Install dependencies
|
|
84
84
|
# the package + all [dependency-groups] (e.g. test, dev), at the versions in uv.lock
|
|
@@ -106,7 +106,7 @@ jobs:
|
|
|
106
106
|
runs-on: ubuntu-latest
|
|
107
107
|
strategy:
|
|
108
108
|
matrix:
|
|
109
|
-
environment: ['
|
|
109
|
+
environment: ['py313', 'py314', 'py315']
|
|
110
110
|
fail-fast: false
|
|
111
111
|
|
|
112
112
|
steps:
|
|
@@ -114,9 +114,9 @@ jobs:
|
|
|
114
114
|
uses: actions/checkout@v7
|
|
115
115
|
|
|
116
116
|
- name: Set up pixi
|
|
117
|
-
uses: prefix-dev/setup-pixi@v0.
|
|
117
|
+
uses: prefix-dev/setup-pixi@v0.11.3
|
|
118
118
|
with:
|
|
119
|
-
pixi-version: v0.
|
|
119
|
+
pixi-version: v0.84.1
|
|
120
120
|
cache: true
|
|
121
121
|
# install (and cache) only the environment this matrix run tests
|
|
122
122
|
environments: ${{ matrix.environment }}
|
|
@@ -169,7 +169,7 @@ jobs:
|
|
|
169
169
|
uses: actions/checkout@v7
|
|
170
170
|
|
|
171
171
|
- name: Install uv
|
|
172
|
-
uses: astral-sh/setup-uv@v10.
|
|
172
|
+
uses: astral-sh/setup-uv@v10.3.3
|
|
173
173
|
|
|
174
174
|
- name: Build package
|
|
175
175
|
# --no-sources: build like it will be published, ignoring [tool.uv.sources] (local paths, git)
|
|
@@ -228,7 +228,7 @@ jobs:
|
|
|
228
228
|
|
|
229
229
|
- name: Install uv
|
|
230
230
|
if: steps.ty.outputs.enabled == 'true' && hashFiles('pixi.toml') == ''
|
|
231
|
-
uses: astral-sh/setup-uv@v10.
|
|
231
|
+
uses: astral-sh/setup-uv@v10.3.3
|
|
232
232
|
|
|
233
233
|
- name: Run ty (uv)
|
|
234
234
|
# the package + all [dependency-groups] (incl. afterpython itself), at the versions in uv.lock
|
|
@@ -239,9 +239,9 @@ jobs:
|
|
|
239
239
|
|
|
240
240
|
- name: Set up pixi
|
|
241
241
|
if: steps.ty.outputs.enabled == 'true' && hashFiles('pixi.toml') != ''
|
|
242
|
-
uses: prefix-dev/setup-pixi@v0.
|
|
242
|
+
uses: prefix-dev/setup-pixi@v0.11.3
|
|
243
243
|
with:
|
|
244
|
-
pixi-version: v0.
|
|
244
|
+
pixi-version: v0.84.1
|
|
245
245
|
cache: true
|
|
246
246
|
environments: default
|
|
247
247
|
|
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
- name: Install pnpm
|
|
48
48
|
uses: pnpm/action-setup@v6
|
|
49
49
|
with:
|
|
50
|
-
version:
|
|
50
|
+
version: 12
|
|
51
51
|
|
|
52
52
|
- name: Set up Node.js
|
|
53
53
|
uses: actions/setup-node@v7
|
|
@@ -57,7 +57,7 @@ jobs:
|
|
|
57
57
|
cache-dependency-path: './afterpython/_website/pnpm-lock.yaml'
|
|
58
58
|
|
|
59
59
|
- name: Install uv
|
|
60
|
-
uses: astral-sh/setup-uv@v10.
|
|
60
|
+
uses: astral-sh/setup-uv@v10.3.3
|
|
61
61
|
|
|
62
62
|
- name: Install the project
|
|
63
63
|
# your package + its dependencies (pdoc imports it for the API reference)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* Dark mode for what theme.css can't reach. Colors from Bootstrap 5.3's dark mode,
|
|
2
|
+
like pdoc's light ones are from its light mode. */
|
|
3
|
+
|
|
4
|
+
/* code blocks match inline code instead of github-dark's own background */
|
|
5
|
+
html.dark .pdoc .pdoc-code {
|
|
6
|
+
background: var(--code);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
html.dark .pdoc .decorator-deprecated {
|
|
10
|
+
color: #ea868f;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
{#- the icons have their light color baked in, swap it for the dark text color -#}
|
|
14
|
+
{% macro alert(kind, icon, light, color, background, border) %}
|
|
15
|
+
html.dark .pdoc .alert.{{ kind }} {
|
|
16
|
+
color: {{ color }};
|
|
17
|
+
background-color: {{ background }};
|
|
18
|
+
border-color: {{ border }};
|
|
19
|
+
background-image: url("data:image/svg+xml,{% filter urlencode %}{% filter replace(light, color) %}{% include 'resources/' ~ icon ~ '.svg' %}{% endfilter %}{% endfilter %}");
|
|
20
|
+
}
|
|
21
|
+
{% endmacro %}
|
|
22
|
+
{{ alert("note", "info-circle-fill", "#084298", "#6ea8fe", "#031633", "#084298") }}
|
|
23
|
+
{{ alert("tip", "lightbulb", "#0a3622", "#75b798", "#051b11", "#0f5132") }}
|
|
24
|
+
{{ alert("important", "exclamation-square-fill", "#055160", "#6edff6", "#032830", "#087990") }}
|
|
25
|
+
{{ alert("warning", "exclamation-triangle-fill", "#664d03", "#ffda6a", "#332701", "#997404") }}
|
|
26
|
+
{{ alert("caution", "exclamation-octagon-fill", "#842029", "#ea868f", "#2c0b0e", "#842029") }}
|
|
27
|
+
{{ alert("danger", "lightning-fill", "#842029", "#ea868f", "#2c0b0e", "#842029") }}
|
|
28
|
+
|
|
29
|
+
{#- pdoc indents every non-top-level nav link by one --indent, so a nested class's
|
|
30
|
+
members (e.g. Feed.Requests.download) line up with the outer class's own members
|
|
31
|
+
(Feed.download) and read as duplicates. Indent one more step per nesting level. -#}
|
|
32
|
+
nav.pdoc li li li a {
|
|
33
|
+
padding-left: calc(var(--pad) + 2 * var(--indent));
|
|
34
|
+
}
|
|
35
|
+
nav.pdoc li li li li a {
|
|
36
|
+
padding-left: calc(var(--pad) + 3 * var(--indent));
|
|
37
|
+
}
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
{% extends "default/frame.html.jinja2" %}
|
|
2
|
-
{# Override pdoc's default 35vh logo height — too dominant in the sidebar. #}
|
|
3
2
|
{% block head %}
|
|
3
|
+
{# Same as the project website's app.html: follow the theme chosen on the website
|
|
4
|
+
(same origin, so its localStorage is shared), else the OS setting.
|
|
5
|
+
Dark colors are in theme.css, syntax-highlighting.css and custom.css. #}
|
|
6
|
+
<script>
|
|
7
|
+
(function () {
|
|
8
|
+
const query = window.matchMedia('(prefers-color-scheme: dark)');
|
|
9
|
+
const apply = (dark) => document.documentElement.classList.toggle('dark', dark);
|
|
10
|
+
const stored = localStorage.getItem('theme');
|
|
11
|
+
apply(stored ? stored === 'dark' : query.matches);
|
|
12
|
+
query.addEventListener('change', (e) => {
|
|
13
|
+
if (!localStorage.getItem('theme')) apply(e.matches);
|
|
14
|
+
});
|
|
15
|
+
})();
|
|
16
|
+
</script>
|
|
17
|
+
{# Override pdoc's default 35vh logo height — too dominant in the sidebar. #}
|
|
4
18
|
<style>
|
|
5
19
|
nav.pdoc img.logo { max-height: 5rem; margin-bottom: 1.5rem; }
|
|
6
20
|
</style>
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/* auto-generated, see templates/README.md */
|
|
2
|
+
pre { line-height: 125%; }
|
|
3
|
+
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 20px; }
|
|
4
|
+
.pdoc-code .hll { background-color: #ffffcc }
|
|
5
|
+
.pdoc-code { background: #f8f8f8; }
|
|
6
|
+
.pdoc-code .c { color: #3D7B7B; font-style: italic } /* Comment */
|
|
7
|
+
.pdoc-code .err { border: 1px solid #FF0000 } /* Error */
|
|
8
|
+
.pdoc-code .k { color: #008000; font-weight: bold } /* Keyword */
|
|
9
|
+
.pdoc-code .o { color: #666666 } /* Operator */
|
|
10
|
+
.pdoc-code .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
|
|
11
|
+
.pdoc-code .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
|
|
12
|
+
.pdoc-code .cp { color: #9C6500 } /* Comment.Preproc */
|
|
13
|
+
.pdoc-code .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
|
|
14
|
+
.pdoc-code .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
|
|
15
|
+
.pdoc-code .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
|
|
16
|
+
.pdoc-code .gd { color: #A00000 } /* Generic.Deleted */
|
|
17
|
+
.pdoc-code .ge { font-style: italic } /* Generic.Emph */
|
|
18
|
+
.pdoc-code .gr { color: #E40000 } /* Generic.Error */
|
|
19
|
+
.pdoc-code .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
|
20
|
+
.pdoc-code .gi { color: #008400 } /* Generic.Inserted */
|
|
21
|
+
.pdoc-code .go { color: #717171 } /* Generic.Output */
|
|
22
|
+
.pdoc-code .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
|
23
|
+
.pdoc-code .gs { font-weight: bold } /* Generic.Strong */
|
|
24
|
+
.pdoc-code .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
|
25
|
+
.pdoc-code .gt { color: #0044DD } /* Generic.Traceback */
|
|
26
|
+
.pdoc-code .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
|
|
27
|
+
.pdoc-code .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
|
|
28
|
+
.pdoc-code .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
|
|
29
|
+
.pdoc-code .kp { color: #008000 } /* Keyword.Pseudo */
|
|
30
|
+
.pdoc-code .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
|
|
31
|
+
.pdoc-code .kt { color: #B00040 } /* Keyword.Type */
|
|
32
|
+
.pdoc-code .m { color: #666666 } /* Literal.Number */
|
|
33
|
+
.pdoc-code .s { color: #BA2121 } /* Literal.String */
|
|
34
|
+
.pdoc-code .na { color: #687822 } /* Name.Attribute */
|
|
35
|
+
.pdoc-code .nb { color: #008000 } /* Name.Builtin */
|
|
36
|
+
.pdoc-code .nc { color: #0000FF; font-weight: bold } /* Name.Class */
|
|
37
|
+
.pdoc-code .no { color: #880000 } /* Name.Constant */
|
|
38
|
+
.pdoc-code .nd { color: #AA22FF } /* Name.Decorator */
|
|
39
|
+
.pdoc-code .ni { color: #717171; font-weight: bold } /* Name.Entity */
|
|
40
|
+
.pdoc-code .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
|
|
41
|
+
.pdoc-code .nf { color: #0000FF } /* Name.Function */
|
|
42
|
+
.pdoc-code .nl { color: #767600 } /* Name.Label */
|
|
43
|
+
.pdoc-code .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
|
|
44
|
+
.pdoc-code .nt { color: #008000; font-weight: bold } /* Name.Tag */
|
|
45
|
+
.pdoc-code .nv { color: #19177C } /* Name.Variable */
|
|
46
|
+
.pdoc-code .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
|
|
47
|
+
.pdoc-code .w { color: #bbbbbb } /* Text.Whitespace */
|
|
48
|
+
.pdoc-code .mb { color: #666666 } /* Literal.Number.Bin */
|
|
49
|
+
.pdoc-code .mf { color: #666666 } /* Literal.Number.Float */
|
|
50
|
+
.pdoc-code .mh { color: #666666 } /* Literal.Number.Hex */
|
|
51
|
+
.pdoc-code .mi { color: #666666 } /* Literal.Number.Integer */
|
|
52
|
+
.pdoc-code .mo { color: #666666 } /* Literal.Number.Oct */
|
|
53
|
+
.pdoc-code .sa { color: #BA2121 } /* Literal.String.Affix */
|
|
54
|
+
.pdoc-code .sb { color: #BA2121 } /* Literal.String.Backtick */
|
|
55
|
+
.pdoc-code .sc { color: #BA2121 } /* Literal.String.Char */
|
|
56
|
+
.pdoc-code .dl { color: #BA2121 } /* Literal.String.Delimiter */
|
|
57
|
+
.pdoc-code .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
|
|
58
|
+
.pdoc-code .s2 { color: #BA2121 } /* Literal.String.Double */
|
|
59
|
+
.pdoc-code .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
|
|
60
|
+
.pdoc-code .sh { color: #BA2121 } /* Literal.String.Heredoc */
|
|
61
|
+
.pdoc-code .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
|
|
62
|
+
.pdoc-code .sx { color: #008000 } /* Literal.String.Other */
|
|
63
|
+
.pdoc-code .sr { color: #A45A77 } /* Literal.String.Regex */
|
|
64
|
+
.pdoc-code .s1 { color: #BA2121 } /* Literal.String.Single */
|
|
65
|
+
.pdoc-code .ss { color: #19177C } /* Literal.String.Symbol */
|
|
66
|
+
.pdoc-code .bp { color: #008000 } /* Name.Builtin.Pseudo */
|
|
67
|
+
.pdoc-code .fm { color: #0000FF } /* Name.Function.Magic */
|
|
68
|
+
.pdoc-code .vc { color: #19177C } /* Name.Variable.Class */
|
|
69
|
+
.pdoc-code .vg { color: #19177C } /* Name.Variable.Global */
|
|
70
|
+
.pdoc-code .vi { color: #19177C } /* Name.Variable.Instance */
|
|
71
|
+
.pdoc-code .vm { color: #19177C } /* Name.Variable.Magic */
|
|
72
|
+
.pdoc-code .il { color: #666666 } /* Literal.Number.Integer.Long */
|
|
73
|
+
|
|
74
|
+
/* dark: pygmentize -f html -a "html.dark .pdoc-code" -S github-dark (pre/span.linenos rules dropped, they are above) */
|
|
75
|
+
html.dark .pdoc-code .hll { background-color: #6e7681 }
|
|
76
|
+
html.dark .pdoc-code { background: #0d1117; color: #E6EDF3 }
|
|
77
|
+
html.dark .pdoc-code .c { color: #8B949E; font-style: italic } /* Comment */
|
|
78
|
+
html.dark .pdoc-code .err { color: #F85149 } /* Error */
|
|
79
|
+
html.dark .pdoc-code .esc { color: #E6EDF3 } /* Escape */
|
|
80
|
+
html.dark .pdoc-code .g { color: #E6EDF3 } /* Generic */
|
|
81
|
+
html.dark .pdoc-code .k { color: #FF7B72 } /* Keyword */
|
|
82
|
+
html.dark .pdoc-code .l { color: #A5D6FF } /* Literal */
|
|
83
|
+
html.dark .pdoc-code .n { color: #E6EDF3 } /* Name */
|
|
84
|
+
html.dark .pdoc-code .o { color: #FF7B72; font-weight: bold } /* Operator */
|
|
85
|
+
html.dark .pdoc-code .x { color: #E6EDF3 } /* Other */
|
|
86
|
+
html.dark .pdoc-code .p { color: #E6EDF3 } /* Punctuation */
|
|
87
|
+
html.dark .pdoc-code .ch { color: #8B949E; font-style: italic } /* Comment.Hashbang */
|
|
88
|
+
html.dark .pdoc-code .cm { color: #8B949E; font-style: italic } /* Comment.Multiline */
|
|
89
|
+
html.dark .pdoc-code .cp { color: #8B949E; font-weight: bold; font-style: italic } /* Comment.Preproc */
|
|
90
|
+
html.dark .pdoc-code .cpf { color: #8B949E; font-style: italic } /* Comment.PreprocFile */
|
|
91
|
+
html.dark .pdoc-code .c1 { color: #8B949E; font-style: italic } /* Comment.Single */
|
|
92
|
+
html.dark .pdoc-code .cs { color: #8B949E; font-weight: bold; font-style: italic } /* Comment.Special */
|
|
93
|
+
html.dark .pdoc-code .gd { color: #FFA198; background-color: #490202 } /* Generic.Deleted */
|
|
94
|
+
html.dark .pdoc-code .ge { color: #E6EDF3; font-style: italic } /* Generic.Emph */
|
|
95
|
+
html.dark .pdoc-code .ges { color: #E6EDF3; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
|
|
96
|
+
html.dark .pdoc-code .gr { color: #FFA198 } /* Generic.Error */
|
|
97
|
+
html.dark .pdoc-code .gh { color: #79C0FF; font-weight: bold } /* Generic.Heading */
|
|
98
|
+
html.dark .pdoc-code .gi { color: #56D364; background-color: #0F5323 } /* Generic.Inserted */
|
|
99
|
+
html.dark .pdoc-code .go { color: #8B949E } /* Generic.Output */
|
|
100
|
+
html.dark .pdoc-code .gp { color: #8B949E } /* Generic.Prompt */
|
|
101
|
+
html.dark .pdoc-code .gs { color: #E6EDF3; font-weight: bold } /* Generic.Strong */
|
|
102
|
+
html.dark .pdoc-code .gu { color: #79C0FF } /* Generic.Subheading */
|
|
103
|
+
html.dark .pdoc-code .gt { color: #FF7B72 } /* Generic.Traceback */
|
|
104
|
+
html.dark .pdoc-code .g-Underline { color: #E6EDF3; text-decoration: underline } /* Generic.Underline */
|
|
105
|
+
html.dark .pdoc-code .kc { color: #79C0FF } /* Keyword.Constant */
|
|
106
|
+
html.dark .pdoc-code .kd { color: #FF7B72 } /* Keyword.Declaration */
|
|
107
|
+
html.dark .pdoc-code .kn { color: #FF7B72 } /* Keyword.Namespace */
|
|
108
|
+
html.dark .pdoc-code .kp { color: #79C0FF } /* Keyword.Pseudo */
|
|
109
|
+
html.dark .pdoc-code .kr { color: #FF7B72 } /* Keyword.Reserved */
|
|
110
|
+
html.dark .pdoc-code .kt { color: #FF7B72 } /* Keyword.Type */
|
|
111
|
+
html.dark .pdoc-code .ld { color: #79C0FF } /* Literal.Date */
|
|
112
|
+
html.dark .pdoc-code .m { color: #A5D6FF } /* Literal.Number */
|
|
113
|
+
html.dark .pdoc-code .s { color: #A5D6FF } /* Literal.String */
|
|
114
|
+
html.dark .pdoc-code .na { color: #E6EDF3 } /* Name.Attribute */
|
|
115
|
+
html.dark .pdoc-code .nb { color: #E6EDF3 } /* Name.Builtin */
|
|
116
|
+
html.dark .pdoc-code .nc { color: #F0883E; font-weight: bold } /* Name.Class */
|
|
117
|
+
html.dark .pdoc-code .no { color: #79C0FF; font-weight: bold } /* Name.Constant */
|
|
118
|
+
html.dark .pdoc-code .nd { color: #D2A8FF; font-weight: bold } /* Name.Decorator */
|
|
119
|
+
html.dark .pdoc-code .ni { color: #FFA657 } /* Name.Entity */
|
|
120
|
+
html.dark .pdoc-code .ne { color: #F0883E; font-weight: bold } /* Name.Exception */
|
|
121
|
+
html.dark .pdoc-code .nf { color: #D2A8FF; font-weight: bold } /* Name.Function */
|
|
122
|
+
html.dark .pdoc-code .nl { color: #79C0FF; font-weight: bold } /* Name.Label */
|
|
123
|
+
html.dark .pdoc-code .nn { color: #FF7B72 } /* Name.Namespace */
|
|
124
|
+
html.dark .pdoc-code .nx { color: #E6EDF3 } /* Name.Other */
|
|
125
|
+
html.dark .pdoc-code .py { color: #79C0FF } /* Name.Property */
|
|
126
|
+
html.dark .pdoc-code .nt { color: #7EE787 } /* Name.Tag */
|
|
127
|
+
html.dark .pdoc-code .nv { color: #79C0FF } /* Name.Variable */
|
|
128
|
+
html.dark .pdoc-code .ow { color: #FF7B72; font-weight: bold } /* Operator.Word */
|
|
129
|
+
html.dark .pdoc-code .pm { color: #E6EDF3 } /* Punctuation.Marker */
|
|
130
|
+
html.dark .pdoc-code .w { color: #6E7681 } /* Text.Whitespace */
|
|
131
|
+
html.dark .pdoc-code .mb { color: #A5D6FF } /* Literal.Number.Bin */
|
|
132
|
+
html.dark .pdoc-code .mf { color: #A5D6FF } /* Literal.Number.Float */
|
|
133
|
+
html.dark .pdoc-code .mh { color: #A5D6FF } /* Literal.Number.Hex */
|
|
134
|
+
html.dark .pdoc-code .mi { color: #A5D6FF } /* Literal.Number.Integer */
|
|
135
|
+
html.dark .pdoc-code .mo { color: #A5D6FF } /* Literal.Number.Oct */
|
|
136
|
+
html.dark .pdoc-code .sa { color: #79C0FF } /* Literal.String.Affix */
|
|
137
|
+
html.dark .pdoc-code .sb { color: #A5D6FF } /* Literal.String.Backtick */
|
|
138
|
+
html.dark .pdoc-code .sc { color: #A5D6FF } /* Literal.String.Char */
|
|
139
|
+
html.dark .pdoc-code .dl { color: #79C0FF } /* Literal.String.Delimiter */
|
|
140
|
+
html.dark .pdoc-code .sd { color: #A5D6FF } /* Literal.String.Doc */
|
|
141
|
+
html.dark .pdoc-code .s2 { color: #A5D6FF } /* Literal.String.Double */
|
|
142
|
+
html.dark .pdoc-code .se { color: #79C0FF } /* Literal.String.Escape */
|
|
143
|
+
html.dark .pdoc-code .sh { color: #79C0FF } /* Literal.String.Heredoc */
|
|
144
|
+
html.dark .pdoc-code .si { color: #A5D6FF } /* Literal.String.Interpol */
|
|
145
|
+
html.dark .pdoc-code .sx { color: #A5D6FF } /* Literal.String.Other */
|
|
146
|
+
html.dark .pdoc-code .sr { color: #79C0FF } /* Literal.String.Regex */
|
|
147
|
+
html.dark .pdoc-code .s1 { color: #A5D6FF } /* Literal.String.Single */
|
|
148
|
+
html.dark .pdoc-code .ss { color: #A5D6FF } /* Literal.String.Symbol */
|
|
149
|
+
html.dark .pdoc-code .bp { color: #E6EDF3 } /* Name.Builtin.Pseudo */
|
|
150
|
+
html.dark .pdoc-code .fm { color: #D2A8FF; font-weight: bold } /* Name.Function.Magic */
|
|
151
|
+
html.dark .pdoc-code .vc { color: #79C0FF } /* Name.Variable.Class */
|
|
152
|
+
html.dark .pdoc-code .vg { color: #79C0FF } /* Name.Variable.Global */
|
|
153
|
+
html.dark .pdoc-code .vi { color: #79C0FF } /* Name.Variable.Instance */
|
|
154
|
+
html.dark .pdoc-code .vm { color: #79C0FF } /* Name.Variable.Magic */
|
|
155
|
+
html.dark .pdoc-code .il { color: #A5D6FF } /* Literal.Number.Integer.Long */
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* pdoc's default color scheme, plus a dark one used when <html> has the "dark" class */
|
|
2
|
+
:root {
|
|
3
|
+
--pdoc-background: #fff;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.pdoc {
|
|
7
|
+
--text: #212529;
|
|
8
|
+
--muted: #6c757d;
|
|
9
|
+
--link: #3660a5;
|
|
10
|
+
--link-hover: #1659c5;
|
|
11
|
+
--code: #f8f8f8;
|
|
12
|
+
--active: #fff598;
|
|
13
|
+
|
|
14
|
+
--accent: #eee;
|
|
15
|
+
--accent2: #c1c1c1;
|
|
16
|
+
|
|
17
|
+
--nav-hover: rgba(255, 255, 255, 0.5);
|
|
18
|
+
--name: #0066BB;
|
|
19
|
+
--def: #008800;
|
|
20
|
+
--annotation: #007020;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* dark grays match the project website's dark mode */
|
|
24
|
+
html.dark {
|
|
25
|
+
--pdoc-background: #121212;
|
|
26
|
+
color-scheme: dark; /* dark scrollbars and search input */
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
html.dark .pdoc {
|
|
30
|
+
--text: #e5e5e5;
|
|
31
|
+
--muted: #94a3b8;
|
|
32
|
+
--link: #58a6ff;
|
|
33
|
+
--link-hover: #79b8ff;
|
|
34
|
+
--code: #1e1e1e;
|
|
35
|
+
--active: #555;
|
|
36
|
+
|
|
37
|
+
--accent: #1e1e1e;
|
|
38
|
+
--accent2: #383838;
|
|
39
|
+
|
|
40
|
+
--nav-hover: rgba(0, 0, 0, 0.3);
|
|
41
|
+
--name: #77c1ff;
|
|
42
|
+
--def: #0cdd0c;
|
|
43
|
+
--annotation: #00c037;
|
|
44
|
+
}
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
fetch-depth: 0 # full history and tags, for git-cliff's release notes
|
|
28
28
|
|
|
29
29
|
- name: Install uv
|
|
30
|
-
uses: astral-sh/setup-uv@v10.
|
|
30
|
+
uses: astral-sh/setup-uv@v10.3.3
|
|
31
31
|
|
|
32
32
|
- name: Check tag matches version
|
|
33
33
|
# e.g. a hand-made tag v0.4.0 on a commit whose pyproject.toml says 0.3.20
|
afterpython/tools/myst.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
|
+
from collections.abc import Iterable
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
from afterpython._typing import NodeEnv, tContentType
|
|
@@ -151,11 +152,12 @@ def _write_index_file(content_type: tContentType):
|
|
|
151
152
|
return index_file
|
|
152
153
|
|
|
153
154
|
|
|
154
|
-
def
|
|
155
|
-
"""Ensure pnpm
|
|
155
|
+
def ensure_pnpm_12(node_env: NodeEnv) -> None:
|
|
156
|
+
"""Ensure pnpm 12.x is available on `node_env`'s PATH. No-op if already satisfied.
|
|
156
157
|
|
|
157
|
-
Pinned to
|
|
158
|
-
|
|
158
|
+
Pinned to the website template's pnpm major (devEngines in its package.json)
|
|
159
|
+
because an unpinned `npm install -g pnpm` previously did a silent 9→10 jump
|
|
160
|
+
that broke `ap init` via ERR_PNPM_IGNORED_BUILDS. We
|
|
159
161
|
pre-check the installed version so we don't redundantly invoke `npm install
|
|
160
162
|
-g`, which fails with EEXIST when pnpm was installed by a different package
|
|
161
163
|
manager (e.g. Homebrew) that owns the shim filenames npm wants to write.
|
|
@@ -171,13 +173,13 @@ def ensure_pnpm_11(node_env: NodeEnv) -> None:
|
|
|
171
173
|
)
|
|
172
174
|
if result.returncode == 0:
|
|
173
175
|
current = result.stdout.strip()
|
|
174
|
-
if current.startswith("
|
|
176
|
+
if current.startswith("12."):
|
|
175
177
|
return
|
|
176
178
|
except FileNotFoundError:
|
|
177
179
|
pass
|
|
178
180
|
|
|
179
181
|
install = subprocess.run(
|
|
180
|
-
["npm", "install", "-g", "pnpm@
|
|
182
|
+
["npm", "install", "-g", "pnpm@12"],
|
|
181
183
|
env=node_env,
|
|
182
184
|
capture_output=True,
|
|
183
185
|
text=True,
|
|
@@ -186,14 +188,14 @@ def ensure_pnpm_11(node_env: NodeEnv) -> None:
|
|
|
186
188
|
if install.returncode == 0:
|
|
187
189
|
return
|
|
188
190
|
|
|
189
|
-
msg = ["Failed to install pnpm@
|
|
191
|
+
msg = ["Failed to install pnpm@12 via npm."]
|
|
190
192
|
if current:
|
|
191
193
|
msg.append(f"Detected existing pnpm version: {current}")
|
|
192
194
|
msg.append(
|
|
193
195
|
"If pnpm is already installed via another package manager "
|
|
194
196
|
"(e.g. Homebrew: `brew install pnpm`), npm refuses to overwrite "
|
|
195
197
|
"its shims. Please either:\n"
|
|
196
|
-
" - upgrade your existing pnpm to major version
|
|
198
|
+
" - upgrade your existing pnpm to major version 12, or\n"
|
|
197
199
|
" - uninstall it and let afterpython manage pnpm via npm."
|
|
198
200
|
)
|
|
199
201
|
if install.stderr:
|
|
@@ -201,19 +203,27 @@ def ensure_pnpm_11(node_env: NodeEnv) -> None:
|
|
|
201
203
|
raise RuntimeError("\n".join(msg))
|
|
202
204
|
|
|
203
205
|
|
|
204
|
-
def init_myst():
|
|
206
|
+
def init_myst(content_types: Iterable[tContentType] | None = None):
|
|
205
207
|
"""
|
|
206
208
|
Initialize MyST Markdown (mystmd) and myst.yml files in
|
|
207
209
|
doc/, blog/, tutorial/, example/, guide/ directories with sensible defaults
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
content_types: content types to initialize; defaults to all of them.
|
|
213
|
+
A directory that already has a myst.yml is left untouched.
|
|
208
214
|
"""
|
|
209
215
|
from afterpython.const import CONTENT_TYPES
|
|
210
216
|
from afterpython.utils import find_node_env
|
|
211
217
|
|
|
212
218
|
# find any existing node.js version and use it, if no, install the Node.js version specified in NODEENV_VERSION
|
|
213
219
|
node_env: NodeEnv = find_node_env()
|
|
214
|
-
|
|
215
|
-
|
|
220
|
+
ensure_pnpm_12(node_env)
|
|
221
|
+
initialized = False
|
|
222
|
+
for content_type in sorted(content_types or CONTENT_TYPES):
|
|
216
223
|
path = ap.paths.afterpython_path / content_type
|
|
224
|
+
if (path / "myst.yml").exists():
|
|
225
|
+
print(f"Skipping {path.name}/ (myst.yml already exists)")
|
|
226
|
+
continue
|
|
217
227
|
print(f"Initializing MyST Markdown (mystmd) in {path.name}/ directory ...")
|
|
218
228
|
path.mkdir(parents=True, exist_ok=True)
|
|
219
229
|
subprocess.run(
|
|
@@ -224,6 +234,16 @@ def init_myst():
|
|
|
224
234
|
env=node_env,
|
|
225
235
|
check=True,
|
|
226
236
|
)
|
|
237
|
+
site_defaults: dict[str, Any] = {
|
|
238
|
+
"options": {
|
|
239
|
+
"analytics_google": "{{ GOOGLE_ANALYTICS_ID }}",
|
|
240
|
+
# "twitter": "",
|
|
241
|
+
},
|
|
242
|
+
}
|
|
243
|
+
# `myst init` defaults every project to book-theme; blog posts are
|
|
244
|
+
# standalone articles, so article-theme fits them better.
|
|
245
|
+
if content_type == "blog":
|
|
246
|
+
site_defaults["template"] = "article-theme"
|
|
227
247
|
myst_yml_defaults = {
|
|
228
248
|
"extends": "../authors.yml",
|
|
229
249
|
"project": {
|
|
@@ -232,12 +252,9 @@ def init_myst():
|
|
|
232
252
|
if content_type != "doc"
|
|
233
253
|
else "Documentation",
|
|
234
254
|
},
|
|
235
|
-
"site":
|
|
236
|
-
"options": {
|
|
237
|
-
"analytics_google": "{{ GOOGLE_ANALYTICS_ID }}",
|
|
238
|
-
# "twitter": "",
|
|
239
|
-
},
|
|
240
|
-
},
|
|
255
|
+
"site": site_defaults,
|
|
241
256
|
}
|
|
242
257
|
update_myst_yml(myst_yml_defaults, path, add_comments=True)
|
|
243
|
-
|
|
258
|
+
initialized = True
|
|
259
|
+
if initialized:
|
|
260
|
+
subprocess.run(["ap", "sync"])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: afterpython
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: CLI tool to streamline Python package maintenance and generate a dedicated project website
|
|
5
5
|
Keywords: package-maintenance,project-website,static-site-generator,developer-tools,documentation,cli-tool,ci/cd,mystmd,semantic-release,python-packaging
|
|
6
6
|
Author: Stephen Yau
|
|
@@ -11,26 +11,27 @@ Classifier: Intended Audience :: Developers
|
|
|
11
11
|
Classifier: Topic :: Software Development :: Build Tools
|
|
12
12
|
Classifier: Topic :: Software Development :: Documentation
|
|
13
13
|
Classifier: Typing :: Typed
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
-
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
17
|
+
Requires-Dist: click>=8.5.1
|
|
18
18
|
Requires-Dist: trogon>=0.6.0
|
|
19
|
-
Requires-Dist: httpx2>=2.
|
|
20
|
-
Requires-Dist: tomlkit>=0.15.
|
|
19
|
+
Requires-Dist: httpx2>=2.16.0
|
|
20
|
+
Requires-Dist: tomlkit>=0.15.2
|
|
21
21
|
Requires-Dist: ruamel-yaml>=0.19.1
|
|
22
|
-
Requires-Dist: gitpython>=3.2.
|
|
23
|
-
Requires-Dist: python-dotenv>=1.2.
|
|
22
|
+
Requires-Dist: gitpython>=3.2.1
|
|
23
|
+
Requires-Dist: python-dotenv>=1.2.4
|
|
24
24
|
Requires-Dist: pyproject-metadata>=0.12.1
|
|
25
|
-
Requires-Dist: jupytext>=1.19.
|
|
26
|
-
Requires-Dist: mystmd>=1.
|
|
25
|
+
Requires-Dist: jupytext>=1.19.6
|
|
26
|
+
Requires-Dist: mystmd>=1.12.0
|
|
27
27
|
Requires-Dist: pdoc>=16.0.0
|
|
28
|
-
Requires-Dist: ruff>=0.
|
|
29
|
-
Requires-Dist: prek>=0.5.
|
|
30
|
-
Requires-Dist: ty>=0.0.
|
|
28
|
+
Requires-Dist: ruff>=0.17.4
|
|
29
|
+
Requires-Dist: prek>=0.5.10
|
|
30
|
+
Requires-Dist: ty>=0.0.99
|
|
31
31
|
Requires-Dist: git-cliff>=2.14.2
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-
|
|
32
|
+
Requires-Dist: questionary>=2.1.1
|
|
33
|
+
Requires-Dist: marimo[recommended,lsp]>=0.25.2 ; extra == 'marimo'
|
|
34
|
+
Requires-Python: >=3.13
|
|
34
35
|
Project-URL: homepage, https://afterpython.afterpython.org
|
|
35
36
|
Project-URL: repository, https://github.com/AfterPythonOrg/afterpython
|
|
36
37
|
Project-URL: documentation, https://afterpython.afterpython.org/doc
|
|
@@ -44,8 +45,8 @@ Description-Content-Type: text/markdown
|
|
|
44
45
|
[](https://pypi.org/project/afterpython)
|
|
45
46
|

|
|
46
47
|
[](https://github.com/AfterPythonOrg/afterpython/discussions)
|
|
47
|
-
[](https://deepwiki.com/AfterPythonOrg/afterpython)
|
|
48
48
|
[](https://codewiki.google/github.com/afterpythonorg/afterpython?utm_source=badge&utm_medium=github&utm_campaign=github.com/afterpythonorg/afterpython)
|
|
49
|
+
<!--[](https://deepwiki.com/AfterPythonOrg/afterpython)-->
|
|
49
50
|
<!--  -->
|
|
50
51
|
<!-- [](https://pixi.sh) -->
|
|
51
52
|
|
|
@@ -3,8 +3,9 @@ afterpython/_io/toml.py,sha256=dvmq6n4MhlJ02u_YjfC3mOnCWatfCn_J1lugavigoJw,3410
|
|
|
3
3
|
afterpython/_io/yaml.py,sha256=raksve_gaIFJim8lQrq-kQHkRjTloed7CT2FY0oUJSg,654
|
|
4
4
|
afterpython/_paths.py,sha256=FTwQ7necKYuRosCyMZPfv1eqaEmGIsyqd3yXpm-WQTA,1584
|
|
5
5
|
afterpython/_typing.py,sha256=kDO25BbJCdNNkqoP9-JYC1zsOuNvzhqvSOCcam3yuAk,128
|
|
6
|
-
afterpython/builders/__init__.py,sha256=
|
|
7
|
-
afterpython/builders/build_pdoc.py,sha256=
|
|
6
|
+
afterpython/builders/__init__.py,sha256=2ee-FggKVZmjDazH5dLOe7irTOkHNZhQK9SK7EX_dEA,1069
|
|
7
|
+
afterpython/builders/build_pdoc.py,sha256=lFWQzw4w_-O1PdWHst3eAbgZKkZuQXWtMBFOmZK5BlQ,2442
|
|
8
|
+
afterpython/builders/comments_json.py,sha256=7gY1wy78wqSscTIFlDhwDKNYN6ioLzpDpACLBmwB9rw,3603
|
|
8
9
|
afterpython/builders/content_json.py,sha256=yem8qhVjy5-aTnmUIING5ttNZFsuTQ-r5M_dYKGRyTk,5362
|
|
9
10
|
afterpython/builders/faq_json.py,sha256=mMfFepRBL_1QYO0tQ6orf5ESo2LVntk55nfFzencViM,1193
|
|
10
11
|
afterpython/builders/index_md.py,sha256=ZpBA1FIHgw9MXD8kRaq2OBaEAKnf94_sJmB2cG68iag,6021
|
|
@@ -16,7 +17,7 @@ afterpython/builders/metadata.py,sha256=EueKoYWM__Hb9MwX0KYejxJvouoaAxD1oz9AP-Na
|
|
|
16
17
|
afterpython/builders/url_md.py,sha256=MfXSy0f44J72OlHASir-Xscqq1onA10vtqUO_L4b1xM,3949
|
|
17
18
|
afterpython/cli/__init__.py,sha256=G4AB-rllhmr7tURFc5cXJfkjZZ2bXtMBg3oy4zUGEFw,84
|
|
18
19
|
afterpython/cli/commands/add.py,sha256=Ppp4msdvOwN9_-fdG5-b0-IV9p0Eef9CiIEU3srUjYk,1792
|
|
19
|
-
afterpython/cli/commands/build.py,sha256=
|
|
20
|
+
afterpython/cli/commands/build.py,sha256=7LgNZnT0daUB7oSIR-ZziZ_pMc9YPulgsCHGkAeMqEw,11861
|
|
20
21
|
afterpython/cli/commands/bump.py,sha256=ULrZmQuQ-oJSYXNyEyCg3VxrHDhzwOSMv37Uk1fQlgs,13354
|
|
21
22
|
afterpython/cli/commands/changelog.py,sha256=R4GdvJlnfd8joVnRRon9y-eM8RfSIxE1GCOspMrxXEw,1597
|
|
22
23
|
afterpython/cli/commands/check.py,sha256=QBt_KHlD72QJmBordcsoGKvyX4Iuj7ezjFStuNZVaOk,1694
|
|
@@ -24,7 +25,7 @@ afterpython/cli/commands/clean.py,sha256=havP43ZC1AKFzvscsRMF_to6TvOwruxGA5qzr6d
|
|
|
24
25
|
afterpython/cli/commands/commit_msg.py,sha256=2PYTqsxMeYaGwQSb2MER3a73gmUoSAietuApJW0XKw4,4513
|
|
25
26
|
afterpython/cli/commands/dev.py,sha256=bbugeF52iQI8xr2h59yRdV-IUxM3RD4d-RqVCdj3JA0,10197
|
|
26
27
|
afterpython/cli/commands/format.py,sha256=VFwCG9KDTF6j4Y_Ewp4_RpS8uNBQNOAj9HU_G97my5A,710
|
|
27
|
-
afterpython/cli/commands/init.py,sha256=
|
|
28
|
+
afterpython/cli/commands/init.py,sha256=1tECOi_okfuZLgbXnVHek2-7qwLDXbLLEUrnX8EPrU4,14504
|
|
28
29
|
afterpython/cli/commands/init_branch_rules.py,sha256=fzAm8D5qbW3u4bEMpqPuRgO-0akuCGG7pu09JlKhYn4,243
|
|
29
30
|
afterpython/cli/commands/install.py,sha256=B8JuQmtU_4EZpHct2J5j30BGLkGmvwKvU26upbmabvQ,750
|
|
30
31
|
afterpython/cli/commands/lint.py,sha256=4m_eXX7PC4CKPj3YhkNf79XwAe1qTYluEdKPJf0aCkQ,794
|
|
@@ -38,30 +39,33 @@ afterpython/cli/commands/start.py,sha256=edbPWsgr4m5P4w-0z12ObwkdD60HGzV5jFQlbwl
|
|
|
38
39
|
afterpython/cli/commands/sync.py,sha256=Rx_Wmf8toys3FjENtcKVCw22ejEvOzyuqblWKA04dl0,6467
|
|
39
40
|
afterpython/cli/commands/update.py,sha256=q_ZxbPC-4fyUPlX3Ohoz5f3cJrz5j3d5-1AH453_VTQ,9649
|
|
40
41
|
afterpython/cli/main.py,sha256=XgmBo1rDv4EsX97fCfjd7kxFEu7SWNOJiiQulbzMljw,5007
|
|
41
|
-
afterpython/const.py,sha256=
|
|
42
|
+
afterpython/const.py,sha256=R4G-rq_1sZ35aQR0eXxpNgIjbk2Aw5lvhMSKNNjiyA4,225
|
|
42
43
|
afterpython/main.py,sha256=w0z6mTib3u4p2HxMrk-tIJlZtur7uRaqsbE0ewlYlSs,490
|
|
43
44
|
afterpython/pcu.py,sha256=nfdY2uKgOxHQ1AqUN9Y-L5BxDLd7NiuZf3tt_ef2wvA,6500
|
|
44
45
|
afterpython/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
|
-
afterpython/templates/afterpython-template.toml,sha256=
|
|
46
|
-
afterpython/templates/ci-workflow-template.yml,sha256=
|
|
46
|
+
afterpython/templates/afterpython-template.toml,sha256=c4lEl8B6ObhNHBKqlQNl1nS-47azH2Jg6YUj-494JCc,1725
|
|
47
|
+
afterpython/templates/ci-workflow-template.yml,sha256=gcxaaFW4OztMhtfEyraiGAJ0FBFg7A0J_3LiG7Lpa6U,8943
|
|
47
48
|
afterpython/templates/cliff-template.toml,sha256=HVemOBXIAvxz_8IMMAUcSRqYVmC0etfHleVeTG6woHg,5248
|
|
48
49
|
afterpython/templates/dependabot-template.yml,sha256=CBQEgh8EsXw2X7IqzGtFI7lVT9liF6PW4DvGLB0X2LY,1136
|
|
49
|
-
afterpython/templates/deploy-workflow-template.yml,sha256=
|
|
50
|
-
afterpython/templates/pdoc/
|
|
50
|
+
afterpython/templates/deploy-workflow-template.yml,sha256=n98miM10UUG1vkPATTGSP2QZQoJxvH5LqXnYhbF5Sbw,2858
|
|
51
|
+
afterpython/templates/pdoc/custom.css,sha256=eAkXzF8jYInX88kHec2MoArxunTWnxSsCzytRtFWriI,1764
|
|
52
|
+
afterpython/templates/pdoc/frame.html.jinja2,sha256=byBlXAQBCcTDgj8vCiDjFjjo46DG6uaLzzRf2x9pMHI,989
|
|
53
|
+
afterpython/templates/pdoc/syntax-highlighting.css,sha256=RqxTpVlTYuevLeGAUQbOJzK5UiVsQBhZfNSExvgmHag,10552
|
|
54
|
+
afterpython/templates/pdoc/theme.css,sha256=Qf8GHLKJryY8EBJBxreAGjSoUTG73PDkYTwlGFMO7eI,904
|
|
51
55
|
afterpython/templates/pre-commit-config-template.yaml,sha256=MXk79KxRFDaJynuCPtqgVbqJllaKIKI5Fdmwe08uiDU,2016
|
|
52
|
-
afterpython/templates/release-workflow-template.yml,sha256=
|
|
53
|
-
afterpython/templates/ruff-template.toml,sha256=
|
|
56
|
+
afterpython/templates/release-workflow-template.yml,sha256=9vd9C3-pWOHhA5WWgSG4PuH4bCBZs7EWmCc1kDIIVJM,4150
|
|
57
|
+
afterpython/templates/ruff-template.toml,sha256=IU33i84L7IhcLFYZ7Cfdg8EVlpq6YVAQJ3vLQGLXOxk,1316
|
|
54
58
|
afterpython/templates/ty-template.toml,sha256=8Z5jTnedzrNBgPaWYHY0RSVdXfg_SeNt1HO1OLnSA7E,666
|
|
55
59
|
afterpython/tools/_afterpython.py,sha256=y0-3IbKe1DV3JVJlKoIztoSyQs2K73LxNCgEyf1vitc,4946
|
|
56
60
|
afterpython/tools/_git.py,sha256=qUrunBNFwkbn8J1fJDXgiIaA2xNDuRCNryhbBPX2ReQ,6063
|
|
57
61
|
afterpython/tools/branch_rules.py,sha256=zrlN1FFl8gv9sKMbV7Ri5EuPhiUK3dTMOtMJRpZoRUE,3244
|
|
58
62
|
afterpython/tools/github_actions.py,sha256=0xzOc41QF1PKagD1CW7BAt_Rugy0KCEx_KfcrPKVl3c,3168
|
|
59
|
-
afterpython/tools/myst.py,sha256
|
|
63
|
+
afterpython/tools/myst.py,sha256=-bdasdZC6ElTTgPfbsHsZSskotNtlSv1ldev0L2GMJ0,10190
|
|
60
64
|
afterpython/tools/prek.py,sha256=NEEGf8alTt9MIelAJ8yxWD-V4mnM_pJ7oHgVQG8pbzo,3543
|
|
61
65
|
afterpython/tools/pyproject.py,sha256=Slhxo-Z9M7Gn9ZGL2BKmbPONpDgAJ1g33TdiulxwEyQ,3700
|
|
62
66
|
afterpython/utils.py,sha256=rbCOmRCHif2qzefw9rS-jFA05dz57hZKBr2mxVRaGR0,12406
|
|
63
67
|
afterpython/version.py,sha256=hihRV1S-gc1m46OaXD32ikkEkqzs-Gtq7AcAqOQV-wY,1603
|
|
64
|
-
afterpython-0.4.
|
|
65
|
-
afterpython-0.4.
|
|
66
|
-
afterpython-0.4.
|
|
67
|
-
afterpython-0.4.
|
|
68
|
+
afterpython-0.4.1.dist-info/WHEEL,sha256=MWx7psoF7KNST9G72pGtiBYuaXRXQXBk9pw5R6FzYko,80
|
|
69
|
+
afterpython-0.4.1.dist-info/entry_points.txt,sha256=roa0PDgBueM1JPbRG0G2OSxzaN394OUL_oS9iEwVLBc,80
|
|
70
|
+
afterpython-0.4.1.dist-info/METADATA,sha256=umUYEVFSbdJOdTNhrlnzbZyUHyIjx_ONyIobB4nJbkI,6330
|
|
71
|
+
afterpython-0.4.1.dist-info/RECORD,,
|
|
File without changes
|