Skip to content

Commit fe7e1ae

Browse files
committed
Replace the hand-written project cards in index.html with a templated
build pipeline
1 parent a5b0b12 commit fe7e1ae

6 files changed

Lines changed: 34 additions & 64 deletions

File tree

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ __pycache__/
44
*.pyo
55
*.egg-info/
66

7-
# Mock data used only by `python scripts/build.py --mock`
8-
scripts/_mock_repos.json
9-
107
# Local dev scratch
118
*.tmp
129
_test_out.html

README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,11 @@ GitHub API ──► scripts/build.py ──► index.html
2121
| `site.json` | Categories, keywords, excluded repos, copy. **Zero repo metadata.** | yes |
2222
| `templates/index.template.html` | Static HTML shell. Contains `{{projects}}` placeholder. | yes |
2323
| `scripts/build.py` | Fetches repos + renders HTML. | rarely |
24-
| `scripts/_mock_repos.json` | Local fixtures for `--mock` mode. Ignored by git. | n/a |
2524
| `index.html` | **Generated. Do not edit by hand.** | no |
2625

2726
## Local development
2827

2928
```bash
30-
# Render using mock data (no network, fast iteration on templates)
31-
python scripts/build.py --mock
32-
3329
# Render against the live GitHub API (rate-limited to 60/h without token)
3430
python scripts/build.py
3531

index.html

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<meta name="description" content="Python Backport Developers™ — An organization dedicated to backporting Python's newest features and libraries to older Python versions.">
6+
<meta name="description" content="An organization for backporting Python's new features">
77
<meta name="theme-color" content="#0d1117">
88
<title>Python Backport Developers™</title>
99
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%230d1117'/%3E%3Cpath d='M30.5 12c-9 0-15 5.5-15 12.5 0 4.4 2.4 7.7 6.4 9.7l-2 6.4c-.2.7.5 1.3 1.1.9l7.4-4.7c1 .1 1.7.2 2.6.2 9 0 15-5.5 15-12.5S39.5 12 30.5 12zm-5.6 9.6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm11.2 0c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z' fill='%23FFD43B'/%3E%3Cpath d='M44 32v2c0 1.5-.3 2.9-.9 4.2l2.3 5.4c.2.6-.4 1.1-.9.8l-5.5-2.7C36.5 42.7 33.7 43 31 43c-1 0-1.9-.1-2.8-.3l2.3-1.5c.2 0 .4.1.5.1 6.4 0 11.3-3.5 11.3-8.7 0-.2 0-.4-.1-.6h1.8zM45.6 28c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5z' fill='%233572A5'/%3E%3C/svg%3E">
@@ -482,12 +482,10 @@
482482
<span>Open source · Backporting Python's future</span>
483483
</div>
484484
<h1 class="hero-title">
485-
Bringing <span class="gradient">tomorrow's Python</span><br>
486-
to yesterday's interpreters.
485+
Python Backport Developers™
487486
</h1>
488487
<p class="hero-subtitle">
489-
We are <strong>Python Backport Developers™</strong> — an open-source organization dedicated
490-
to backporting the newest features, libraries and tooling of CPython into older Python versions.
488+
An organization for backporting Python's new features
491489
</p>
492490
<div class="hero-actions">
493491
<a href="#projects" class="btn btn-primary">
@@ -584,10 +582,10 @@ <h2 class="section-title">Core backports</h2>
584582
<p class="section-desc">Libraries that reimplement or backport features of modern CPython.</p>
585583
</div>
586584
<div class="projects-grid">
587-
<a href="https://github.com/pythonbackport/profiling" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>profiling</span></div></div><div class="project-desc">Deterministic tracing profiler and a low-overhead statistical sampling profiler named Tachyon, backported from CPython 3.15 to 3.14. Exports flame graphs, pstats, Gecko profiles, JSONL and more.</div><div class="project-meta"><span>12</span><span>python · profiling · sampling</span><span>MIT</span></div></a>
588-
<a href="https://github.com/pythonbackport/frozendict" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>frozendict</span></div></div><div class="project-desc">A fully hashable, immutable mapping type — the frozendict proposed for the standard library, available today on every supported Python version.</div><div class="project-meta"><span>7</span><span>python · immutable · hashable</span><span>MIT</span></div></a>
589-
<a href="https://github.com/pythonbackport/lazyimports" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>lazyimports</span></div><span class="project-tag">PEP-690</span></div><div class="project-desc">Implementation of PEP 690 — Lazy Imports. Defer module imports until first use to slash startup time and memory footprint of large applications.</div><div class="project-meta"><span>4</span><span>python · pep-690 · lazy-import</span><span>MIT</span></div></a>
590-
<a href="https://github.com/pythonbackport/sentinel" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>sentinel</span></div><span class="project-tag">PEP-769</span></div><div class="project-desc">Backport of PEP 769 — a standardized sentinel object for default arguments. Replace None, object() and bespoke sentinels with a clean, well-typed API.</div><div class="project-meta"><span>★ 2</span><span>python · pep-769 · typing</span><span>MIT</span></div></a>
585+
<a href="https://github.com/pythonbackport/python-profiling" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>python-profiling</span></div></div><div class="project-desc">Backport from python 3.15's new library 'profiling'</div><div class="project-meta"><span>1</span><span>profiling · python · python-profiling</span><span>NOASSERTION</span></div></a>
586+
<a href="https://github.com/pythonbackport/python-frozendict" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>python-frozendict</span></div></div><div class="project-desc">Standalone back-port of Python 3.15's `frozendict` builtin.</div><div class="project-meta"><span>2</span><span>frozendict · python · python-frozendict</span><span>MIT</span></div></a>
587+
<a href="https://github.com/pythonbackport/python-lazyimports" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>python-lazyimports</span></div></div><div class="project-desc">Backport of Python 3.15's lazy import statement</div><div class="project-meta"><span>3</span><span>lazy-imports · python · python3</span><span>NOASSERTION</span></div></a>
588+
<a href="https://github.com/pythonbackport/pythonbackport-sentinel" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>pythonbackport-sentinel</span></div></div><div class="project-desc">Standalone back-port of Python 3.15's `sentinel` builtin.</div><div class="project-meta"><span>★ 2</span><span>python · python3 · python315</span><span>MIT</span></div></a>
591589
</div>
592590
</div>
593591
</section>
@@ -596,10 +594,10 @@ <h2 class="section-title">Core backports</h2>
596594
<div class="container">
597595
<div class="section-head reveal">
598596
<h2 class="section-title">Community</h2>
599-
<p class="section-desc">Discussion hubs, RFCs and meta-repositories for the org.</p>
597+
<p class="section-desc">Discussion hubs and meta-repositories for the org.</p>
600598
</div>
601599
<div class="projects-grid">
602-
<a href="https://github.com/pythonbackport/community" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>community</span></div></div><div class="project-desc">The home of public discussions, Q&amp;A, roadmaps and proposals for the pythonbackport organization.</div><div class="project-meta"><span>1</span><span>discussions · community · forum</span><span>MIT</span></div></a>
600+
<a href="https://github.com/pythonbackport/community" target="_blank" rel="noopener" class="project-card reveal"><div class="project-head"><div class="project-title"><span>community</span></div></div><div class="project-desc">Community Discussions</div><div class="project-meta"><span>2</span><span>CC-BY-4.0</span></div></a>
603601
</div>
604602
</div>
605603
</section>

scripts/build.py

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
USER_AGENT = "pythonbackport-website/1.0"
4040

4141
PLACEHOLDER_PROJECTS = "{{projects}}"
42-
PLACEHOLDER_SITE = "{{site_json_ld}}"
42+
PLACEHOLDER_TITLE = "{{site_title}}"
43+
PLACEHOLDER_TAGLINE = "{{site_tagline}}"
4344

4445

4546
# ---------- GitHub API ------------------------------------------------------
@@ -337,13 +338,17 @@ def assemble(site: dict, categorized: list[tuple[str, list[dict]]]) -> str:
337338

338339
projects_html = "\n".join(b for b in section_blocks if b)
339340

340-
# The order of substitution matters: stats + marquee must come before
341-
# {{projects}} so that any matching placeholders inside category blocks
342-
# (shouldn't exist but defensive) aren't double-replaced.
341+
site_block = site.get("site", {})
342+
title = esc(site_block.get("title", site["org"]))
343+
tagline = esc(site_block.get("tagline", ""))
344+
345+
# Replace all known placeholders. Order matters: title/tagline first,
346+
# then {{projects}}, then optional stats/marquee.
347+
tpl = tpl.replace(PLACEHOLDER_TITLE, title)
348+
tpl = tpl.replace(PLACEHOLDER_TAGLINE, tagline)
343349
if PLACEHOLDER_PROJECTS not in tpl:
344350
raise SystemExit(f"Template missing placeholder {PLACEHOLDER_PROJECTS!r}")
345351
tpl = tpl.replace(PLACEHOLDER_PROJECTS, projects_html)
346-
# Stats/marquee are inserted by separate placeholders if used.
347352
for ph, body in (("{{stats}}", stats_block), ("{{marquee}}", marquee_block)):
348353
if ph in tpl:
349354
tpl = tpl.replace(ph, body)
@@ -357,36 +362,11 @@ def main(argv: Iterable[str] | None = None) -> int:
357362
help="Exit 1 if index.html would change (CI guard)")
358363
p.add_argument("--stdout", action="store_true",
359364
help="Write HTML to stdout instead of index.html")
360-
p.add_argument("--mock", action="store_true",
361-
help="Use scripts/_mock_repos.json instead of hitting GitHub (CI/tests)")
362365
args = p.parse_args(list(argv) if argv is not None else None)
363366

364367
site = load_site()
365368
token = os.environ.get("GH_TOKEN") or os.environ.get("GITHUB_TOKEN")
366-
367-
if args.mock:
368-
mock_path = ROOT / "scripts" / "_mock_repos.json"
369-
raw = json.loads(mock_path.read_text(encoding="utf-8"))
370-
visible = [r for r in raw if should_show(r, site)]
371-
by_cat: dict[str, list[dict]] = {k: [] for k in site.get("categories", {})}
372-
for r in visible:
373-
cat = classify(r, site)
374-
cat_cfg = site.get("categories", {}).get(cat, {})
375-
if cat_cfg.get("hidden_by_default"):
376-
continue
377-
by_cat.setdefault(cat, []).append(r)
378-
categorized: list[tuple[str, list[dict]]] = []
379-
for cat_key, cat_cfg in site.get("categories", {}).items():
380-
items = by_cat.get(cat_key, [])
381-
items_sorted = sorted(items, key=lambda r: (
382-
[(cat_cfg.get("order", []).index(r["name"]) if r["name"] in cat_cfg.get("order", []) else 999)],
383-
-r.get("stargazers_count", 0),
384-
r["name"].lower(),
385-
))
386-
if items_sorted:
387-
categorized.append((cat_key, items_sorted))
388-
else:
389-
categorized = build_repos(site, token)
369+
categorized = build_repos(site, token)
390370

391371
rendered = assemble(site, categorized)
392372

site.json

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
22
"org": "pythonbackport",
33
"site": {
4-
"title": "Python Backport Developers",
5-
"tagline": "Bringing tomorrow's Python to yesterday's interpreters.",
4+
"title": "Python Backport Developers",
5+
"tagline": "An organization for backporting Python's new features",
66
"intro": "We are Python Backport Developers — an open-source organization dedicated to backporting the newest features, libraries and tooling of CPython into older Python versions."
77
},
88
"display": {
99
"show_archived": false,
1010
"show_forks": false,
11-
"exclude_repos": ["pb-website", "Entity521"],
11+
"exclude_repos": ["website", ".github"],
1212
"max_description_chars": 220,
1313
"max_topics_per_card": 3
1414
},
@@ -17,16 +17,17 @@
1717
"title": "Core backports",
1818
"description": "Libraries that reimplement or backport features of modern CPython.",
1919
"keywords": [
20-
"backport", "pep ", "stdlib", "immutable", "lazy import",
21-
"sentinel", "froze", "hashable", "profil", "tachyon",
22-
"c extension", "sampling"
20+
"backport", "back-port", "back port", "pep ", "stdlib",
21+
"immutable", "lazy import", "lazy imports", "sentinel",
22+
"froze", "hashable", "profil", "tachyon",
23+
"c extension", "sampling", "builtin"
2324
],
24-
"order": ["profiling", "frozendict", "lazyimports", "sentinel"]
25+
"order": ["python-profiling", "python-frozendict", "python-lazyimports", "pythonbackport-sentinel"]
2526
},
2627
"community": {
2728
"title": "Community",
28-
"description": "Discussion hubs, RFCs and meta-repositories for the org.",
29-
"keywords": ["discussion", "community", "forum"],
29+
"description": "Discussion hubs and meta-repositories for the org.",
30+
"keywords": ["discussion", "discussions", "community", "forum"],
3031
"always_include_names": ["community"],
3132
"order": ["community"]
3233
},

templates/index.template.html

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<meta name="description" content="Python Backport Developers™ — An organization dedicated to backporting Python's newest features and libraries to older Python versions.">
6+
<meta name="description" content="{{site_tagline}}">
77
<meta name="theme-color" content="#0d1117">
8-
<title>Python Backport Developers™</title>
8+
<title>{{site_title}}</title>
99
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%230d1117'/%3E%3Cpath d='M30.5 12c-9 0-15 5.5-15 12.5 0 4.4 2.4 7.7 6.4 9.7l-2 6.4c-.2.7.5 1.3 1.1.9l7.4-4.7c1 .1 1.7.2 2.6.2 9 0 15-5.5 15-12.5S39.5 12 30.5 12zm-5.6 9.6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm11.2 0c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z' fill='%23FFD43B'/%3E%3Cpath d='M44 32v2c0 1.5-.3 2.9-.9 4.2l2.3 5.4c.2.6-.4 1.1-.9.8l-5.5-2.7C36.5 42.7 33.7 43 31 43c-1 0-1.9-.1-2.8-.3l2.3-1.5c.2 0 .4.1.5.1 6.4 0 11.3-3.5 11.3-8.7 0-.2 0-.4-.1-.6h1.8zM45.6 28c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5z' fill='%233572A5'/%3E%3C/svg%3E">
1010
<link rel="preconnect" href="https://fonts.googleapis.com">
1111
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -482,12 +482,10 @@
482482
<span>Open source · Backporting Python's future</span>
483483
</div>
484484
<h1 class="hero-title">
485-
Bringing <span class="gradient">tomorrow's Python</span><br>
486-
to yesterday's interpreters.
485+
{{site_title}}
487486
</h1>
488487
<p class="hero-subtitle">
489-
We are <strong>Python Backport Developers™</strong> — an open-source organization dedicated
490-
to backporting the newest features, libraries and tooling of CPython into older Python versions.
488+
{{site_tagline}}
491489
</p>
492490
<div class="hero-actions">
493491
<a href="#projects" class="btn btn-primary">

0 commit comments

Comments
 (0)