Files
cs249r_book/tools/scripts/content/format_python_in_qmd.py
Vijay Janapa Reddi 3b37726b27 refactor(tools): reorganize scripts directory structure for better maintainability
Consolidated 21 root-level scripts into logical subdirectories:

New structure:
- images/: All image management scripts (10 files consolidated from 3 locations)
- infrastructure/: CI/CD and container scripts (3 files)
- content/: Added formatting scripts (3 files moved from root)
- testing/: All test scripts (5 files consolidated)
- glossary/: Added standardize_glossaries.py
- maintenance/: Added generate_release_notes.py, preflight.py
- utilities/: Added validation scripts

Benefits:
- Reduced root-level clutter (21 → 2 files)
- Related scripts grouped logically
- Easier to find and maintain scripts
- Follows standard project organization patterns

Changes:
- Created new subdirectories: images/, infrastructure/
- Moved scripts from root to appropriate subdirectories
- Consolidated scattered scripts (images were in 3 places)
- Updated all pre-commit hook references
- Created README files for new directories
- Included backup file for rollback if needed

Tool: tools/scripts/reorganize_scripts.py (for future reference)
2025-10-09 13:36:16 -04:00

116 lines
3.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""Format Python code blocks in .qmd files using Black."""
import ast
import re
import sys
from pathlib import Path
from typing import List
import subprocess
import tempfile
def is_valid_python(code: str) -> bool:
"""Check if code string is valid Python syntax."""
try:
ast.parse(code)
return True
except SyntaxError:
return False
def format_python_blocks(content: str, line_length: int = 70) -> str:
"""Find and format Python code blocks in markdown using Black."""
lines = content.split('\n')
result = []
in_python_block = False
python_lines = []
block_indent = ""
for line in lines:
# Detect start of Python block
if re.match(r'^```(\{\.)?python', line):
in_python_block = True
result.append(line)
python_lines = []
continue
# Detect end of Python block
if in_python_block and line.strip() == '```':
# Format accumulated Python code with Black
if python_lines:
code = '\n'.join(python_lines)
# Validate Python syntax before attempting to format
if not is_valid_python(code):
# Skip formatting for invalid Python (e.g., shell, pseudocode, etc.)
result.extend(python_lines)
else:
try:
# Write to temp file
with tempfile.NamedTemporaryFile(
mode='w', suffix='.py', delete=False
) as f:
f.write(code)
temp_path = f.name
# Run Black with stderr suppressed
subprocess.run(
['black', '--line-length', str(line_length),
'--quiet', temp_path],
check=True,
stderr=subprocess.DEVNULL,
stdout=subprocess.DEVNULL
)
# Read formatted code
with open(temp_path, 'r') as f:
formatted = f.read().rstrip()
result.extend(formatted.split('\n'))
# Cleanup
Path(temp_path).unlink()
except (subprocess.CalledProcessError, FileNotFoundError):
# If Black fails or isn't installed, keep original
result.extend(python_lines)
python_lines = []
in_python_block = False
result.append(line)
continue
# Accumulate Python code
if in_python_block:
python_lines.append(line)
else:
result.append(line)
return '\n'.join(result)
def main(files: List[str], line_length: int = 70) -> int:
"""Format Python blocks in .qmd files."""
changed = 0
for filepath in files:
path = Path(filepath)
if path.suffix == '.qmd':
try:
content = path.read_text(encoding='utf-8')
formatted = format_python_blocks(content, line_length)
if formatted != content:
path.write_text(formatted, encoding='utf-8')
print(f"Formatted: {filepath}")
changed += 1
except Exception as e:
print(f"Error processing {filepath}: {e}",
file=sys.stderr)
return 1
return 0 if changed == 0 else 1 # Return 1 if changes made
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))