SmartSwitch
Named function registry and plugin system for Python
What is SmartSwitch?
SmartSwitch is a lightweight library that helps you organize and manage functions using two core capabilities:
Named Handler Registry: Register functions by name or custom alias, then call them dynamically
Plugin System: Extend functionality with middleware-style plugins for logging, validation, and more
In one sentence: SmartSwitch turns your functions into a callable registry with extensible middleware.
When is SmartSwitch Useful?
SmartSwitch shines in these scenarios:
API Routers: Map endpoint names to handler functions
Command Dispatchers: Build CLI tools with named command handlers
Event Handlers: Create event-driven systems with clean handler registration
Plugin Architectures: Need middleware-style wrapping around functions
Code Organization: Replace messy if-elif chains with declarative function registries
Key Features
Core Functionality
Named handler registry: Call functions by name using decorator-based registration
Custom aliases: Use friendly names different from function names
Prefix-based naming: Convention-driven automatic name derivation
Hierarchical organization: Parent-child Switcher relationships with dotted-path access
Zero dependencies: Pure Python 3.10+ standard library
Type safe: Full type hints support
Plugin System
Extensible architecture: Add custom functionality via plugins
Clean API: Access plugins via
sw.plugin_name.method()patternComposable: Chain multiple plugins seamlessly
Standard plugins: Built-in logging plugin included
External plugins: Third-party packages can extend functionality
Developer Experience
Modular & testable: Each handler is an independent, testable function
Clean code: Replace if-elif chains with declarative registries
High performance: Optimized with caching (~1-2μs overhead per call)
Well documented: Comprehensive guides with tested examples
Quick Example
Basic Usage
Replace this messy code:
# Manual dictionary - error-prone
operations = {
'save': save_data,
'load': load_data,
'delete': delete_data
}
# Need to check existence
op = operations.get(action)
if op:
result = op(data)
With clean, self-registering handlers:
from smartswitch import Switcher
ops = Switcher()
@ops
def save_data(data):
return f"Saved {data}"
@ops
def load_data(data):
return f"Loaded {data}"
@ops
def delete_data(data):
return f"Deleted {data}"
# Clean, direct call
result = ops('save_data')(data)
With Plugins
Add logging to track all handler calls:
from smartswitch import Switcher
# Create switcher with logging plugin
sw = Switcher().plug('logging', flags='print,enabled,after,time')
@sw
def my_handler(x):
return x * 2
# Use handler
result = sw('my_handler')(5) # → 10
# Access plugin to analyze history
print(history) # → [{'handler': 'my_handler', 'args': (5,), 'result': 10, ...}]
# Find slow operations
slowest = sw.logging.history(slowest=5)
Learning Path
For Beginners
Start here to understand the basics:
Installation - Get SmartSwitch installed
Quick Start - Learn the two core patterns in minutes
Basic Usage - Understand decorator patterns and calling conventions
For Production Use
Deep dive into specific features:
Named Handlers - Registry patterns, aliases, prefix-based naming
API Discovery - Introspection and hierarchical organization
Best Practices - Production patterns and performance tips
For Extension Developers
Build custom functionality:
Plugin System Overview - Understanding the plugin architecture
Plugin Development - Create your own plugins
Middleware Pattern - Advanced plugin patterns
Why SmartSwitch?
Traditional approaches to conditional logic often lead to:
Long if-elif chains that grow over time
Duplicate code across similar handlers
Hard-to-maintain monolithic functions
Poor testability and code organization
SmartSwitch solves these problems by:
Separating registration from invocation: Functions self-register, you call by name
Making handlers independent: Each function is standalone and testable
Enabling composition: Plugins add cross-cutting concerns without modifying handlers
Providing clear structure: Hierarchical organization for complex systems
Real-World Example
Here’s a complete API router implementation:
from smartswitch import Switcher
api = Switcher(name="api")
@api('list_users')
def get_users(page=1):
# Fetch from database
return {"users": [...], "page": page}
@api('create_user')
def create_user(data):
# Create user
return {"id": 123, "created": True}
@api('not_found')
def handle_404():
return {"error": "Not Found", "status": 404}
# Route requests
def handle_request(endpoint, **kwargs):
handler = api._methods.get(endpoint)
if handler:
return api(endpoint)(**kwargs)
return api('not_found')()
# Use it
response = handle_request('list_users', page=2)
print(response) # → {"users": [...], "page": 2}
Get Started
Install with pip:
pip install smartswitch
Then check out the Quick Start Guide to begin using SmartSwitch in your projects.
Performance
SmartSwitch adds minimal overhead (~1-2 microseconds per dispatch). For real-world functions doing actual work (API calls, database queries, business logic), this overhead is negligible:
Function execution time: 50ms (API call)
SmartSwitch overhead: 0.002ms
Relative impact: 0.004% ✅
See Performance Best Practices for details.
Documentation
Getting Started
User Guide
- Named Handlers Guide
- Basic Named Handler Access
- One-Liner Invocation
- Custom Aliases
- Explicit Named Dispatch
- Prefix-Based Auto-Naming
- Handler Registry
- Duplicate Name Detection
- Handler Not Found
- Common Patterns
- Combining Named and Automatic Dispatch
- Descriptor Protocol for Class Usage
- Performance Characteristics
- Best Practices
- Next Steps
- API Discovery and Introspection
- Best Practices
Plugin System
- Plugin System
- Plugin Development Guide
- Overview
- Quick Links
- The Plugin Protocol
- Plugin Lifecycle (v0.6.0+)
- Plugin Naming
- Basic Plugin Example
- Accessing the Plugin
- Advanced Plugin Example: Retry Logic
- Plugin Initialization Parameters
- Storing State
- Chaining Multiple Plugins
- Standard vs External Plugins
- Best Practices
- Plugin Protocol Reference
- FAQ
- Summary
- Plugin Middleware Pattern
- LoggingPlugin
Examples
API Reference
Advanced
- Architecture Deep Dive
- Architecture Overview
- Registration Flow
- Named Dispatch Flow
- Class Relationships
- Module Structure
- Component Responsibilities
- Key Design Decisions
- Component Interaction Summary
- Performance Characteristics
- Thread Safety Considerations
- Plugin System Details
- Introspection API
- Future Extension Points
- Design Principles Applied
License
MIT License - see LICENSE file for details.