Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Validate note files
run: python -c "from pathlib import Path; notes=list(Path('.').rglob('*.md')); assert len(notes)>=2 and all(p.read_text(encoding='utf-8').strip() for p in notes)"
run: python scripts/validate_notes.py
5 changes: 3 additions & 2 deletions 01-basics/01-变量和数据类型.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,9 @@ print("很高兴认识你!")
# 获取出生年份
birth_year = int(input("请输入你的出生年份:"))

# 计算年龄
current_year = 2026
# 使用当前年份计算年龄,避免示例过期
from datetime import date
current_year = date.today().year
age = current_year - birth_year

# 输出
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ python-notes/
- **GitHub:** [@DorianChn](https://github.com/DorianChn)
- **Email:** 3671276527@qq.com

## ✅ 本地验证

```bash
python scripts/validate_notes.py
```

该检查不需要第三方依赖,会验证笔记非空并检查仓库内的相对链接。

---

<div align="center">
Expand Down
45 changes: 45 additions & 0 deletions scripts/validate_notes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Validate the learning-note collection without third-party dependencies."""

from __future__ import annotations

import re
import sys
from pathlib import Path
from urllib.parse import unquote


ROOT = Path(__file__).resolve().parents[1]
LINK = re.compile(r"\[[^\]]+\]\(([^)]+)\)")


def fail(message: str) -> None:
print(f"validation error: {message}", file=sys.stderr)
raise SystemExit(1)


def main() -> None:
notes = sorted(ROOT.rglob("*.md"))
if len(notes) < 2:
fail(f"expected at least 2 Markdown files, found {len(notes)}")

for note in notes:
text = note.read_text(encoding="utf-8")
if not text.strip():
fail(f"empty note: {note.relative_to(ROOT)}")
for match in LINK.finditer(text):
target = unquote(match.group(1).split("#", 1)[0].strip())
if not target or target.startswith(("http://", "https://", "mailto:")):
continue
candidate = (note.parent / target).resolve()
try:
candidate.relative_to(ROOT)
except ValueError:
fail(f"link escapes repository: {note.relative_to(ROOT)} -> {target}")
if not candidate.exists():
fail(f"missing link: {note.relative_to(ROOT)} -> {target}")

print(f"validated {len(notes)} Markdown files and all relative links")


if __name__ == "__main__":
main()