Named function registry and plugin system for Python
Project description
SmartSwitch
Named function registry and plugin system for Python
SmartSwitch is a lightweight Python library for managing function registries with named handlers and extensible plugin architecture. Perfect for API routers, command dispatchers, event handlers, and any scenario where you need clean, maintainable function organization.
What is SmartSwitch?
SmartSwitch provides 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, async support, etc.
When to use SmartSwitch:
- Building API routers or command dispatchers
- Creating plugin-based architectures
- Organizing related functions into callable registries
- Need middleware-style function wrapping
- Want clean, testable code instead of if-elif chains
Installation
pip install smartswitch
Quick Start
Basic Handler Registry
from smartswitch import Switcher
# Create a registry
ops = Switcher()
# Register handlers
@ops
def save_data(data):
return f"Saved: {data}"
@ops
def load_data(data):
return f"Loaded: {data}"
# Call by name
result = ops('save_data')("my_file.txt")
print(result) # → "Saved: my_file.txt"
Custom Aliases
ops = Switcher()
# Register with custom names
@ops('reset')
def destroy_all_data():
return "Everything destroyed"
@ops('clear')
def remove_cache():
return "Cache cleared"
# Call with friendly alias
result = ops('reset')()
print(result) # → "Everything destroyed"
Prefix-Based Auto-Naming
Use naming conventions to automatically derive handler names:
# Set a prefix for automatic name derivation
protocols = Switcher(prefix='protocol_')
@protocols # Auto-registers as 's3_aws' (removes prefix)
def protocol_s3_aws():
return {"type": "s3", "region": "us-east-1"}
@protocols # Auto-registers as 'gcs'
def protocol_gcs():
return {"type": "gcs", "bucket": "data"}
# Call by derived names
result = protocols('s3_aws')()
print(result) # → {"type": "s3", "region": "us-east-1"}
Hierarchical Organization
Organize multiple Switchers into parent-child relationships:
from smartswitch import Switcher
class MyAPI:
# Main switcher
main = Switcher(name="main")
# Child switchers with hierarchy
users = Switcher(name="users", parent=main, prefix="user_")
products = Switcher(name="products", parent=main, prefix="product_")
@users
def user_list(self):
return ["alice", "bob"]
@products
def product_list(self):
return ["laptop", "phone"]
# Direct access
api = MyAPI()
api.users('list')() # → ["alice", "bob"]
# Hierarchical access via parent
api.main('users.list')() # → ["alice", "bob"]
api.main('products.list')() # → ["laptop", "phone"]
# Discover children
for child in api.main._children.values():
print(f"{child.name}: {list(child._methods.keys())}")
Plugin System
Extend SmartSwitch functionality with plugins:
from smartswitch import Switcher
# Create switcher with logging plugin
sw = Switcher().plug('logging', mode='print,after,time')
@sw
def my_handler(x):
return x * 2
# Use handler - logs output automatically
result = sw('my_handler')(5) # → 10
# Output: ← my_handler() → 10 (0.0001s)
# Use before+after for debugging
sw_debug = Switcher().plug('logging', mode='print,before,after')
@sw_debug
def process(data):
return f"Processed: {data}"
sw_debug('process')("test")
# Output:
# → process('test')
# ← process() → Processed: test
Creating Custom Plugins
from smartswitch import BasePlugin
class ValidationPlugin(BasePlugin):
"""Validate arguments before handler execution."""
def wrap_handler(self, switch, entry, call_next):
def wrapper(*args, **kwargs):
# Custom validation logic
if not args:
raise ValueError("No arguments provided")
return call_next(*args, **kwargs)
return wrapper
# Use custom plugin
sw = Switcher().plug(ValidationPlugin())
@sw
def process(data):
return f"Processed: {data}"
# Plugin validates before execution
result = sw('process')("test") # → "Processed: test"
Chaining Multiple Plugins
from smartswitch import Switcher
from my_plugins import CachePlugin, MetricsPlugin
sw = (Switcher()
.plug('logging', mode='print,after,time')
.plug(CachePlugin(ttl=300))
.plug(MetricsPlugin(namespace='api')))
@sw
def expensive_operation(x):
# Plugins execute in order: logging → cache → metrics
return x * 2
Real-World Examples
API Router
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')()
Command Dispatcher
cli = Switcher(prefix='cmd_')
@cli
def cmd_backup(target):
return f"Backing up {target}"
@cli
def cmd_restore(source):
return f"Restoring from {source}"
@cli('help')
def cmd_show_help():
return "Available commands: " + ", ".join(cli._methods.keys())
# Dispatch commands
command = input("Enter command: ")
result = cli(command.split()[0])(*command.split()[1:])
Event Handler
events = Switcher()
@events('user.created')
def on_user_created(user_id):
print(f"Welcome email sent to user {user_id}")
@events('user.deleted')
def on_user_deleted(user_id):
print(f"Cleanup completed for user {user_id}")
# Emit events
def emit(event_name, *args):
if event_name in events._methods:
events(event_name)(*args)
Key Features
Core Functionality
- Named handler registry: Register and call functions by name
- 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()pattern - Composable: 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 and tested examples
Performance
SmartSwitch adds minimal overhead (~1-2 microseconds per dispatch). For real-world functions doing actual work (API calls, database queries, business logic), this is negligible:
Function execution time: 50ms (API call)
SmartSwitch overhead: 0.002ms
Relative impact: 0.004% ✅
Good for:
- API handlers and request routers
- Command dispatchers
- Event handling systems
- Business logic organization
- Any function doing real work (>1ms execution time)
Consider alternatives for:
- Ultra-fast functions (<10μs) called millions of times per second
- Simple 2-3 case switches (plain if-elif is fine)
See Performance Best Practices for details.
Thread Safety
SmartSwitch is designed for typical Python usage patterns:
- Handler dispatch (calling
sw('name')(args)) is fully thread-safe - uses read-only operations - Decorator registration should be done at module import time (single-threaded)
Recommended usage:
# Module level - executed once at import (safe)
switch = Switcher()
@switch
def my_handler(x):
return x * 2
# Runtime - called many times (thread-safe)
result = switch('my_handler')(42)
For advanced scenarios requiring runtime registration in multi-threaded applications, external synchronization is needed.
Documentation
📚 Full documentation: smartswitch.readthedocs.io
User Guides:
Feature Guides:
- Named Handlers - Function registry patterns
- API Discovery - Introspection and hierarchies
- Best Practices - Production patterns
Plugin System:
- Plugin Overview - Understanding plugins
- Plugin Development - Create custom plugins
- Logging Plugin - Call history tracking
Reference:
- API Reference - Complete API docs
- Architecture - Internal design
All examples in documentation are tested - They come directly from our test suite with 82% coverage.
License
MIT
Contributing
Contributions welcome! Please feel free to submit a Pull Request.
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 smartswitch-0.9.2.tar.gz.
File metadata
- Download URL: smartswitch-0.9.2.tar.gz
- Upload date:
- Size: 31.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4d832f9efb7fad432cd8464c11c2d77617cb78ad6f9750515bf6f11b7eb5e16
|
|
| MD5 |
42fb56f70410c111d40a2a14fba72253
|
|
| BLAKE2b-256 |
fba77b42483dfec1e8e35f8e51acc0ec35d80a3dee6491f21308246e472616fd
|
Provenance
The following attestation bundles were made for smartswitch-0.9.2.tar.gz:
Publisher:
publish.yml on genropy/smartswitch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
smartswitch-0.9.2.tar.gz -
Subject digest:
e4d832f9efb7fad432cd8464c11c2d77617cb78ad6f9750515bf6f11b7eb5e16 - Sigstore transparency entry: 702073107
- Sigstore integration time:
-
Permalink:
genropy/smartswitch@f64fb45e7c379b396d42553e8ed28d8ceb28038d -
Branch / Tag:
refs/tags/v0.9.2 - Owner: https://github.com/genropy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f64fb45e7c379b396d42553e8ed28d8ceb28038d -
Trigger Event:
push
-
Statement type:
File details
Details for the file smartswitch-0.9.2-py3-none-any.whl.
File metadata
- Download URL: smartswitch-0.9.2-py3-none-any.whl
- Upload date:
- Size: 18.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa78716132ea0462916b65c805adfefd342701b32cf42e41a8bf36defb27ab65
|
|
| MD5 |
0fa2bd5f3a7acfa7da36febc45e6c8a3
|
|
| BLAKE2b-256 |
f28e6a8c1bb0ca11b40cb6c80eb81edee88418de3f4099e1c07a3ac07d76f2f4
|
Provenance
The following attestation bundles were made for smartswitch-0.9.2-py3-none-any.whl:
Publisher:
publish.yml on genropy/smartswitch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
smartswitch-0.9.2-py3-none-any.whl -
Subject digest:
fa78716132ea0462916b65c805adfefd342701b32cf42e41a8bf36defb27ab65 - Sigstore transparency entry: 702073118
- Sigstore integration time:
-
Permalink:
genropy/smartswitch@f64fb45e7c379b396d42553e8ed28d8ceb28038d -
Branch / Tag:
refs/tags/v0.9.2 - Owner: https://github.com/genropy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f64fb45e7c379b396d42553e8ed28d8ceb28038d -
Trigger Event:
push
-
Statement type: