skills/python-configuration/SKILL.md
Python configuration management via environment variables and typed settings. Use when externalizing config, setting up pydantic-settings, managing secrets, or implementing environment-specific behavior.
npx skillsauth add julianobarbosa/claude-code-skills python-configurationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Externalize configuration from code using environment variables and typed settings. Well-managed configuration enables the same code to run in any environment without modification.
All environment-specific values (URLs, secrets, feature flags) come from environment variables, not code.
Parse and validate configuration into typed objects at startup, not scattered throughout code.
Validate all required configuration at application boot. Missing config should crash immediately with a clear message.
Provide reasonable defaults for local development while requiring explicit values for sensitive settings.
from pydantic_settings import BaseSettings
from pydantic import Field
class Settings(BaseSettings):
database_url: str = Field(alias="DATABASE_URL")
api_key: str = Field(alias="API_KEY")
debug: bool = Field(default=False, alias="DEBUG")
settings = Settings() # Loads from environment
Create a central settings class that loads and validates all configuration.
from pydantic_settings import BaseSettings
from pydantic import Field, PostgresDsn, ValidationError
import sys
class Settings(BaseSettings):
"""Application configuration loaded from environment variables."""
# Database
db_host: str = Field(alias="DB_HOST")
db_port: int = Field(default=5432, alias="DB_PORT")
db_name: str = Field(alias="DB_NAME")
db_user: str = Field(alias="DB_USER")
db_password: str = Field(alias="DB_PASSWORD")
# Redis
redis_url: str = Field(default="redis://localhost:6379", alias="REDIS_URL")
# API Keys
api_secret_key: str = Field(alias="API_SECRET_KEY")
# Feature flags
enable_new_feature: bool = Field(default=False, alias="ENABLE_NEW_FEATURE")
model_config = {
"env_file": ".env",
"env_file_encoding": "utf-8",
}
# Create singleton instance at module load
try:
settings = Settings()
except ValidationError as e:
print(f"Configuration error:\n{e}")
sys.exit(1)
Import settings throughout your application:
from myapp.config import settings
def get_database_connection():
return connect(
host=settings.db_host,
port=settings.db_port,
database=settings.db_name,
)
Required settings should crash the application immediately with a clear error.
from pydantic_settings import BaseSettings
from pydantic import Field, ValidationError
import sys
class Settings(BaseSettings):
# Required - no default means it must be set
api_key: str = Field(alias="API_KEY")
database_url: str = Field(alias="DATABASE_URL")
# Optional with defaults
log_level: str = Field(default="INFO", alias="LOG_LEVEL")
try:
settings = Settings()
except ValidationError as e:
print("=" * 60)
print("CONFIGURATION ERROR")
print("=" * 60)
for error in e.errors():
field = error["loc"][0]
print(f" - {field}: {error['msg']}")
print("\nPlease set the required environment variables.")
sys.exit(1)
A clear error at startup is better than a cryptic None failure mid-request.
Provide sensible defaults for local development while requiring explicit values for secrets.
class Settings(BaseSettings):
# Has local default, but prod will override
db_host: str = Field(default="localhost", alias="DB_HOST")
db_port: int = Field(default=5432, alias="DB_PORT")
# Always required - no default for secrets
db_password: str = Field(alias="DB_PASSWORD")
api_secret_key: str = Field(alias="API_SECRET_KEY")
# Development convenience
debug: bool = Field(default=False, alias="DEBUG")
model_config = {"env_file": ".env"}
Create a .env file for local development (never commit this):
# .env (add to .gitignore)
DB_PASSWORD=local_dev_password
API_SECRET_KEY=dev-secret-key
DEBUG=true
Prefix related variables for clarity and easy debugging.
# Database configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_USER=admin
DB_PASSWORD=secret
# Redis configuration
REDIS_URL=redis://localhost:6379
REDIS_MAX_CONNECTIONS=10
# Authentication
AUTH_SECRET_KEY=your-secret-key
AUTH_TOKEN_EXPIRY_SECONDS=3600
AUTH_ALGORITHM=HS256
# Feature flags
FEATURE_NEW_CHECKOUT=true
FEATURE_BETA_UI=false
Makes env | grep DB_ useful for debugging.
Pydantic handles common conversions automatically.
from pydantic_settings import BaseSettings
from pydantic import Field, field_validator
class Settings(BaseSettings):
# Automatically converts "true", "1", "yes" to True
debug: bool = False
# Automatically converts string to int
max_connections: int = 100
# Parse comma-separated string to list
allowed_hosts: list[str] = Field(default_factory=list)
@field_validator("allowed_hosts", mode="before")
@classmethod
def parse_allowed_hosts(cls, v: str | list[str]) -> list[str]:
if isinstance(v, str):
return [host.strip() for host in v.split(",") if host.strip()]
return v
Usage:
ALLOWED_HOSTS=example.com,api.example.com,localhost
MAX_CONNECTIONS=50
DEBUG=true
Use an environment enum to switch behavior.
from enum import Enum
from pydantic_settings import BaseSettings
from pydantic import Field, computed_field
class Environment(str, Enum):
LOCAL = "local"
STAGING = "staging"
PRODUCTION = "production"
class Settings(BaseSettings):
environment: Environment = Field(
default=Environment.LOCAL,
alias="ENVIRONMENT",
)
# Settings that vary by environment
log_level: str = Field(default="DEBUG", alias="LOG_LEVEL")
@computed_field
@property
def is_production(self) -> bool:
return self.environment == Environment.PRODUCTION
@computed_field
@property
def is_local(self) -> bool:
return self.environment == Environment.LOCAL
# Usage
if settings.is_production:
configure_production_logging()
else:
configure_debug_logging()
Organize related settings into nested models.
from pydantic import BaseModel
from pydantic_settings import BaseSettings
class DatabaseSettings(BaseModel):
host: str = "localhost"
port: int = 5432
name: str
user: str
password: str
class RedisSettings(BaseModel):
url: str = "redis://localhost:6379"
max_connections: int = 10
class Settings(BaseSettings):
database: DatabaseSettings
redis: RedisSettings
debug: bool = False
model_config = {
"env_nested_delimiter": "__",
"env_file": ".env",
}
Environment variables use double underscore for nesting:
DATABASE__HOST=db.example.com
DATABASE__PORT=5432
DATABASE__NAME=myapp
DATABASE__USER=admin
DATABASE__PASSWORD=secret
REDIS__URL=redis://redis.example.com:6379
For container environments, read secrets from mounted files.
from pydantic_settings import BaseSettings
from pydantic import Field
from pathlib import Path
class Settings(BaseSettings):
# Read from environment variable or file
db_password: str = Field(alias="DB_PASSWORD")
model_config = {
"secrets_dir": "/run/secrets", # Docker secrets location
}
Pydantic will look for /run/secrets/db_password if the env var isn't set.
Add custom validation for complex requirements.
from pydantic_settings import BaseSettings
from pydantic import Field, model_validator
class Settings(BaseSettings):
db_host: str = Field(alias="DB_HOST")
db_port: int = Field(alias="DB_PORT")
read_replica_host: str | None = Field(default=None, alias="READ_REPLICA_HOST")
read_replica_port: int = Field(default=5432, alias="READ_REPLICA_PORT")
@model_validator(mode="after")
def validate_replica_settings(self):
if self.read_replica_host and self.read_replica_port == self.db_port:
if self.read_replica_host == self.db_host:
raise ValueError(
"Read replica cannot be the same as primary database"
)
return self
.env files (gitignored) or secret managersDB_HOST, REDIS_URL for clarityos.getenv() throughout codepydantic-settings reads env at class IMPORT, not at instantiation — tests that monkeypatch env after import see cached values. Reload the module or instantiate before patching.env_nested_delimiter explicitly set — without it, DB_HOST and DB_PORT don't auto-bind to Settings.db.host.SecretStr redacts in __repr__ but NOT in __str__ — print(secret) leaks; f"{secret}" leaks; only repr(secret) redacts..env file precedence vs process env: pydantic-settings reads .env FIRST then overlays process env. A CI secret in process env wins over a developer's .env — but stale .env values stick if process env is missing the key.Field(env=...) vs model_config = SettingsConfigDict(...). Mixing breaks silently in some paths.testing
Brief description of what this skill does. Include specific triggers - when should Claude use this skill? Example triggers, file types, or keywords that indicate this skill applies.
tools
Manage and troubleshoot PATH configuration in zsh. Use when adding tools to PATH (bun, nvm, Python venv, cargo, go), diagnosing "command not found" errors, validating PATH entries, or organizing shell configuration in .zshrc and .zshrc.local files.
tools
Zabbix monitoring system automation via API and Python. Use when: (1) Managing hosts, templates, items, triggers, or host groups, (2) Automating monitoring configuration, (3) Sending data via Zabbix trapper/sender, (4) Querying historical data or events, (5) Bulk operations on Zabbix objects, (6) Maintenance window management, (7) User/permission management
development
Operate YouTube Music via natural language. Search songs, artists, albums, playlists, lyrics, charts, recommendations, and control playback. Browse personal library, manage playlists, rate tracks, and inspect account info. Use this skill whenever the user asks about YouTube Music, wants to play music, manage playlists, search by song or artist name, inspect lyrics, or control playback.