API Reference
Below is the Sphinx API reference. For more context or quick-start guides, see:
LLM API Details – Complete API reference
LLM Quick Reference – 30-second quick start
Plugin-free router runtime (source of truth).
If this file vanished, rebuild it verbatim from this description. The module
exposes a single class, BaseRouter, which binds methods on an object
instance, resolves dotted selectors, and exposes rich introspection without any
plugin logic. Subclasses add middleware but must preserve these semantics.
Constructor and slots
Constructor signature:
BaseRouter(owner, name=None, prefix=None, *,
get_default_handler=None, get_use_smartasync=None,
get_kwargs=None, branch=False, auto_discover=True,
auto_selector="*", parent_router=None)
owneris required;NoneraisesValueError. Routers are bound to this instance and never re-bound.parent_router: optional parent router. When provided, this router is automatically attached as a child usingnameas the alias. Requiresnameto be set; raisesValueErroron name collision.Slots:
instance,name,prefix(string trimmed from function names),_entries(logical name → MethodEntry),_handlers(name → callable),_children(name → child router),_get_defaults(SmartOptions defaults).Default options:
get_default_handlerandget_use_smartasyncbecome defaults merged viaSmartOptionsinget(); extraget_kwargsare copied into_get_defaults.On init: registers with owner via optional
_register_routerhook, then auto-discovers entries whenauto_discoveris true by callingadd_entry(auto_selector)("*"by default).
Registration and naming
add_entry(target, *, name=None, metadata=None, replace=False, **options)
Accepts a callable or string/iterable of attribute names. Comma-separated strings are split and each processed. Empty/whitespace-only strings are ignored.
replace=Falseraises on logical name collision.Special markers
"*","_all_","__all__"trigger marker discovery via_register_marked(see below). A comma inside such marker string is split and each chunk processed recursively.When
targetis a string, it is resolved as an attribute ofowner; anAttributeErroris surfaced with a helpful message.When
targetis a function, it is bound toownerunless already a bound method.metadata+optionsare merged into the MethodEntry metadata._resolve_namestripsprefixfromfunc.__name__when present; an explicitnamealways overrides.
Marker discovery
_iter_marked_methods walks the reversed MRO of type(owner) (child first
wins), scans __dict__ for plain functions carrying TARGET_ATTR_NAME
markers.
Duplicates (by function identity) are skipped. Only markers whose name
matches this router’s name are used; the name key is removed from the
payload before consumption. _register_marked binds each function to owner,
merges marker data + metadata + extra options, and registers with collision
behaviour governed by replace.
Handler table and wrapping
_register_callablecreates aMethodEntry(name, bound func, router, empty plugins list, metadata dict) and stores it in_entries; it invokes_after_entry_registeredhook then rebuilds the handler cache._rebuild_handlersrecreates_handlersby passing each entry through_wrap_handler(default: passthrough). Subclasses may inject middleware.
Lookup and execution
get(selector, **options)mergesoptionsintoSmartOptionsusing_get_defaults. It resolvesselectorvia_resolve_path: a dotted string traverses children (_childrenlookup) and yields the terminal router plus method name; no dot returnsself+ selector. Missing children raiseKeyError. Missing handlers fall back todefault_handler(if provided) else raiseNotImplementedError.When
use_smartasyncoption is truthy, the returned handler is wrapped viasmartasync.smartasyncbefore returning.__getitem__aliasesget;callfetches then invokes the handler with given args/kwargs.entriesreturns a tuple of registered handler names (built from_handlerskeys).
Children (instance hierarchies only)
attach_instance(child, name=None) / detach_instance(child)
attach_instanceconnects routers exposed on aRoutedClasschild that is already stored as an attribute on the parent instance. It enforces that the child is not bound to another parent (via_routed_parent).Alias/mapping rules: parent with a single router can omit
name(aliases default to child router names); parent with multiple routers requires explicit alias/mapping; unmapped child routers are skipped (not attached).Attached child routers inherit plugins via
_on_attached_to_parent; the child’s_routed_parentis set to the parent instance.
detach_instance removes all child routers whose instance matches the
given child and clears _routed_parent when pointing to the parent. It is
best-effort (no error if nothing was removed).
Child discovery helpers
_collect_child_routers(source, override_name=None, seen=None) scans only
attributes/slots on source for BaseRouter instances, returning
[(key, router), ...] with unique keys (override → attr name → router.name →
"child"). A seen set guards against cycles.
Introspection
members(**kwargs)builds a nested dict of routers and entries respecting filters. Returns dict withentriesandrouterskeys only if non-empty. Empty routers (no entries, no child routers) return{}. Uses helper methods_entry_member_infoand_get_plugin_info.
Hooks for subclasses
_wrap_handler: override to wrap callables (middleware stack)._after_entry_registered: invoked after registering a handler._on_attached_to_parent: invoked when attached viaattach_instance._describe_entry_extra: allow subclasses to extend per-entry description.
Default implementations are no-ops/passthrough.
Invariants and guarantees
Handler names are unique unless
replace=True.Selector traversal never fabricates routers: only attached children are used.
Marker discovery is deterministic (reversed MRO, first occurrence wins).
Introspection never mutates handler metadata; it reads from
MethodEntry.All normalizations preserve user-provided metadata copies (shallow-copied).
- class smartroute.core.base_router.BaseRouter(owner, name=None, prefix=None, *, get_default_handler=None, get_use_smartasync=None, get_kwargs=None, branch=False, auto_discover=True, auto_selector='*', parent_router=None)[source]
Bases:
objectPlugin-free router bound to an object instance.
Responsibilities: - register bound methods/functions with logical names (optionally via markers) - resolve dotted selectors across child routers - expose handler tables and introspection data - provide hooks for subclasses to wrap handlers or filter introspection
- Parameters:
owner (
Any)name (
Optional[str])prefix (
Optional[str])get_default_handler (
Optional[Callable])get_use_smartasync (
Optional[bool])get_kwargs (
Optional[Dict[str,Any]])branch (
bool)auto_discover (
bool)auto_selector (
str)parent_router (
Optional[BaseRouter])
- __init__(owner, name=None, prefix=None, *, get_default_handler=None, get_use_smartasync=None, get_kwargs=None, branch=False, auto_discover=True, auto_selector='*', parent_router=None)[source]
- Parameters:
owner (
Any)name (
Optional[str])prefix (
Optional[str])get_default_handler (
Optional[Callable])get_use_smartasync (
Optional[bool])get_kwargs (
Optional[Dict[str,Any]])branch (
bool)auto_discover (
bool)auto_selector (
str)parent_router (
Optional[BaseRouter])
- instance
- name
- prefix
- add_entry(target, *, name=None, metadata=None, replace=False, **options)[source]
Register handler(s) on this router.
- Parameters:
target (
Any) – Callable, attribute name(s), comma-separated string, or wildcard marker.name (
Optional[str]) – Logical name override for this entry.metadata (
Optional[Dict[str,Any]]) – Extra metadata stored on the MethodEntry.replace (
bool) – Allow overwriting an existing logical name.options (
Any) – Extra metadata merged into entry metadata.
- Return type:
- Returns:
self (to allow chaining).
- Raises:
ValueError – on handler name collision when replace is False.
AttributeError – when resolving missing attributes on owner.
TypeError – on unsupported target type.
- get(selector, **options)[source]
Resolve and return a handler callable for the given selector.
Dotted selectors traverse attached children. Falls back to
default_handlerif provided, otherwise raises NotImplementedError. Whenuse_smartasyncis true, the handler is wrapped accordingly.- Parameters:
selector (
str)options (
Any)
- Return type:
Callable
- __getitem__(selector, **options)
Resolve and return a handler callable for the given selector.
Dotted selectors traverse attached children. Falls back to
default_handlerif provided, otherwise raises NotImplementedError. Whenuse_smartasyncis true, the handler is wrapped accordingly.- Parameters:
selector (
str)options (
Any)
- Return type:
Callable
- call(selector, *args, **kwargs)[source]
Fetch and invoke a handler in one step.
- Parameters:
selector (
str)
- entries()[source]
Return a tuple of logical handler names registered on this router.
- Return type:
Tuple[str,...]
- attach_instance(routed_child, *, name=None)[source]
Attach a RoutedClass instance with optional alias mapping.
- Parameters:
routed_child (
Any)name (
Optional[str])
- Return type:
- detach_instance(routed_child)[source]
Detach all routers belonging to a RoutedClass instance.
- Parameters:
routed_child (
Any)- Return type:
Router with plugin pipeline (source of truth).
If this module disappeared, rebuild it exactly as described. Router extends
BaseRouter with a global plugin registry, per-router plugin instances,
middleware wrapping, and plugin state stored on the router instance.
Internal state
_plugin_specs: list of_PluginSpec(factory, kwargs copy, alias)._plugins: instantiated plugins in the order they were attached._plugins_by_name: name → plugin instance (first wins)._inherited_from: set of parent ids already inherited to avoid double cloning when the same child is attached multiple times._plugin_info: per-plugin state store on the router.
Global registry
Router.register_plugin(name, plugin_class) validates that plugin_class
is a subclass of BasePlugin and name is non-empty. Re-registering an
existing name with a different class raises ValueError; otherwise it is
idempotent. available_plugins returns a shallow copy of the registry.
Attaching plugins
plug(plugin_name, **config) looks up the plugin class by name in the global
registry (raises ValueError with available names if missing). It stores a
_PluginSpec clone, instantiates the plugin (applying alias=name), appends
to _plugins and _plugins_by_name if not present, applies
plugin.on_decore to all existing entries (also ensuring entry.plugins
lists the plugin), rebuilds handlers, and returns self. __getattr__
exposes attached plugins by name or raises AttributeError.
Runtime flags and data
Stored on the router under _plugin_info[plugin_code] using a reserved
"_all_" bucket for router-level defaults and one bucket per handler
name, each with config and locals. set_plugin_enabled /
is_plugin_enabled and set_runtime_data / get_runtime_data read/write
these buckets (no contextvars).
Wrapping pipeline
_wrap_handler(entry, call_next) builds middleware layers from the current
_plugins in reverse order (last attached closest to the handler). For each
plugin, it calls plugin.wrap_handler(self, entry, wrapped) to produce a
callable, then wraps it with a guard that skips execution when
is_plugin_enabled is False. functools.wraps preserves metadata of the
next callable. The final callable is stored in _handlers by BaseRouter.
Entry/plugin application
_apply_plugin_to_entriesensuresentry.pluginscontains the plugin name and invokesplugin.on_decoreon each existing entry. Called when a plugin is attached and during inheritance._after_entry_registered(override) is triggered byBaseRouterwhenever a new handler is registered; it applies all attached plugins the same way and leaves names inentry.plugins.
Inheritance behaviour
_on_attached_to_parent(parent) runs when a child router is attached.
Parent specs are cloned once per parent (id tracked in _inherited_from).
Cloned specs are instantiated into new plugins that are prepended ahead of
existing child plugins to preserve parent-first order. _plugins_by_name is
seeded without overwriting existing names. on_decore is applied to entries
and handlers rebuilt.
Filtering
_allow_entry first calls BaseRouter then asks each plugin in
_plugins (ordered as attached) via allow_entry. Any explicit False
hides the entry; any other truthy/None keeps it.
Filter arguments passed to members() are forwarded as-is to plugins via
allow_entry(**filters). Plugins are responsible for interpreting and
validating their own filter parameters.
Description hooks
_describe_entry_extraasks plugins to contribute extra fields formembers()output. Plugins implemententry_metadata(router, entry)which returns a dict stored inplugins[plugin_name]["metadata"].
Data shapes
_PluginSpec dataclass stores factory, kwargs, optional alias and
provides:
instantiate()→ creates plugin viafactory(**kwargs); applies alias toplugin.nameif set.clone()→ returns a new spec with a shallow-copied kwargs dict and same alias.
Router Invariants
Plugin order is deterministic (first attached = outermost layer; reversed wrapping). Filter evaluation follows attachment order.
Global registry changes do not mutate existing router instances.
Plugin access via attribute never fails silently.
- class smartroute.core.router.Router(*args, **kwargs)[source]
Bases:
BaseRouterRouter with plugin registry/pipeline support.
- classmethod register_plugin(plugin_class, name=None)[source]
Register a plugin class globally.
- Parameters:
plugin_class (
Type[BasePlugin]) – A BasePlugin subclass with plugin_code definedname (
Optional[str]) – Optional override name. If provided, overwrites any existing registration. If not provided, uses plugin_code and raises if already registered.
- Return type:
None
- plug(plugin, **config)[source]
Attach a plugin by name (previously registered globally).
- Parameters:
plugin (
str)config (
Any)
- Return type:
- iter_plugins()[source]
Return attached plugin instances in application order.
- Return type:
List[BasePlugin]
- get_config(plugin_name, method_name=None)[source]
Return plugin config (global + per-handler overrides) for an attached plugin.
- Parameters:
plugin_name (
str)method_name (
Optional[str])
- Return type:
Dict[str,Any]
- set_plugin_enabled(method_name, plugin_name, enabled=True)[source]
- Parameters:
method_name (
str)plugin_name (
str)enabled (
bool)
- Return type:
None
- is_plugin_enabled(method_name, plugin_name)[source]
- Parameters:
method_name (
str)plugin_name (
str)
- Return type:
bool
- set_runtime_data(method_name, plugin_name, key, value)[source]
- Parameters:
method_name (
str)plugin_name (
str)key (
str)value (
Any)
- Return type:
None
- get_runtime_data(method_name, plugin_name, key, default=None)[source]
- Parameters:
method_name (
str)plugin_name (
str)key (
str)default (
Any)
- Return type:
Any
- instance
- name
- prefix
Decorator helpers for marking routed methods (source of truth).
Rebuild this module exactly from the behaviours below. It contains only marker helpers; no router mutation happens at decoration time.
route(router, *, name=None, **kwargs)
Returns a decorator storing metadata on the function under
TARGET_ATTR_NAMEas a list of dicts. Each payload starts with{"name": router}.Explicit logical name: if
nameis provided, the payload setsentry_nameto that value. Otherwise the handler name defaults to the function name (after optional prefix stripping byBaseRouter).Extra
**kwargsare copied verbatim into the payload (e.g.scopes,scope_channels, plugin flags). Existing markers are preserved; the new one is appended so multiple routers can target the same function.The decorator returns the original function unchanged aside from the marker.
Re-exports
This module re-exports RoutedClass and Router for convenience so user
code can import everything from one place without understanding internal
package layout.
- smartroute.core.decorators.route(router, *, name=None, **kwargs)[source]
Mark a bound method for inclusion in the given router.
- Parameters:
router (
str) – Router identifier (e.g."api").name (
Optional[str]) – Optional explicit entry name (overrides function name/prefix stripping).kwargs (
Any)
- Return type:
Callable
- class smartroute.core.decorators.RoutedClass[source]
Bases:
objectMixin providing helper proxies for runtime routers.
- property routedclass: _RoutedProxy
- class smartroute.core.decorators.Router(*args, **kwargs)[source]
Bases:
BaseRouterRouter with plugin registry/pipeline support.
- instance
- name
- prefix
- get_config(plugin_name, method_name=None)[source]
Return plugin config (global + per-handler overrides) for an attached plugin.
- Parameters:
plugin_name (
str)method_name (
Optional[str])
- Return type:
Dict[str,Any]
- get_runtime_data(method_name, plugin_name, key, default=None)[source]
- Parameters:
method_name (
str)plugin_name (
str)key (
str)default (
Any)
- Return type:
Any
- is_plugin_enabled(method_name, plugin_name)[source]
- Parameters:
method_name (
str)plugin_name (
str)
- Return type:
bool
- iter_plugins()[source]
Return attached plugin instances in application order.
- Return type:
List[BasePlugin]
- plug(plugin, **config)[source]
Attach a plugin by name (previously registered globally).
- Parameters:
plugin (
str)config (
Any)
- Return type:
- classmethod register_plugin(plugin_class, name=None)[source]
Register a plugin class globally.
- Parameters:
plugin_class (
Type[BasePlugin]) – A BasePlugin subclass with plugin_code definedname (
Optional[str]) – Optional override name. If provided, overwrites any existing registration. If not provided, uses plugin_code and raises if already registered.
- Return type:
None