Skip to content

Commit a09e2dd

Browse files
committed
Add a helper script for creating empty POTM pages
1 parent 864dbad commit a09e2dd

2 files changed

Lines changed: 178 additions & 1 deletion

File tree

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,19 @@ To **publish** when you're happy with your post, push it to a branch on [draft-g
8383

8484
### POTM
8585

86-
Papers-of-the-month are special, consisting of a **root** page at `pages/posts/potm/YYYY/MM/potm.md`, and multiple **child** pages at `pages/posts/potm/YYYY/MM/paper-slug/paper-slug.md`. They should have specific frontmatter:
86+
Papers-of-the-month are special, consisting of a **root** page at `pages/posts/potm/YYYY/MM/potm.md`, and multiple **child** pages at `pages/posts/potm/YYYY/MM/paper-slug/paper-slug.md`.
87+
88+
To simplify creation, use the helper script `tools/create_potm.py`:
89+
90+
```sh
91+
# Create a new POTM root page for February 2026
92+
python tools/create_potm.py --month 2026-02
93+
94+
# Create a new POTM child page for a paper with slug 'muon' in the most recent POTM month
95+
python tools/create_potm.py --paper muon
96+
```
97+
98+
If creating these pages manually, note that they should have specific frontmatter:
8799

88100
**Frontmatter for a POTM root page**
89101

tools/create_potm.py

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
"""Create POTM scaffolding files.
2+
3+
Usage:
4+
5+
python tools/create_potm.py --month 2026-02
6+
7+
.. to create the root page for February 2026.
8+
9+
python tools/create_potm.py --paper muon
10+
11+
.. to create an empty paper review in the most recent POTM month.
12+
"""
13+
14+
import argparse
15+
import datetime as dt
16+
import logging
17+
import re
18+
from pathlib import Path
19+
20+
ROOT_TEMPLATE = """
21+
---
22+
date: {date}
23+
title: '{month_name} Papers: TODO Title'
24+
merge_potm: true
25+
---
26+
27+
... POTM intro paragraph / meta-review of this month's papers.
28+
"""
29+
30+
REVIEW_TEMPLATE = """
31+
---
32+
paper_title: "<Full Paper Title>"
33+
paper_authors: "<Forename Surname, et al.' or 'Forename Surname, Forename Surname and Forename Surname.' (max 3 unless more than 3 first authors)>"
34+
paper_orgs: "<name of org>"
35+
paper_link: "https://arxiv.org/abs/<paper_id>"
36+
tags: # see https://graphcore-research.github.io/tags/
37+
- efficient-inference
38+
potm_order: 1 # editor to decide
39+
review_authors: [] # "<alias>"
40+
---
41+
42+
200 words is a rough guide for the length of a summary. Feel free to go a fair bit over or under if needs be. See [README](/README.md) for a guide to formatting & previewing.
43+
44+
### The key idea
45+
46+
... a few sentences outlining why the paper is interesting
47+
48+
### [optional] Background
49+
50+
... if necessary, a short intro to background matierial needed to understand the method
51+
52+
### Their method
53+
54+
...
55+
56+
### Results
57+
58+
...
59+
60+
### [optional] Takeaways
61+
62+
...
63+
"""
64+
65+
ROOT = Path(__file__).resolve().parents[1]
66+
POTM_DIR = ROOT / "pages" / "posts" / "potm"
67+
LOGGER = logging.getLogger(__name__)
68+
69+
70+
def parse_month(month: str) -> tuple[int, int]:
71+
m = re.fullmatch(r"(\d{4})-(\d{2})", month)
72+
if not m:
73+
raise ValueError(f"Invalid --month '{month}', expected YYYY-MM")
74+
year = int(m.group(1))
75+
mon = int(m.group(2))
76+
if not 1 <= mon <= 12:
77+
raise ValueError(f"Invalid month in --month '{month}'")
78+
return year, mon
79+
80+
81+
def find_latest_potm_month() -> tuple[int, int] | None:
82+
latest: tuple[int, int] | None = None
83+
if POTM_DIR.exists():
84+
for year_dir in POTM_DIR.iterdir():
85+
if not year_dir.is_dir() or not year_dir.name.isdigit():
86+
continue
87+
year_val = int(year_dir.name)
88+
for month_dir in year_dir.iterdir():
89+
if not month_dir.is_dir() or not re.fullmatch(r"\d{2}", month_dir.name):
90+
continue
91+
month_val = int(month_dir.name)
92+
if not 1 <= month_val <= 12:
93+
continue
94+
value = (year_val, month_val)
95+
if latest is None or value > latest:
96+
latest = value
97+
return latest
98+
99+
100+
def create_root(month_dir: Path, year: int, month: int) -> None:
101+
potm_root = month_dir / "potm.md"
102+
if potm_root.exists():
103+
LOGGER.warning(f"Already exists: {potm_root.relative_to(ROOT)}")
104+
return
105+
106+
potm_root.parent.mkdir(parents=True, exist_ok=True)
107+
potm_root.write_text(
108+
ROOT_TEMPLATE.strip().format(
109+
date=dt.date.today().isoformat(),
110+
month_name=dt.date(year, month, 1).strftime("%B"),
111+
)
112+
+ "\n",
113+
encoding="utf-8",
114+
)
115+
LOGGER.info(f"Created: {potm_root.relative_to(ROOT)}")
116+
117+
118+
def create_paper_review(month_dir: Path, paper_slug: str) -> None:
119+
out_path = month_dir / paper_slug / f"{paper_slug}.md"
120+
if out_path.exists():
121+
LOGGER.warning(f"Already exists: {out_path.relative_to(ROOT)}")
122+
return
123+
124+
out_path.parent.mkdir(parents=True, exist_ok=True)
125+
out_path.write_text(REVIEW_TEMPLATE.strip() + "\n", encoding="utf-8")
126+
LOGGER.info(f"Created: {out_path.relative_to(ROOT)}")
127+
128+
129+
def main() -> int:
130+
logging.basicConfig(format="%(name)s:%(levelname)s: %(message)s")
131+
LOGGER.setLevel(logging.INFO)
132+
parser = argparse.ArgumentParser(description="Create POTM scaffolding pages")
133+
parser.add_argument(
134+
"--month",
135+
type=parse_month,
136+
help="YYYY-MM format specifying the month (default for `--paper` is the most recent month).",
137+
)
138+
parser.add_argument(
139+
"--paper",
140+
type=str,
141+
help="Paper short name (e.g. 'muon') to scaffold a POTM child page.",
142+
)
143+
parser.usage = """%(prog)s --month YYYY-MM (to create a new root page)
144+
%(prog)s --paper paper-slug [--month YYYY-MM] (to create a paper review in most recent [or specified] month)
145+
"""
146+
args = parser.parse_args()
147+
148+
if not (args.month or args.paper):
149+
parser.error("Must specify --month and/or --paper")
150+
151+
year, month = args.month or find_latest_potm_month()
152+
potm_dir = POTM_DIR / f"{year:04d}" / f"{month:02d}"
153+
154+
if args.paper:
155+
if not re.fullmatch(r"[a-zA-Z0-9-]+", args.paper):
156+
parser.error(
157+
f"Invalid slug --paper '{args.paper}'. Use letters, digits and '-'."
158+
)
159+
create_paper_review(potm_dir, args.paper)
160+
else:
161+
create_root(potm_dir, year, month)
162+
163+
164+
if __name__ == "__main__":
165+
main()

0 commit comments

Comments
 (0)