#!/usr/bin/env python3 """Update README.md code blocks marked with snippet-source comments from the referenced files. Usage: python scripts/update_readme_snippets.py [--check] """ import argparse import re import sys from pathlib import Path def get_github_url(file_path: str) -> str: """Return the GitHub URL for a repo-relative file path.""" base_url = "https://github.com/modelcontextprotocol/python-sdk/blob/main" return f"{base_url}/{file_path}" def process_snippet_block(match: re.Match[str], check_mode: bool = False) -> str: """Return the regenerated block, or the original in check mode when the code is unchanged.""" full_match = match.group(0) indent = match.group(1) file_path = match.group(2) try: # A missing source file must be fatal: returning the stale block would let --check # exit 0, hiding renamed/deleted snippets from CI. SystemExit escapes the # `except Exception` below. file = Path(file_path) if not file.exists(): sys.exit(f"Error: snippet-source file not found: {file_path}") code = file.read_text().rstrip() github_url = get_github_url(file_path) indented_code = code.replace("\n", f"\n{indent}") replacement = f"""{indent} {indent}```python {indent}{indented_code} {indent}``` {indent}_Full example: [{file_path}]({github_url})_ {indent}""" if check_mode: existing_content = match.group(3) if existing_content is not None: existing_lines = existing_content.strip().split("\n") code_lines: list[str] = [] in_code = False for line in existing_lines: if line.strip() == "```python": in_code = True elif line.strip() == "```": break elif in_code: code_lines.append(line) existing_code = "\n".join(code_lines).strip() expected_code = code.replace("\n", f"\n{indent}").strip() if existing_code == expected_code: return full_match return replacement except Exception as e: print(f"Error processing {file_path}: {e}") return full_match def update_readme_snippets(check_mode: bool = False) -> bool: """Update README.md snippet blocks from their source files. Returns False when README.md is missing or check_mode finds stale snippets. """ readme_path = Path("README.md") if not readme_path.exists(): print(f"Error: README file not found: {readme_path}") return False content = readme_path.read_text() original_content = content # Matches `` ... `` blocks pattern = r"^(\s*)\n" r"(.*?)" r"^\1" updated_content = re.sub( pattern, lambda m: process_snippet_block(m, check_mode), content, flags=re.MULTILINE | re.DOTALL ) if check_mode: if updated_content != original_content: print( f"Error: {readme_path} has outdated code snippets. " "Run 'python scripts/update_readme_snippets.py' to update." ) return False else: print(f"✓ {readme_path} code snippets are up to date") return True else: if updated_content != original_content: readme_path.write_text(updated_content) print(f"✓ Updated {readme_path}") else: print(f"✓ {readme_path} already up to date") return True def main(): parser = argparse.ArgumentParser(description="Update README code snippets from source files") parser.add_argument( "--check", action="store_true", help="Check mode - verify snippets are up to date without modifying" ) args = parser.parse_args() success = update_readme_snippets(check_mode=args.check) if not success: sys.exit(1) if __name__ == "__main__": main()