projects/unit3/slack-notification/starter/validate_starter.py (143 lines of code) (raw):
#!/usr/bin/env python3
"""
Validation script for Module 1 starter code
Ensures the starter template is ready for learners to implement
"""
import subprocess
import sys
import os
from pathlib import Path
def test_project_structure():
"""Check that all required files exist."""
print("Project Structure:")
required_files = [
"server.py",
"pyproject.toml",
"README.md"
]
all_exist = True
for file in required_files:
if Path(file).exists():
print(f" ✓ {file} exists")
else:
print(f" ✗ {file} missing")
all_exist = False
return all_exist
def test_imports():
"""Test that the starter code imports work."""
try:
# Test importing the server module
import server
print("✓ server.py imports successfully")
# Check that FastMCP is imported
if hasattr(server, 'mcp'):
print("✓ FastMCP server instance found")
else:
print("✗ FastMCP server instance not found")
return False
return True
except ImportError as e:
print(f"✗ Import error: {e}")
print(" Please ensure you've installed dependencies: uv sync")
return False
def test_todos():
"""Check that TODO comments exist for learners."""
print("\nTODO Comments:")
with open("server.py", "r") as f:
content = f.read()
todos = []
for i, line in enumerate(content.split('\n'), 1):
if 'TODO' in line:
todos.append((i, line.strip()))
if todos:
print(f"✓ Found {len(todos)} TODO comments for learners:")
for line_no, todo in todos[:5]: # Show first 5
print(f" Line {line_no}: {todo[:60]}...")
if len(todos) > 5:
print(f" ... and {len(todos) - 5} more")
return True
else:
print("✗ No TODO comments found - learners need guidance!")
return False
def test_starter_runs():
"""Test that the starter code can at least be executed."""
print("\nExecution Test:")
try:
# Try to import and check if server can be initialized
import server
# If we can import it and it has the right attributes, it should run
if hasattr(server, 'mcp') and hasattr(server, 'send_slack_notification'):
print("✓ Server imports and initializes correctly")
return True
else:
print("✗ Server missing required components")
return False
except Exception as e:
print(f"✗ Failed to initialize server: {e}")
return False
def test_dependencies():
"""Check that pyproject.toml is properly configured."""
print("\nDependencies:")
try:
import tomllib
except ImportError:
import tomli as tomllib
try:
with open("pyproject.toml", "rb") as f:
config = tomllib.load(f)
# Check for required sections
if "project" in config and "dependencies" in config["project"]:
deps = config["project"]["dependencies"]
print(f"✓ Found {len(deps)} dependencies")
for dep in deps:
print(f" - {dep}")
else:
print("✗ No dependencies section found")
return False
return True
except Exception as e:
print(f"✗ Error reading pyproject.toml: {e}")
return False
def test_no_implementation():
"""Ensure starter code doesn't contain the solution."""
print("\nImplementation Check:")
with open("server.py", "r") as f:
content = f.read()
# Check that tool functions are not implemented
solution_indicators = [
"subprocess.run", # Git commands
"json.dumps", # Returning JSON
"git diff", # Git operations
"template", # Template logic
]
found_implementations = []
for indicator in solution_indicators:
if indicator in content.lower():
found_implementations.append(indicator)
if found_implementations:
print(f"⚠️ Found possible solution code: {', '.join(found_implementations)}")
print(" Make sure these are only in comments/examples")
return True # Warning, not failure
else:
print("✓ No solution implementation found (good!)")
return True
def main():
"""Run all validation checks."""
print("Module 1 Starter Code Validation")
print("=" * 50)
# Change to starter directory if needed
if Path("validate_starter.py").exists():
os.chdir(Path("validate_starter.py").parent)
tests = [
("Project Structure", test_project_structure),
("Python Imports", test_imports),
("TODO Comments", test_todos),
("Starter Execution", test_starter_runs),
("Dependencies", test_dependencies),
("Clean Starter", test_no_implementation)
]
results = []
for test_name, test_func in tests:
print(f"\n{test_name}:")
try:
results.append(test_func())
except Exception as e:
print(f"✗ Test failed with error: {e}")
results.append(False)
print("\n" + "=" * 50)
passed = sum(results)
total = len(results)
print(f"Checks passed: {passed}/{total}")
if passed == total:
print("\n✓ Starter code is ready for learners!")
print("\nLearners should:")
print("1. Run: uv sync")
print("2. Follow the TODO comments in server.py")
print("3. Test with: uv run pytest test_server.py")
print("4. Configure Claude Desktop when ready")
else:
print("\n✗ Some checks failed. Please review the starter code.")
sys.exit(1)
if __name__ == "__main__":
main()