# app_environment.py - Production-grade environment configuration """ Production environment configuration for OmniBiMol Streamlit app. Provides clean environment handling to separate development/debug output from production-ready user-facing UI. Usage: from app_environment import AppEnvironment env = AppEnvironment() if env.is_development(): # Show debug UI elements if env.should_show_backend_status(): render_backend_status_badge() """ import os import logging from typing import Optional logger = logging.getLogger(__name__) class AppEnvironment: """ Manages application environment configuration. Separates development/debug UI from production user-facing UI. """ # Environment modes DEVELOPMENT = "development" PRODUCTION = "production" def __init__(self): """Initialize environment configuration from APP_ENV variable.""" # Default to production for safety self.env = os.getenv("APP_ENV", self.PRODUCTION).strip().lower() # Validate environment if self.env not in {self.DEVELOPMENT, self.PRODUCTION}: logger.warning( f"Invalid APP_ENV='{self.env}'. Valid values: " f"'{self.DEVELOPMENT}', '{self.PRODUCTION}'. Defaulting to '{self.PRODUCTION}'." ) self.env = self.PRODUCTION logger.info(f"OmniBiMol running in {self.env} mode") def is_development(self) -> bool: """Check if running in development mode.""" return self.env == self.DEVELOPMENT def is_production(self) -> bool: """Check if running in production mode.""" return self.env == self.PRODUCTION def should_show_backend_status(self) -> bool: """ Determine if backend status badge should be shown. Returns: True in development mode, False in production. """ return self.is_development() def should_show_debug_ui(self) -> bool: """ Determine if debug/development UI elements should be visible. Includes: - Backend routing details - Environment labels - Debug status indicators - Internal error details Returns: True in development mode, False in production. """ return self.is_development() def should_expose_errors(self) -> bool: """ Determine if raw errors should be exposed in UI. Returns: True in development mode, False in production (user-friendly messages only). """ return self.is_development() def get_user_message(self, internal_error: Optional[str] = None) -> str: """ Get user-friendly message, hiding internal details in production. Args: internal_error: The actual error for logging purposes Returns: Production: Generic user message Development: Full error details """ if self.is_production(): return "Processing request... Some data could not be loaded. Results may be partial." else: return internal_error or "An error occurred." def log_debug(self, message: str, **kwargs) -> None: """Log debug message (visible in logs, not UI).""" logger.debug(message, extra=kwargs) def log_info(self, message: str, **kwargs) -> None: """Log info message.""" logger.info(message, extra=kwargs) def log_error(self, message: str, **kwargs) -> None: """Log error message.""" logger.error(message, extra=kwargs) # Global singleton instance _app_environment: Optional[AppEnvironment] = None def get_environment() -> AppEnvironment: """ Get or create the global app environment instance. Returns: AppEnvironment singleton """ global _app_environment if _app_environment is None: _app_environment = AppEnvironment() return _app_environment