A secure, high-performance Python SDK for FeatureFlagsHQ feature flag management
Project description
FeatureFlagsHQ Python SDK
A secure, high-performance Python SDK for FeatureFlagsHQ feature flag management with enterprise-grade security, offline support, and comprehensive analytics.
✨ Features
- 🔒 Enterprise Security: HMAC authentication, input validation, and security filtering
- ⚡ High Performance: Background polling, caching, and circuit breaker patterns
- 🌐 Offline Support: Works seamlessly without internet connectivity
- 📊 Analytics & Metrics: Comprehensive usage tracking and statistics
- 🎯 User Segmentation: Advanced targeting based on user attributes
- 🔄 Real-time Updates: Background flag synchronization with change callbacks
- 🛡️ Production Ready: Rate limiting, error handling, and graceful degradation
📦 Installation
pip install featureflagshq
🚀 Quick Start
from featureflagshq import FeatureFlagsHQSDK
# Initialize the SDK
sdk = FeatureFlagsHQSDK(
client_id="your_client_id",
client_secret="your_client_secret",
environment="production" # or "staging", "development"
)
# Get a feature flag value
user_id = "user_123"
is_enabled = sdk.get_bool(user_id, "new_dashboard", default_value=False)
if is_enabled:
print("New dashboard is enabled for this user!")
else:
print("Using classic dashboard")
# Clean shutdown
sdk.shutdown()
⚙️ Configuration
🌍 Environment Variables
The SDK can be configured using environment variables:
export FEATUREFLAGSHQ_CLIENT_ID="your_client_id"
export FEATUREFLAGSHQ_CLIENT_SECRET="your_client_secret"
export FEATUREFLAGSHQ_ENVIRONMENT="production"
# SDK will automatically use environment variables
sdk = FeatureFlagsHQSDK()
🔧 Advanced Configuration
sdk = FeatureFlagsHQSDK(
client_id="your_client_id",
client_secret="your_client_secret",
environment="production",
api_base_url="https://api.featureflagshq.com", # Custom API endpoint
timeout=30, # Request timeout
max_retries=3, # Number of retries
offline_mode=False, # Enable offline mode
enable_metrics=True, # Enable analytics
on_flag_change=lambda name, old, new: print(f"Flag {name} changed!")
)
💻 Usage Examples
🎯 Basic Flag Evaluation
from featureflagshq import FeatureFlagsHQSDK
sdk = FeatureFlagsHQSDK(
client_id="your_client_id",
client_secret="your_client_secret"
)
user_id = "user_123"
# Boolean flags
show_beta_feature = sdk.get_bool(user_id, "beta_feature", default_value=False)
# String flags
button_color = sdk.get_string(user_id, "button_color", default_value="blue")
# Integer flags
max_items = sdk.get_int(user_id, "max_items_per_page", default_value=10)
# Float flags
discount_rate = sdk.get_float(user_id, "discount_rate", default_value=0.0)
# JSON flags
config = sdk.get_json(user_id, "app_config", default_value={})
👥 User Segmentation
# Define user segments for targeting
user_segments = {
"country": "US",
"subscription": "premium",
"age": 25,
"beta_user": True
}
# Evaluate flags with segments
is_premium_feature_enabled = sdk.get_bool(
user_id="user_123",
flag_name="premium_analytics",
default_value=False,
segments=user_segments
)
📊 Bulk Flag Evaluation
# Get all flags for a user
all_flags = sdk.get_user_flags("user_123", segments=user_segments)
print(f"All flags for user: {all_flags}")
# Get specific flags only
specific_flags = sdk.get_user_flags(
"user_123",
segments=user_segments,
flag_keys=["feature_a", "feature_b", "feature_c"]
)
🔄 Context Manager Usage
# Automatic cleanup with context manager
with FeatureFlagsHQSDK(client_id="...", client_secret="...") as sdk:
is_enabled = sdk.get_bool("user_123", "new_feature")
# SDK automatically shuts down when exiting the context
🏭 Production Setup
from featureflagshq import create_production_client
# Create a production-ready client with security hardening
sdk = create_production_client(
client_id="your_client_id",
client_secret="your_client_secret",
environment="production",
timeout=30,
max_retries=3
)
🌶️ Flask Integration
from flask import Flask, request
from featureflagshq import FeatureFlagsHQSDK
app = Flask(__name__)
# Initialize SDK once
sdk = FeatureFlagsHQSDK(
client_id="your_client_id",
client_secret="your_client_secret"
)
@app.route('/dashboard')
def dashboard():
user_id = request.user.id # Get from your auth system
# Check if new dashboard is enabled
use_new_dashboard = sdk.get_bool(user_id, "new_dashboard_v2")
if use_new_dashboard:
return render_template('dashboard_v2.html')
else:
return render_template('dashboard_v1.html')
# Clean shutdown when app closes
@app.teardown_appcontext
def shutdown_sdk(exception):
sdk.shutdown()
🎸 Django Integration
# settings.py
FEATUREFLAGSHQ_CLIENT_ID = "your_client_id"
FEATUREFLAGSHQ_CLIENT_SECRET = "your_client_secret"
FEATUREFLAGSHQ_ENVIRONMENT = "production"
# utils.py
from django.conf import settings
from featureflagshq import FeatureFlagsHQSDK
_sdk_instance = None
def get_feature_flags_sdk():
global _sdk_instance
if _sdk_instance is None:
_sdk_instance = FeatureFlagsHQSDK(
client_id=settings.FEATUREFLAGSHQ_CLIENT_ID,
client_secret=settings.FEATUREFLAGSHQ_CLIENT_SECRET,
environment=settings.FEATUREFLAGSHQ_ENVIRONMENT
)
return _sdk_instance
# views.py
from django.shortcuts import render
from .utils import get_feature_flags_sdk
def my_view(request):
sdk = get_feature_flags_sdk()
user_id = str(request.user.id)
show_new_feature = sdk.get_bool(user_id, "new_feature")
return render(request, 'template.html', {
'show_new_feature': show_new_feature
})
🔬 Advanced Features
📞 Flag Change Callbacks
def on_flag_changed(flag_name, old_value, new_value):
print(f"Flag '{flag_name}' changed from {old_value} to {new_value}")
# Trigger cache invalidation, send notifications, etc.
sdk = FeatureFlagsHQSDK(
client_id="your_client_id",
client_secret="your_client_secret",
on_flag_change=on_flag_changed
)
🔄 Manual Refresh and Cache Control
# Manually refresh flags from server
success = sdk.refresh_flags()
if success:
print("Flags refreshed successfully")
# Get all cached flags
all_flags = sdk.get_all_flags()
print(f"Cached flags: {list(all_flags.keys())}")
# Force log upload
sdk.flush_logs()
📈 SDK Health and Statistics
# Get SDK health status
health = sdk.get_health_check()
print(f"SDK Status: {health['status']}")
print(f"Cached Flags: {health['cached_flags_count']}")
# Get detailed usage statistics
stats = sdk.get_stats()
print(f"Total API calls: {stats['api_calls']['total']}")
print(f"Unique users: {stats['unique_users_count']}")
print(f"Circuit breaker state: {stats['circuit_breaker']['state']}")
🌐 Offline Mode
# Enable offline mode for environments without internet
sdk = FeatureFlagsHQSDK(
client_id="your_client_id",
client_secret="your_client_secret",
offline_mode=True
)
# All flag evaluations will use default values in offline mode
result = sdk.get_bool("user_123", "feature_flag", default_value=True)
⚠️ Error Handling
The SDK includes comprehensive error handling and graceful degradation:
try:
sdk = FeatureFlagsHQSDK(
client_id="invalid_client_id",
client_secret="invalid_secret"
)
# SDK will continue to work but use default values
# Check health to see if there are authentication issues
health = sdk.get_health_check()
if health['status'] != 'healthy':
print(f"SDK not healthy: {health}")
except ValueError as e:
print(f"Configuration error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
✅ Best Practices
1️⃣ Singleton Pattern
Create one SDK instance per application and reuse it:
# Good
sdk = FeatureFlagsHQSDK(client_id="...", client_secret="...")
# Reuse sdk throughout your application
# Bad - creates multiple instances
def get_flag():
sdk = FeatureFlagsHQSDK(client_id="...", client_secret="...")
return sdk.get_bool("user", "flag")
2️⃣ Always Provide Default Values
# Good - provides fallback behavior
is_enabled = sdk.get_bool("user_123", "new_feature", default_value=False)
# Risky - might return None in error cases
is_enabled = sdk.get_bool("user_123", "new_feature")
3️⃣ Use Context Managers for Short-lived Usage
# For scripts or short-lived processes
with FeatureFlagsHQSDK(client_id="...", client_secret="...") as sdk:
result = sdk.get_bool("user", "flag")
# Automatic cleanup
4️⃣ Monitor SDK Health
# Periodically check SDK health in production
health = sdk.get_health_check()
if health['status'] != 'healthy':
# Alert your monitoring system
logger.warning(f"FeatureFlags SDK unhealthy: {health}")
📚 API Reference
🎯 Main Methods
get(user_id, flag_name, default_value, segments)- Get flag value with type inferenceget_bool(user_id, flag_name, default_value, segments)- Get boolean flagget_string(user_id, flag_name, default_value, segments)- Get string flagget_int(user_id, flag_name, default_value, segments)- Get integer flagget_float(user_id, flag_name, default_value, segments)- Get float flagget_json(user_id, flag_name, default_value, segments)- Get JSON flagget_user_flags(user_id, segments, flag_keys)- Get multiple flags for useris_flag_enabled_for_user(user_id, flag_name, segments)- Check if flag is enabled
🛠️ Management Methods
refresh_flags()- Manually refresh flags from serverflush_logs()- Upload pending analytics logsget_all_flags()- Get all cached flag definitionsget_stats()- Get SDK usage statisticsget_health_check()- Get SDK health statusshutdown()- Clean shutdown of background threads
🔐 Security
The SDK implements multiple security layers:
- HMAC Authentication: All API requests are signed with HMAC-SHA256
- Input Validation: All inputs are validated and sanitized
- Security Filtering: Sensitive data is filtered from logs
- Rate Limiting: Per-user rate limiting prevents abuse
- Circuit Breaker: Automatic failure detection and recovery
🆘 Support
- Documentation: Official docs
- Issues: GitHub Issues
- Email: hello@featureflagshq.com
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🤝 Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📋 Changelog
See CHANGELOG.md for version history and updates.
Built with ❤️ by the FeatureFlagsHQ Team
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file featureflagshq-1.0.1.tar.gz.
File metadata
- Download URL: featureflagshq-1.0.1.tar.gz
- Upload date:
- Size: 65.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
889954f626c9fb27356822032d1bbead8d7699dbffb5e6bbcbbc42fdeb402d71
|
|
| MD5 |
cda91204dd82dee38d076914184c558c
|
|
| BLAKE2b-256 |
129170a234850538fc3695e498cc701c07f6e3fc4436fa0690bcff8b1b274560
|
File details
Details for the file featureflagshq-1.0.1-py3-none-any.whl.
File metadata
- Download URL: featureflagshq-1.0.1-py3-none-any.whl
- Upload date:
- Size: 17.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1d04a0e416f37440e02c041dd55e2ad87e67c484288fc43f5939a8b3b57fddd
|
|
| MD5 |
3094bd9012be1de004019b3e85b25451
|
|
| BLAKE2b-256 |
c13a2282811e423643ddfc98df8886165d70846ecf24c32120c52b7519208645
|