Spaces:
Sleeping
Sleeping
| """ | |
| Application configuration classes for different environments. | |
| Uses environment variables with sensible defaults. | |
| """ | |
| import os | |
| from pathlib import Path | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| # app/config/settings.py -> parent (config) -> parent (app) -> parent (project root) | |
| BASE_DIR = Path(__file__).resolve().parent.parent.parent | |
| class BaseConfig: | |
| """Base configuration shared across all environments.""" | |
| # Flask | |
| SECRET_KEY: str = os.getenv("SECRET_KEY", "change-me-in-production-32-chars!!") | |
| DEBUG: bool = False | |
| TESTING: bool = False | |
| # SQLAlchemy | |
| SQLALCHEMY_DATABASE_URI: str = os.getenv( | |
| "DATABASE_URL", f"sqlite:///{BASE_DIR / 'database' / 'scraper.db'}" | |
| ) | |
| SQLALCHEMY_TRACK_MODIFICATIONS: bool = False | |
| SQLALCHEMY_ENGINE_OPTIONS: dict = { | |
| "pool_pre_ping": True, | |
| "pool_recycle": 300, | |
| } | |
| # CSRF | |
| WTF_CSRF_ENABLED: bool = os.getenv("WTF_CSRF_ENABLED", "True") == "True" | |
| WTF_CSRF_TIME_LIMIT: int = 3600 | |
| # Session | |
| SESSION_COOKIE_SECURE: bool = os.getenv("SESSION_COOKIE_SECURE", "False") == "True" | |
| SESSION_COOKIE_HTTPONLY: bool = True | |
| SESSION_COOKIE_SAMESITE: str = "Lax" | |
| PERMANENT_SESSION_LIFETIME: int = 86400 | |
| # Rate limiting | |
| RATELIMIT_DEFAULT: str = os.getenv("RATELIMIT_DEFAULT", "200 per hour") | |
| RATELIMIT_STORAGE_URL: str = os.getenv("RATELIMIT_STORAGE_URL", "memory://") | |
| RATELIMIT_HEADERS_ENABLED: bool = True | |
| # Scraping engine | |
| MAX_CONCURRENT_JOBS: int = int(os.getenv("MAX_CONCURRENT_JOBS", "5")) | |
| REQUEST_TIMEOUT: int = int(os.getenv("REQUEST_TIMEOUT", "30")) | |
| MAX_RETRIES: int = int(os.getenv("MAX_RETRIES", "3")) | |
| DEFAULT_DELAY: float = float(os.getenv("DEFAULT_DELAY", "1.0")) | |
| MAX_PAGES: int = int(os.getenv("MAX_PAGES", "50")) | |
| # Directories | |
| EXPORT_DIR: Path = BASE_DIR / os.getenv("EXPORT_DIR", "exports") | |
| LOG_DIR: Path = BASE_DIR / os.getenv("LOG_DIR", "logs") | |
| # Logging | |
| LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") | |
| LOG_FORMAT: str = "%(asctime)s [%(levelname)s] %(name)s: %(message)s" | |
| def init_app(cls, app) -> None: | |
| """Hook for environment-specific initialization.""" | |
| # Ensure required directories exist | |
| cls.EXPORT_DIR.mkdir(parents=True, exist_ok=True) | |
| cls.LOG_DIR.mkdir(parents=True, exist_ok=True) | |
| (BASE_DIR / "database").mkdir(parents=True, exist_ok=True) | |
| class DevelopmentConfig(BaseConfig): | |
| DEBUG: bool = True | |
| LOG_LEVEL: str = "DEBUG" | |
| SESSION_COOKIE_SECURE: bool = False | |
| class ProductionConfig(BaseConfig): | |
| DEBUG: bool = False | |
| SESSION_COOKIE_SECURE: bool = True | |
| LOG_LEVEL: str = "WARNING" | |
| SQLALCHEMY_ENGINE_OPTIONS: dict = { | |
| "pool_pre_ping": True, | |
| "pool_recycle": 300, | |
| "pool_size": 10, | |
| "max_overflow": 20, | |
| } | |
| class TestingConfig(BaseConfig): | |
| TESTING: bool = True | |
| DEBUG: bool = True | |
| WTF_CSRF_ENABLED: bool = False | |
| SQLALCHEMY_DATABASE_URI: str = "sqlite:///:memory:" | |
| config_map = { | |
| "development": DevelopmentConfig, | |
| "production": ProductionConfig, | |
| "testing": TestingConfig, | |
| "default": DevelopmentConfig, | |
| } | |
| def get_config() -> type: | |
| env = os.getenv("FLASK_ENV", "development").lower() | |
| return config_map.get(env, DevelopmentConfig) | |