Plugin System
New in v0.5.0: SmartSwitch includes a powerful plugin system that allows you to extend handler behavior with reusable components.
Overview
Plugins wrap handlers to add cross-cutting concerns like:
Validation (Pydantic type checking)
Logging (Call history and performance monitoring)
Authentication (Permission checks)
Caching (Result memoization)
Async/Sync bridging (SmartAsync integration)
Custom middleware (Your own functionality)
Quick Start
from smartswitch import Switcher
# Enable built-in logging plugin (v0.10.0+ uses flags)
sw = Switcher().plug("logging", flags="print,enabled,after")
@sw
def my_handler(x: int) -> int:
return x * 2
# Call handler - automatically logged
result = sw("my_handler")(5)
# Output: ← my_handler() → 10
# Runtime configuration
sw.logging.configure.flags = "print,enabled,before,after,time"
Built-in Plugins
SmartSwitch comes with two pre-registered plugins:
"logging"- Call history tracking, performance analysis, error monitoring"pydantic"- Automatic type validation using Pydantic models
# Use built-in plugins by name
sw = Switcher().plug("logging").plug("pydantic")
@sw
def typed_handler(x: int, y: str) -> str:
return f"{x}:{y}"
# Both logging and validation applied
result = sw("typed_handler")(42, "test")
Plugin Topics
Plugin Development
Learn how to create custom plugins:
Plugin protocol and lifecycle (v0.6.0+)
on_decorate()hook for setup phaseMetadata sharing between plugins via
func._plugin_metaBasePlugin class for common functionality
Global plugin registry
Middleware Pattern
Understand the middleware architecture:
How plugins compose via wrapper chains
Execution order and control flow
Best practices for middleware design
LoggingPlugin as canonical example
Logging Plugin
Deep dive into the built-in logging plugin (v0.4.0+):
Silent, log, and both modes
Call history tracking
Performance analysis and statistics
Error monitoring
Query API for filtering and analysis
Plugin Order Matters
The order you call .plug() determines:
Metadata dependencies - Later plugins can read earlier plugins’ metadata
Wrapper execution order - Outermost to innermost during calls
# ✅ CORRECT - pydantic before logging
sw = Switcher().plug("pydantic").plug("logging")
# Execution: logging → pydantic → handler
# ✅ ALSO VALID - logging before pydantic
sw = Switcher().plug("logging").plug("pydantic")
# Execution: pydantic → logging → handler
# (validation happens first, then logging)
Choose plugin order based on your needs:
Validation first - Reject invalid calls before logging
Logging first - Log all calls including validation errors
Creating Custom Plugins
To create your own plugin, implement the plugin protocol:
from smartswitch import BasePlugin
class MyPlugin(BasePlugin):
def on_decorate(self, switch, func, entry):
"""Optional: Setup phase during decoration."""
# Prepare resources, store metadata
entry.metadata.setdefault("my_plugin", {})
entry.metadata["my_plugin"]["prepared"] = True
def wrap_handler(self, switch, entry, call_next):
"""Required: Create wrapper function."""
def wrapper(*args, **kwargs):
# Pre-processing
result = call_next(*args, **kwargs)
# Post-processing
return result
return wrapper
# Register and use
from smartswitch import Switcher
Switcher.register_plugin("my_plugin", MyPlugin)
sw = Switcher().plug("my_plugin")
See Plugin Development for complete documentation.
Next Steps
New to plugins? Start with Middleware Pattern to understand the architecture
Want to create plugins? Read Plugin Development for the complete guide
Using logging? Check Logging Plugin for all features and examples