API Reference

Below is the Sphinx API reference. For more context or quick-start guides, see:

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)
  • owner is required; None raises ValueError. 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 using name as the alias. Requires name to be set; raises ValueError on 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_handler and get_use_smartasync become defaults merged via SmartOptions in get(); extra get_kwargs are copied into _get_defaults.

  • On init: registers with owner via optional _register_router hook, then auto-discovers entries when auto_discover is true by calling add_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=False raises 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 target is a string, it is resolved as an attribute of owner; an AttributeError is surfaced with a helpful message.

  • When target is a function, it is bound to owner unless already a bound method. metadata + options are merged into the MethodEntry metadata.

  • _resolve_name strips prefix from func.__name__ when present; an explicit name always 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_callable creates a MethodEntry (name, bound func, router, empty plugins list, metadata dict) and stores it in _entries; it invokes _after_entry_registered hook then rebuilds the handler cache.

  • _rebuild_handlers recreates _handlers by passing each entry through _wrap_handler (default: passthrough). Subclasses may inject middleware.

Lookup and execution

  • get(selector, **options) merges options into SmartOptions using _get_defaults. It resolves selector via _resolve_path: a dotted string traverses children (_children lookup) and yields the terminal router plus method name; no dot returns self + selector. Missing children raise KeyError. Missing handlers fall back to default_handler (if provided) else raise NotImplementedError.

  • When use_smartasync option is truthy, the returned handler is wrapped via smartasync.smartasync before returning.

  • __getitem__ aliases get; call fetches then invokes the handler with given args/kwargs. entries returns a tuple of registered handler names (built from _handlers keys).

Children (instance hierarchies only)

attach_instance(child, name=None) / detach_instance(child)

  • attach_instance connects routers exposed on a RoutedClass child 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_parent is 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 with entries and routers keys only if non-empty. Empty routers (no entries, no child routers) return {}. Uses helper methods _entry_member_info and _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 via attach_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: object

Plugin-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:

BaseRouter

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_handler if provided, otherwise raises NotImplementedError. When use_smartasync is 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_handler if provided, otherwise raises NotImplementedError. When use_smartasync is 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:

BaseRouter

detach_instance(routed_child)[source]

Detach all routers belonging to a RoutedClass instance.

Parameters:

routed_child (Any)

Return type:

BaseRouter

members(**kwargs)[source]

Return a tree of routers/entries/metadata respecting filters.

Parameters:

kwargs (Any)

Return type:

Dict[str, Any]

iter_plugins()[source]
Return type:

List[Any]

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_entries ensures entry.plugins contains the plugin name and invokes plugin.on_decore on each existing entry. Called when a plugin is attached and during inheritance.

  • _after_entry_registered (override) is triggered by BaseRouter whenever a new handler is registered; it applies all attached plugins the same way and leaves names in entry.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_extra asks plugins to contribute extra fields for members() output. Plugins implement entry_metadata(router, entry) which returns a dict stored in plugins[plugin_name]["metadata"].

Data shapes

_PluginSpec dataclass stores factory, kwargs, optional alias and provides:

  • instantiate() → creates plugin via factory(**kwargs); applies alias to plugin.name if 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: BaseRouter

Router with plugin registry/pipeline support.

__init__(*args, **kwargs)[source]
classmethod register_plugin(plugin_class, name=None)[source]

Register a plugin class globally.

Parameters:
  • plugin_class (Type[BasePlugin]) – A BasePlugin subclass with plugin_code defined

  • name (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

classmethod available_plugins()[source]
Return type:

Dict[str, Type[BasePlugin]]

plug(plugin, **config)[source]

Attach a plugin by name (previously registered globally).

Parameters:
  • plugin (str)

  • config (Any)

Return type:

Router

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_NAME as a list of dicts. Each payload starts with {"name": router}.

  • Explicit logical name: if name is provided, the payload sets entry_name to that value. Otherwise the handler name defaults to the function name (after optional prefix stripping by BaseRouter).

  • Extra **kwargs are 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: object

Mixin providing helper proxies for runtime routers.

property routedclass: _RoutedProxy
class smartroute.core.decorators.Router(*args, **kwargs)[source]

Bases: BaseRouter

Router with plugin registry/pipeline support.

instance
name
prefix
__init__(*args, **kwargs)[source]
classmethod available_plugins()[source]
Return type:

Dict[str, Type[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]

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:

Router

classmethod register_plugin(plugin_class, name=None)[source]

Register a plugin class globally.

Parameters:
  • plugin_class (Type[BasePlugin]) – A BasePlugin subclass with plugin_code defined

  • name (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

set_plugin_enabled(method_name, plugin_name, enabled=True)[source]
Parameters:
  • method_name (str)

  • plugin_name (str)

  • enabled (bool)

Return type:

None

set_runtime_data(method_name, plugin_name, key, value)[source]
Parameters:
  • method_name (str)

  • plugin_name (str)

  • key (str)

  • value (Any)

Return type:

None