================================================================================ CRUNCHYROLL DOWNLOADER - CHALLENGE 2 SOLUTION Chapter 2: Configuration Management Challenge: Validation ================================================================================ PROBLEM: Extend Config to validate email format and required fields. SOLUTION: ================================================================================ File: config.py (updated with validation) import os import re from pathlib import Path from dotenv import load_dotenv ENV_FILE = Path(__file__).parent / ".env" load_dotenv(ENV_FILE) class Config: """Crunchyroll configuration with validation.""" def __init__(self): self.email = os.environ.get('CRUNCHYROLL_EMAIL') self.password = os.environ.get('CRUNCHYROLL_PASSWORD') self.api_base = os.environ.get('API_BASE_URL', 'https://api.crunchyroll.com') self.token_cache = os.environ.get('TOKEN_CACHE_FILE', 'token_cache.json') def validate(self) -> bool: """Validate all configuration values.""" # Check email is not empty if not self.email: print("❌ CRUNCHYROLL_EMAIL is empty!") print(" Fix: Add CRUNCHYROLL_EMAIL=your-email@example.com to .env") return False # Check email is not whitespace if not self.email.strip(): print("❌ CRUNCHYROLL_EMAIL is just whitespace!") return False # Validate email format email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' if not re.match(email_pattern, self.email): print(f"❌ CRUNCHYROLL_EMAIL '{self.email}' is not valid!") print(" Expected format: user@example.com") return False # Check password is not empty if not self.password: print("❌ CRUNCHYROLL_PASSWORD is empty!") print(" Fix: Add CRUNCHYROLL_PASSWORD=your-password to .env") return False if not self.password.strip(): print("❌ CRUNCHYROLL_PASSWORD is just whitespace!") return False # Check password minimum length if len(self.password) < 6: print("❌ CRUNCHYROLL_PASSWORD is too short (minimum 6 characters)") return False # Check API base URL format if not self.api_base.startswith('http'): print(f"❌ API_BASE_URL '{self.api_base}' must start with http or https") return False print("✅ Configuration is valid!") return True if __name__ == "__main__": config = Config() if config.validate(): print("Ready to use!") else: print("Configuration has errors") TESTING DIFFERENT SCENARIOS ================================================================================ Test 1: Valid config .env: CRUNCHYROLL_EMAIL=user@gmail.com CRUNCHYROLL_PASSWORD=mypassword123 Result: ✅ Configuration is valid! Test 2: Missing email .env: CRUNCHYROLL_EMAIL= CRUNCHYROLL_PASSWORD=mypassword123 Result: ❌ CRUNCHYROLL_EMAIL is empty! Test 3: Invalid email format .env: CRUNCHYROLL_EMAIL=notanemail CRUNCHYROLL_PASSWORD=mypassword123 Result: ❌ CRUNCHYROLL_EMAIL 'notanemail' is not valid! Test 4: Password too short .env: CRUNCHYROLL_EMAIL=user@gmail.com CRUNCHYROLL_PASSWORD=123 Result: ❌ CRUNCHYROLL_PASSWORD is too short (minimum 6 characters) VALIDATION CHECKLIST ================================================================================ ✅ Email not empty ✅ Email is not just whitespace ✅ Email format is valid (has @ and domain) ✅ Password not empty ✅ Password not just whitespace ✅ Password minimum 6 characters ✅ API URL starts with http or https ================================================================================