API Discovery and Introspection
SmartSwitch provides basic features for inspecting and organizing your handler registries. These are primarily useful for building frameworks and tools that need runtime introspection.
For production examples, see smpub - a CLI/API framework built on SmartSwitch that demonstrates advanced usage patterns.
Listing Registered Handlers
Use the entries() method to get a list of all registered handler names:
from smartswitch import Switcher
api = Switcher()
@api
def save_user(name, email):
"""Save a user to the database."""
pass
@api
def delete_user(user_id):
"""Delete a user from the database."""
pass
# List all registered handlers
handlers = api.entries()
print(handlers) # Output: ['save_user', 'delete_user']
With Prefix Stripping
When using prefix auto-stripping, entries() returns the stripped names:
api = Switcher(prefix="api_")
@api
def api_create(data):
pass
@api
def api_delete(id):
pass
# Returns stripped names
print(api.entries()) # Output: ['create', 'delete']
Organizing Multiple Switchers
Use the add() method to organize multiple Switchers within a single class:
from smartswitch import Switcher
class MyAPI:
# Main switcher
mainswitch = Switcher(name="main")
# Add child switchers
users = mainswitch.add(Switcher(name="users", prefix="user_"))
posts = mainswitch.add(Switcher(name="posts", prefix="post_"))
products = mainswitch.add(Switcher(name="products", prefix="product_"))
@users
def user_create(self, data):
"""Create a new user."""
return "user_created"
@users
def user_delete(self, user_id):
"""Delete a user."""
return "user_deleted"
@posts
def post_create(self, data):
"""Create a new post."""
return "post_created"
# Use directly
api = MyAPI()
api.users('create')() # Direct access
api.posts('create')()
# Or via mainswitch with dot notation
api.mainswitch('users.create')() # Hierarchical access
api.mainswitch('posts.create')()
# Discover all children
for child in api.mainswitch.children:
print(f"{child.name}: {child.entries()}")
This pattern is useful for:
Logical organization - Group related handlers together in one class
Flexible access - Use child switchers directly or via mainswitch
Dot notation - Navigate with
mainswitch('users.create')Discovery - Iterate children to find all registered switchers
Parent-Child Relationship Management
SmartSwitch provides automatic bidirectional parent-child relationship management. When you set a parent, the child is automatically registered with the parent’s children.
Setting Parent Dynamically
from smartswitch import Switcher
# Create independent Switchers
root = Switcher(name="root")
child = Switcher(name="child")
# Set parent dynamically - automatic bidirectional registration
child.parent = root
# Both sides are linked
assert child.parent is root
assert child in root.children
Adding Children
parent = Switcher(name="parent")
child = Switcher(name="child")
# Add child - automatically sets parent
parent.add_child(child, name="child")
assert child.parent is parent
assert parent.describe()["children"]["child"] is child # describe() returns a nested dict
Switcher.add_child() now accepts either a Switcher instance or an arbitrary object.
When you pass a non-switch object (e.g., a service class), SmartSwitch scans it for
all switchers without a parent—both class attributes and instance attributes—and
mounts them automatically:
class BillingModule:
api = Switcher("billing")
def __init__(self):
self.invoicing = Switcher("invoicing")
root = Switcher("root")
root.add_child(BillingModule()) # Finds both api + invoicing switchers
assert root.get_child("billing") is BillingModule.api
assert root.get_child("invoicing")
This makes it easy to cascade service classes: build self-contained modules that expose one or more switchers, then plug them into a root switch without writing any boilerplate. Typical pattern:
class Shop:
api = Switcher("shop")
def __init__(self, conn_string):
self.db = SqlDb(conn_string, self)
self.tables = InventoryTables(self.db)
# Automatically attach every switch defined on db/tables
self.api.add_child(self.db)
self.api.add_child(self.tables)
Each module controls its own switch hierarchy, while the root (Shop.api) simply
mounts them and exposes a single entry point for SmartPublisher or CLI tooling.
Querying Children
parent = Switcher(name="parent")
child1 = Switcher(name="child1", parent=parent)
child2 = Switcher(name="child2", parent=parent)
# Get all children
children = parent.children
print(len(children)) # Output: 2
# Iterate children
for child in parent.children:
print(child.name, child.entries())
Reparenting
When you change a child’s parent, it’s automatically unregistered from the old parent:
old_parent = Switcher(name="old")
new_parent = Switcher(name="new")
child = Switcher(name="child", parent=old_parent)
# Change parent
child.parent = new_parent
# Automatically unregistered from old, registered with new
assert child not in old_parent.children
assert child in new_parent.children
Removing Children
parent = Switcher(name="parent")
child = Switcher(name="child", parent=parent)
# Option 1: Unset parent
child.parent = None
# Option 2: Remove from parent
parent.remove_child(child)
# Both ways unlink the relationship
assert child.parent is None
assert child not in parent.children
Recursive API Discovery
A real-world use case for hierarchical Switchers is discovering all APIs in a system:
# Root API
root_api = Switcher(name="root")
# Handler classes with their own APIs
class UserHandler:
api = Switcher(name="users", prefix="user_", parent=root_api)
@api
def user_list(self):
return ["alice", "bob"]
@api
def user_get(self, name):
return f"User: {name}"
class PostHandler:
api = Switcher(name="posts", prefix="post_", parent=root_api)
@api
def post_list(self):
return ["post1", "post2"]
@api
def post_create(self, title):
return f"Created: {title}"
# Discovery: iterate all children
for child in root_api.children:
print(f"\n{child.name} API:")
for handler_name in child.entries():
print(f" - {handler_name}")
# Output:
# users API:
# - list
# - get
# posts API:
# - list
# - create
This pattern enables:
Automatic API registration - Handlers register themselves on creation
Framework introspection - Tools can discover all available APIs
Documentation generation - Generate docs from the hierarchy
Testing utilities - Find and test all handlers automatically
API Reference
Methods
Switcher.entries()- List registered handler namesSwitcher.add_child(switcher)- Add a child Switcher (sets parent automatically)Switcher.remove_child(switcher)- Remove a child Switcher (unsets parent)
Properties
Switcher.parent- Get or set parent Switcher (bidirectional)Switcher.children- Get set of child Switchers (read-only copy)