A flexible Python package for retrieving environment variables from multiple sources including local environment and AWS Secrets Manager.
- Multiple Sources: Support for local environment variables and AWS Secrets Manager
- Type Safety: Full type hints and robust error handling
- Flexible Usage: Factory pattern and convenience functions for easy integration
- Case-Insensitive Matching: Fallback to case-insensitive key matching for AWS secrets
- Comprehensive Logging: Debug and warning logs for troubleshooting
- Error Recovery: Continues processing even if some keys are missing
pip install env-factory
To automatically load your .env
file, add this to the top of your main script:
from dotenv import load_dotenv
load_dotenv() # This loads variables from .env file
# Now you can use env_factory
from env_factory import get_env_variables
Create a .env
file in your project root directory:
# .env file - Place in your project root
API_KEY=my-secret-api-key
DATABASE_URL=postgresql://localhost:5432/myapp
DEBUG=true
# For AWS functionality (REQUIRED)
AWS_ACCOUNT_ID=123456789012
from env_factory import get_env_variables
# This will read from your .env file
config = get_env_variables(['API_KEY', 'DATABASE_URL'])
print(config)
# Output: {'API_KEY': 'my-secret-api-key', 'DATABASE_URL': 'postgresql://localhost:5432/myapp'}
# Check if variables exist
api_key = config.get('API_KEY')
if api_key:
print(f"API Key found: {api_key}")
else:
print("API Key not found!")
from env_factory import get_env_variables
# Make sure AWS_ACCOUNT_ID is in your .env file!
secrets = get_env_variables(
keys=['DB_PASSWORD', 'JWT_SECRET'],
source='aws',
secret_name='my-app-secrets',
region='us-east-1',
role_name='my-app-role'
)
print(f"Database password: {secrets.get('DB_PASSWORD')}")
from env_factory import get_env_variables
# Load all your app configuration at startup
app_config = get_env_variables([
'API_KEY',
'DATABASE_URL',
'DEBUG',
'PORT'
])
# Use the configuration
api_key = app_config['API_KEY']
database_url = app_config['DATABASE_URL']
debug_mode = app_config.get('DEBUG', 'false').lower() == 'true'
port = int(app_config.get('PORT', '8000'))
print(f"Starting app on port {port}, debug mode: {debug_mode}")
Here's a complete example showing how to use the package:
# main.py
from dotenv import load_dotenv
from env_factory import get_env_variables
# Step 1: Load .env file (MANDATORY)
load_dotenv()
# Step 2: Get your environment variables
config = get_env_variables(['API_KEY', 'DATABASE_URL', 'DEBUG'])
# Step 3: Use the configuration
api_key = config.get('API_KEY')
if not api_key:
raise ValueError("API_KEY is required but not found in .env file")
database_url = config.get('DATABASE_URL', 'sqlite:///default.db')
debug = config.get('DEBUG', 'false').lower() == 'true'
print(f"API Key: {api_key}")
print(f"Database: {database_url}")
print(f"Debug mode: {debug}")
Your .env
file should look like:
# .env
API_KEY=sk-1234567890abcdef
DATABASE_URL=postgresql://user:pass@localhost/mydb
DEBUG=true
# aws_example.py
from dotenv import load_dotenv
from env_factory import get_env_variables
# Load .env file (contains AWS_ACCOUNT_ID)
load_dotenv()
try:
# Get secrets from AWS
secrets = get_env_variables(
keys=['DB_PASSWORD', 'JWT_SECRET'],
source='aws',
secret_name='production-secrets',
region='us-east-1',
role_name='app-secrets-role'
)
print("âś… Successfully retrieved AWS secrets!")
print(f"DB Password exists: {'DB_PASSWORD' in secrets}")
except Exception as e:
print(f"❌ Error: {e}")
Your .env
file must include:
# .env - MANDATORY for AWS
AWS_ACCOUNT_ID=123456789012
from dotenv import load_dotenv
from env_factory import get_env_variables, ConfigurationError
load_dotenv()
try:
config = get_env_variables(['REQUIRED_API_KEY'])
api_key = config.get('REQUIRED_API_KEY')
if not api_key:
print("⚠️ Warning: REQUIRED_API_KEY not found in .env file")
print("Please add it to your .env file: REQUIRED_API_KEY=your-key-here")
else:
print("âś… API key loaded successfully!")
except ConfigurationError as e:
print(f"❌ Configuration error: {e}")
``` with Classes
```python
from env_factory import LocalEnvRetrieval, AWSEnvRetrieval
# Local environment retrieval
local_retriever = LocalEnvRetrieval()
local_vars = local_retriever.get_env_variables(['API_KEY', 'DEBUG_MODE'])
# AWS Secrets Manager retrieval
aws_retriever = AWSEnvRetrieval(
secret_name='production-secrets',
region='us-west-2',
role_name='app-secrets-role'
)
aws_vars = aws_retriever.get_env_variables(['DB_PASSWORD', 'JWT_SECRET'])
from env_factory import EnvFactory
# Create retrievers using factory
local_retriever = EnvFactory.create_local_retriever()
aws_retriever = EnvFactory.create_aws_retriever(
secret_name='my-secrets',
region='eu-west-1',
role_name='secrets-access-role'
)
# Use the retrievers
config = local_retriever.get_env_variables(['PORT', 'HOST'])
secrets = aws_retriever.get_env_variables(['API_TOKEN', 'WEBHOOK_SECRET'])
IMPORTANT: You must store your environment variables in a .env
file in your project root. This is mandatory for the package to work properly.
Create a .env
file in your project root:
# .env file
API_KEY=your-local-api-key
DATABASE_URL=postgresql://localhost:5432/mydb
DEBUG=true
PORT=8000
MANDATORY: Your .env
file must include the AWS Account ID:
# .env file - REQUIRED for AWS functionality
AWS_ACCOUNT_ID=123456789012
ENVIRONMENT=production
Before using AWS functionality, ensure you have:
- AWS Account ID in .env: The
AWS_ACCOUNT_ID
must be set in your.env
file (mandatory) - AWS Credentials: Configure AWS credentials (via AWS CLI, IAM roles, or environment variables)
- IAM Permissions: Ensure your IAM role has access to the specified secrets
Required IAM permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"sts:AssumeRole"
],
"Resource": "*"
}
]
}
from env_factory import get_env_variables, ConfigurationError, SecretRetrievalError
try:
variables = get_env_variables(
keys=['API_KEY', 'SECRET_TOKEN'],
source='aws',
secret_name='app-secrets',
region='us-east-1',
role_name='secrets-role'
)
except ConfigurationError as e:
print(f"Configuration error: {e}")
except SecretRetrievalError as e:
print(f"Failed to retrieve secrets: {e}")
from env_factory import EnvRetrieval
from typing import Dict, List, Optional
class CustomEnvRetrieval(EnvRetrieval):
"""Custom environment retrieval implementation"""
def __init__(self, config_file: str):
self.config_file = config_file
def get_env_variables(self, keys: List[str]) -> Dict[str, Optional[str]]:
# Your custom implementation here
pass
import logging
# Configure logging to see debug information
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('env_factory')
# Now you'll see debug logs when retrieving variables
variables = get_env_variables(['API_KEY'], source='local')
Base class for all environment retrieval implementations.
Methods:
get_env_variables(keys: List[str]) -> Dict[str, Optional[str]]
: Abstract method to retrieve environment variables
Retrieves environment variables from the local system environment.
Methods:
get_env_variables(keys: List[str]) -> Dict[str, Optional[str]]
: Get variables from local environment
Retrieves environment variables from AWS Secrets Manager.
Constructor:
__init__(secret_name: str, region: str, role_name: str)
Methods:
get_env_variables(keys: List[str]) -> Dict[str, Optional[str]]
: Get variables from AWS Secrets Manager
Factory class for creating environment retrieval instances.
Static Methods:
create_local_retriever() -> LocalEnvRetrieval
: Create local retrievercreate_aws_retriever(secret_name: str, region: str, role_name: str) -> AWSEnvRetrieval
: Create AWS retriever
Convenience function for retrieving environment variables.
Parameters:
keys: List[str]
- List of environment variable names to retrievesource: str = "local"
- Environment source ('local' or 'aws')**kwargs
- Additional arguments for AWS (secret_name, region, role_name)
Returns:
Dict[str, Optional[str]]
- Dictionary mapping keys to their values
Base exception for the env_factory package.
Raised when configuration parameters are invalid.
Raised when secret retrieval from AWS fails.
from env_factory import get_env_variables
# Load configuration for a web application
config = get_env_variables([
'DATABASE_URL',
'SECRET_KEY',
'DEBUG',
'PORT',
'REDIS_URL'
])
# Handle missing variables
database_url = config.get('DATABASE_URL')
if not database_url:
raise ValueError("DATABASE_URL is required")
debug_mode = config.get('DEBUG', 'false').lower() == 'true'
port = int(config.get('PORT', '8000'))
import os
from env_factory import get_env_variables
# Determine environment
environment = os.getenv('ENVIRONMENT', 'development')
if environment == 'production':
# Use AWS Secrets Manager in production
config = get_env_variables(
keys=['DATABASE_PASSWORD', 'API_KEY', 'JWT_SECRET'],
source='aws',
secret_name='prod-app-secrets',
region='us-east-1',
role_name='prod-secrets-role'
)
else:
# Use local environment variables in development
config = get_env_variables([
'DATABASE_PASSWORD',
'API_KEY',
'JWT_SECRET'
])
print(f"Loaded {len([v for v in config.values() if v is not None])} variables")
from env_factory import EnvFactory
# Create retrievers
local_retriever = EnvFactory.create_local_retriever()
aws_retriever = EnvFactory.create_aws_retriever(
secret_name='shared-secrets',
region='us-west-2',
role_name='batch-processing-role'
)
# Get different types of configuration
app_config = local_retriever.get_env_variables([
'LOG_LEVEL',
'BATCH_SIZE',
'WORKER_COUNT'
])
sensitive_config = aws_retriever.get_env_variables([
'DATABASE_PASSWORD',
'API_TOKEN',
'ENCRYPTION_KEY'
])
# Merge configurations
full_config = {**app_config, **sensitive_config}
- Always use .env files: Store all environment variables in a
.env
file in your project root (mandatory) - Load .env at startup: Use
python-dotenv
to load your.env
file before using env_factory - AWS Account ID: Always include
AWS_ACCOUNT_ID
in your.env
file when using AWS functionality - Environment-Specific Sources: Use local environment variables for development and AWS Secrets Manager for production
- Error Handling: Always handle
ConfigurationError
andSecretRetrievalError
exceptions - Key Validation: Check if required environment variables are present and not None
- Security: Never commit your
.env
file to version control (add it to.gitignore
)
# .gitignore
.env
.env.local
.env.production
*.env
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Initial release
- Support for local environment variables
- Support for AWS Secrets Manager
- Factory pattern implementation
- Comprehensive error handling
- Type hints and documentation