Configuration Management

Gmail Cleanup โ€” Practical Scripting
Course 1 ยท Chapter 2 ยท Configuration Management

๐Ÿ”ง Configuration Management

Configuration should never be hardcoded! This chapter teaches you how to load settings from environment variables using .env files, validate them, and handle errors gracefully. This is a critical skill for secure, portable applications.

๐Ÿ“‹ Why Configuration Management Matters

Consider this dangerous code:

# โŒ BAD: Hardcoded credentials!
GMAIL_USER = "my-email@gmail.com"
API_TIMEOUT = 10

Problems:

  • Email is visible in the code
  • Can't change settings without editing the code
  • Different values needed for development vs. production
  • Easy to accidentally commit secrets to Git

The solution: .env files + load_dotenv()

๐Ÿ” The .env Pattern

Create a config.py module:

import os
from pathlib import Path
from dotenv import load_dotenv

# Load .env file from same directory as this script
ENV_FILE = Path(__file__).parent / ".env"
load_dotenv(ENV_FILE)

class Config:
    """Application configuration."""

    def __init__(self):
        # Gmail settings
        self.gmail_user = os.environ.get('GMAIL_USER')
        self.api_timeout = int(os.environ.get('API_REQUEST_TIMEOUT', '10'))
        self.max_results = int(os.environ.get('MAX_RESULTS', '100'))

        # Cleanup settings
        self.days_old = int(os.environ.get('DELETE_OLDER_THAN_DAYS', '365'))
        self.min_attachment_mb = int(os.environ.get('MIN_ATTACHMENT_SIZE_MB', '10'))

    def validate(self) -> bool:
        """Validate required configuration."""
        if not self.gmail_user:
            print("โŒ Missing GMAIL_USER in .env")
            return False

        if '@' not in self.gmail_user:
            print("โŒ GMAIL_USER must be a valid email")
            return False

        return True

๐Ÿ“ Using Configuration in Your Script

from config import Config

def main():
    # Load configuration
    config = Config()

    # Validate it
    if not config.validate():
        return False

    # Use it
    print(f"Cleaning emails from: {config.gmail_user}")
    print(f"Deleting emails older than: {config.days_old} days")

    return True

if __name__ == "__main__":
    main()

โš ๏ธ Common Configuration Errors

Error 1: .env file not found

Cause: File is in wrong directory or has wrong name

Fix: Make sure .env is in the same folder as config.py

Error 2: Variables are None

Cause: Variable name in code doesn't match .env

Fix: Case matters! Use exact same names

Error 3: Type conversion errors

Cause: Trying to convert non-numeric value to int

Fix: Validate that .env values are correct type

๐Ÿ’ป Coding Challenges

Challenge 1: Create config.py

Build a Config class that:

  1. Loads .env file from current directory
  2. Reads GMAIL_USER, API_REQUEST_TIMEOUT, MAX_RESULTS
  3. Uses defaults for timeout (10) and max_results (100)
  4. Returns all values

Goal: Create reusable configuration module.

โ†’ Solution

Challenge 2: Configuration Validation

Extend Config.validate() to check:

  1. GMAIL_USER is not empty
  2. GMAIL_USER contains @ symbol (valid email)
  3. API_REQUEST_TIMEOUT is positive number
  4. Return True if all valid, False otherwise

Goal: Practice data validation.

โ†’ Solution

Challenge 3: Error Handling & Logging

Enhance config loading with error handling:

  1. Catch missing .env file gracefully
  2. Handle type conversion errors
  3. Print helpful error messages (what's wrong, how to fix)
  4. Test with missing/invalid values

Goal: Build robust configuration system.

โ†’ Solution