"""
Configuration module for APIFromAnything.
This module provides configuration classes and utilities for different environments.
"""
import enum
import logging
import logging.config
import os
from typing import Any, Dict, List, Optional, Type, Union
from apifrom.logging_utils import configure_logging_dict, setup_sentry
class Environment(enum.Enum):
"""Environment types for the application."""
DEVELOPMENT = "development"
TESTING = "testing"
STAGING = "staging"
PRODUCTION = "production"
[docs]
class BaseConfig:
"""Base configuration class with common settings."""
# Application settings
APP_NAME = "APIFromAnything"
VERSION = "1.0.0"
DEBUG = False
# Server settings
HOST = "127.0.0.1"
PORT = 8000
WORKERS = 1
RELOAD = False
# Security settings
SECRET_KEY = "insecure-secret-key-change-in-production"
ALLOWED_HOSTS = ["*"]
CORS_ORIGINS = ["*"]
HTTPS_ENABLED = False
CSRF_PROTECTION = False
RATE_LIMITING_ENABLED = False
RATE_LIMIT = "100/minute"
# Database settings
DATABASE_URL = "sqlite:///./app.db"
DB_POOL_SIZE = 5
DB_MAX_OVERFLOW = 10
DB_TIMEOUT = 30
# Cache settings
CACHE_URL = "memory://"
CACHE_TTL = 300 # seconds
# Logging settings
LOG_LEVEL = "INFO"
LOG_FORMAT = "simple" # "simple" or "structured"
LOG_FILE = None
# Monitoring settings
METRICS_ENABLED = False
METRICS_PORT = 9090
# Health check settings
HEALTH_CHECK_PATH = "/health"
DETAILED_HEALTH_CHECK_PATH = "/health/detailed"
# Middleware settings
MIDDLEWARE = [
"apifrom.middleware.logging.LoggingMiddleware",
"apifrom.middleware.cors.CORSMiddleware",
]
# External services
SENTRY_DSN = None
class DevelopmentConfig(BaseConfig):
"""Development environment configuration."""
DEBUG = True
RELOAD = True
LOG_LEVEL = "DEBUG"
METRICS_ENABLED = True
class TestingConfig(BaseConfig):
"""Testing environment configuration."""
DEBUG = True
DATABASE_URL = "sqlite:///./test.db"
LOG_LEVEL = "DEBUG"
LOG_FILE = None
METRICS_ENABLED = False
class StagingConfig(BaseConfig):
"""Staging environment configuration."""
HOST = "0.0.0.0"
WORKERS = 2
HTTPS_ENABLED = True
CORS_ORIGINS = ["https://staging.example.com"]
ALLOWED_HOSTS = ["staging.example.com", "api.staging.example.com"]
LOG_FORMAT = "structured"
LOG_FILE = "/var/log/apifrom/app.log"
METRICS_ENABLED = True
RATE_LIMITING_ENABLED = True
# Additional middleware for staging
MIDDLEWARE = BaseConfig.MIDDLEWARE + [
"apifrom.middleware.security.SecurityMiddleware",
]
class ProductionConfig(BaseConfig):
"""Production environment configuration."""
HOST = "0.0.0.0"
WORKERS = 4
HTTPS_ENABLED = True
CORS_ORIGINS = ["https://example.com"]
ALLOWED_HOSTS = ["example.com", "api.example.com"]
CSRF_PROTECTION = True
RATE_LIMITING_ENABLED = True
LOG_FORMAT = "structured"
LOG_FILE = "/var/log/apifrom/app.log"
METRICS_ENABLED = True
# Additional middleware for production
MIDDLEWARE = BaseConfig.MIDDLEWARE + [
"apifrom.middleware.security.SecurityMiddleware",
"apifrom.middleware.rate_limiting.RateLimitingMiddleware",
]
# Map environment types to configuration classes
CONFIG_MAPPING = {
Environment.DEVELOPMENT: DevelopmentConfig,
Environment.TESTING: TestingConfig,
Environment.STAGING: StagingConfig,
Environment.PRODUCTION: ProductionConfig,
}
[docs]
def get_config() -> BaseConfig:
"""
Get the configuration for the current environment.
Returns:
The configuration instance for the current environment.
"""
# Get environment from environment variable
env_name = os.getenv("ENVIRONMENT", "development").lower()
try:
env = Environment(env_name)
except ValueError:
logging.warning(f"Invalid environment: {env_name}. Using development.")
env = Environment.DEVELOPMENT
# Get configuration class for the environment
config_class = CONFIG_MAPPING[env]
# Create configuration instance
config = config_class()
# Override configuration from environment variables
for key in dir(config):
if key.isupper():
env_value = os.getenv(key)
if env_value is not None:
# Convert environment variable to the appropriate type
attr_value = getattr(config, key)
if isinstance(attr_value, bool):
setattr(config, key, env_value.lower() in ("true", "1", "yes"))
elif isinstance(attr_value, int):
setattr(config, key, int(env_value))
elif isinstance(attr_value, float):
setattr(config, key, float(env_value))
elif isinstance(attr_value, list):
setattr(config, key, env_value.split(","))
else:
setattr(config, key, env_value)
return config