================================================================================ PRACTICAL PYTHON SCRIPTING - CHALLENGE 3 SOLUTION Chapter 5: Building rebuild_typescript_course.py Challenge: Complete Rebuild Script ================================================================================ PROBLEM: Create a script that: 1. Finds all chapter files 2. Parses metadata from HTML 3. Connects to database using db_utils 4. Creates subtopic and inserts all chapters 5. Reports final count SOLUTION: ================================================================================ import sys from pathlib import Path import re # Import from db_utils sys.path.insert(0, str(Path(__file__).parent)) from db_utils import DatabaseConnection, get_or_create_subtopic, insert_chapter_with_content # Constants SUBJECT_ID = 3 # Programming SUBJECT_NAME = "Programming" SUBTOPIC_NAME = "TypeScript Fundamentals" # Paths SCRIPT_DIR = Path(__file__).resolve().parent CHAPTERS_DIR = SCRIPT_DIR / "courses" / "Programming" / "TypeScript" / "html" def find_chapters(): """Find all chapter HTML files.""" if not CHAPTERS_DIR.exists(): print(f"❌ Chapters directory not found: {CHAPTERS_DIR}") return [] html_files = sorted(CHAPTERS_DIR.glob("ts1-*.html")) if not html_files: print(f"⚠️ No chapter files found in {CHAPTERS_DIR}") return [] print(f"✅ Found {len(html_files)} chapter files\n") return html_files def parse_chapter(html_file): """Extract chapter data from HTML file.""" try: html_content = html_file.read_text(encoding='utf-8') # Extract chapter number match = re.match(r"ts1-(\d+)", html_file.stem) if not match: return None chapter_num = int(match.group(1)) # Extract title from

title_match = re.search(r'

(.*?)

', html_content) chapter_title = title_match.group(1).strip() if title_match else f"Chapter {chapter_num}" return { 'number': chapter_num, 'title': chapter_title, 'html': html_content, 'sort_order': chapter_num * 10 } except Exception as e: print(f"❌ Error parsing {html_file.name}: {e}") return None def main(): """Main rebuild workflow.""" print("=" * 60) print("🚀 TypeScript Course Rebuild") print("=" * 60 + "\n") # Step 1: Find chapters print("📚 Step 1: Finding chapter files...") html_files = find_chapters() if not html_files: print("❌ No chapters found. Exiting.") return False # Step 2: Connect to database print("📚 Step 2: Connecting to database...") db = DatabaseConnection() if not db.connect(): print("❌ Database connection failed") return False try: # Step 3: Create or get subtopic print(f"\n📚 Step 3: Creating subtopic '{SUBTOPIC_NAME}'...\n") subtopic_id = get_or_create_subtopic( db, subject_id=SUBJECT_ID, subtopic_name=SUBTOPIC_NAME, description="Master TypeScript from fundamentals to advanced patterns" ) if subtopic_id is None: print("❌ Failed to create subtopic") return False # Step 4: Insert chapters print(f"\n📚 Step 4: Inserting {len(html_files)} chapters...\n") chapters_inserted = 0 chapters_failed = 0 for html_file in html_files: chapter = parse_chapter(html_file) if not chapter: chapters_failed += 1 continue page_id = insert_chapter_with_content( db, subtopic_id=subtopic_id, chapter_title=chapter['title'], html_content=chapter['html'], sort_order=chapter['sort_order'] ) if page_id: chapters_inserted += 1 else: chapters_failed += 1 # Step 5: Report results print("\n" + "=" * 60) print("✅ REBUILD COMPLETE!") print("=" * 60) print(f"\n📊 Results:") print(f" Course: {SUBTOPIC_NAME}") print(f" Subject: {SUBJECT_NAME}") print(f" Chapters Inserted: {chapters_inserted}") print(f" Chapters Failed: {chapters_failed}") print(f" Total Found: {len(html_files)}") if chapters_failed > 0: print(f"\n⚠️ Some chapters failed to insert. Check output above.") return chapters_failed == 0 except Exception as e: print(f"❌ Unexpected error: {e}") return False finally: db.disconnect() if __name__ == "__main__": success = main() sys.exit(0 if success else 1) ================================================================================ HOW IT WORKS: ================================================================================ 1. IMPORTS & SETUP - Import db_utils functions - Define constants for subject/course - Calculate paths using Path(__file__) 2. find_chapters() - Use CHAPTERS_DIR.glob("ts1-*.html") - Return sorted list of HTML files - Return empty list if none found 3. parse_chapter() - Read HTML file content - Extract chapter number from filename - Extract title from

tag with regex - Return dict with all metadata 4. main() - The Complete Workflow Step 1: Find all chapter files Step 2: Connect to database Step 3: Create subtopic Step 4: For each chapter: - Parse metadata - Insert into database Step 5: Report results 5. CLEANUP - finally block ensures db.disconnect() - Always runs, even if errors occur ================================================================================ TESTING: ================================================================================ python rebuild_typescript_course.py Output: ============================================================ 🚀 TypeScript Course Rebuild ============================================================ 📚 Step 1: Finding chapter files... ✅ Found 12 chapter files 📚 Step 2: Connecting to database... ✅ Database connection established 📚 Step 3: Creating subtopic 'TypeScript Fundamentals'... ✅ Created subtopic 'TypeScript Fundamentals' with ID 8 📚 Step 4: Inserting 12 chapters... ✅ Created chapter with ID: 101 ✅ Created chapter with ID: 102 ✅ Created chapter with ID: 103 ✅ Created chapter with ID: 104 ✅ Created chapter with ID: 105 ✅ Created chapter with ID: 106 ✅ Created chapter with ID: 107 ✅ Created chapter with ID: 108 ✅ Created chapter with ID: 109 ✅ Created chapter with ID: 110 ✅ Created chapter with ID: 111 ✅ Created chapter with ID: 112 ============================================================ ✅ REBUILD COMPLETE! ============================================================ 📊 Results: Course: TypeScript Fundamentals Subject: Programming Chapters Inserted: 12 Chapters Failed: 0 Total Found: 12 ✅ Connection closed ================================================================================ EVERYTHING BROUGHT TOGETHER: ================================================================================ This script uses ALL chapters 1-5: Chapter 1 - Paths & File System: ✅ Path(__file__).resolve().parent ✅ CHAPTERS_DIR.glob("ts1-*.html") ✅ .exists() and .read_text() Chapter 2 - Configuration: ✅ DatabaseConnection loads .env ✅ Credentials automatic (no hard-coding) Chapter 3 - Database Connections: ✅ db.connect() / db.disconnect() ✅ try/finally for cleanup Chapter 4 - db_utils.py: ✅ get_or_create_subtopic() ✅ insert_chapter_with_content() Chapter 5 - This Script: ✅ Orchestrates the complete workflow ✅ Brings all pieces together This is a REAL PRODUCTION SCRIPT! ================================================================================ KEY TAKEAWAYS: ================================================================================ ✅ How to orchestrate a complex workflow ✅ How to integrate multiple modules ✅ How to handle errors at each step ✅ How to report comprehensive results ✅ How to use try/finally for cleanup The complete workflow: 1. Find files (filesystem) 2. Parse data (regex) 3. Connect to database (db_utils) 4. Create containers (get_or_create_subtopic) 5. Insert data (insert_chapter_with_content) 6. Report results (logging) This is the pattern for ALL data import/rebuild scripts! ================================================================================ NEXT STEPS: ================================================================================ To use this script in production: 1. Copy to your project: cp rebuild_typescript_course.py /var/www/myapp/ 2. Ensure .env exists with credentials 3. Ensure chapter files exist at: /var/www/myapp/courses/Programming/TypeScript/html/ts1-*.html 4. Run it: python rebuild_typescript_course.py 5. Verify in database: SELECT COUNT(*) FROM pages WHERE subtopic_id = 8; You now have a complete, production-ready rebuild script! ================================================================================