API Reference

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

Plugin-free router runtime for Genro Routes.

This module exposes BaseRouter, which binds methods on an object instance, resolves path selectors (using ‘/’ separator), and exposes rich introspection without any plugin logic. Subclasses add middleware but must preserve these semantics.

Constructor and slots

Constructor signature:

BaseRouter(owner, *, prefix=None, description=None,
           default_entry="index", get_default_handler=None,
           get_kwargs=None)
  • owner is required; None raises ValueError. Routers are bound to this instance and never re-bound. Every router is created by its owning RoutingClass (lazy route property) and registers itself with the owner; its name is always "route".

  • description: optional human-readable description of this router’s purpose. Included in nodes() output for documentation/introspection.

  • default_entry: the fallback entry name (default: “index”) used when a path cannot be fully resolved. The router returns this entry with any unconsumed path segments passed as positional arguments when invoked.

  • Slots: instance, name, prefix, description, default_entry, __entries_raw (logical name → MethodEntry with handler), _children (alias → child router), _get_defaults, _bound.

Lazy binding

Routers use lazy binding: methods decorated with @route are discovered and registered automatically on first use (node/nodes). No explicit bind() call is needed.

Marker discovery

_iter_marked_methods walks the MRO of type(owner) (child classes first, so derived overrides win), scans __dict__ for plain functions carrying _route_decorator_kw markers. All markers belong to this router.

Handler table and wrapping

  • _register_callable creates a MethodEntry and stores it in _entries.

  • _rebuild_handlers updates each entry’s handler attribute by passing through _wrap_handler (default: passthrough). Subclasses may inject middleware.

Lookup and execution

  • node(path, **kwargs) resolves path using best-match resolution. Returns a RouterNode wrapper that is callable. The RouterNode contains metadata about the resolved entry. Unconsumed path segments are passed as positional arguments when the node is invoked.

Children (instance hierarchies)

include(source, name=...) links a Router or RouterNode into this router. Accepts a Router (child hierarchy) or RouterNode (entry alias).

detach_instance(child) removes all routers belonging to a child instance.

Instance attachment is handled by RoutingClass.attach_instance(), which sets _routing_parent and delegates the routing link to include(). On the first (primary) attachment include() triggers plugin inheritance via _on_attached_to_parent; subsequent includes of the same router are navigational shortcuts only.

Introspection

  • nodes(**kwargs) builds a nested dict of routers and entries respecting filters. Returns dict with entries and routers keys only if non-empty. Output includes description (router’s description) and owner_doc (owner class docstring) for documentation purposes.

  • Each entry may carry a dialect-neutral result block {"schema": <json schema | None>, "media_type": <str | None>} describing the return type and declared media type. It is produced by the plugin-enabled Router (from the pydantic response_schema and @route(media_type=...)) so OpenAPI/MCP translators read it instead of re-deriving the output.

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 a child router is linked into this router.

  • _describe_entry_extra: allow subclasses to extend per-entry description.

class genro_routes.core.base_router.BaseRouter(owner, *, prefix=None, description=None, default_entry='index', get_default_handler=None, get_kwargs=None)[source]

Bases: RouterInterface

Plugin-free router bound to an object instance.

Responsibilities:
  • Register bound methods/functions with logical names (optionally via markers)

  • Resolve path selectors (using ‘/’ separator) across child routers

  • Expose handler tables and introspection data

  • Provide hooks for subclasses to wrap handlers or filter introspection

Parameters:
  • owner (Any)

  • prefix (str | None)

  • description (str | None)

  • default_entry (str)

  • get_default_handler (Callable | None)

  • get_kwargs (dict[str, Any] | None)

__init__(owner, *, prefix=None, description=None, default_entry='index', get_default_handler=None, get_kwargs=None)[source]
Parameters:
  • owner (Any)

  • prefix (str | None)

  • description (str | None)

  • default_entry (str)

  • get_default_handler (Callable | None)

  • get_kwargs (dict[str, Any] | None)

instance
name: str | None
prefix
description
default_entry
property current_capabilities: set[str]

Collect capabilities from instance and parent chain.

Walks up the _routing_parent chain accumulating capabilities from each RoutingClass instance.

Returns:

Combined set of capabilities from all instances in the hierarchy.

add_entry(target, *, name=None, metadata=None, replace=False, **options)[source]

Register handler(s) on this router.

Note

For most use cases, prefer the @route decorator. Use add_entry directly only for dynamic registration (e.g., introspection-based mapping of external libraries).

Parameters:
  • target (Any) – Callable, attribute name(s), comma-separated string, or wildcard marker.

  • name (str | None) – Logical name override for this entry.

  • metadata (dict[str, Any] | None) – 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.

include(source, *, name=None)[source]

Include a Router or RouterNode (entry alias) into this router.

Accepts two source types:

  • Router: links the source router as a child of this router. Plugin inheritance is triggered via _on_attached_to_parent. If the source router belongs to a RoutingClass, _routing_parent is set on the owner.

  • RouterNode: creates an alias for a single entry in this router. The original handler is shared — no copy is made.

Parameters:
  • source (Any) – A Router instance or a RouterNode from node().

  • name (str | None) – Alias in this router. For Router sources, defaults to source.name. For RouterNode sources, required.

Raises:
  • TypeError – If source is not a Router or RouterNode.

  • ValueError – If name is required but not provided.

  • ValueError – If alias collision in _children or _entries.

Return type:

None

Examples:

# Include a router
self._sys.include(swagger.route, name="swagger")

# Include an entry as alias
fatture.route.include(
    pagamenti.route.node("collega_a_fattura"),
    name="collega_pagamento",
)
add_branches(specs)[source]

Declare one or more child branches as factory specs.

Accepts a single spec dict, a list of dicts, or any iterable/generator of dicts. Each spec is {"name", "lazy", "cls", "params"}. Nothing is constructed here — specs are stored in _branches and materialized later (eager at first tree access, lazy on first traversal).

Parameters:

specs (Any)

Return type:

None

remove_branch(name)[source]

Remove a declared branch. If already materialized, detach its child.

Parameters:

name (str)

Return type:

None

property branches: dict[str, dict[str, Any]]

Read-only view of declared (not-yet-materialized) branch specs.

detach_instance(routing_child)[source]

Detach all routers belonging to a RoutingClass instance.

Parameters:

routing_child (Any)

Return type:

BaseRouter

get_url(path, **kwargs)[source]

Build a URL path for a handler, appending positional parameters.

Accepts a path (e.g., "users/detail") or an endpoint_id with @ prefix (e.g., "@invoice.detail"). Keyword arguments that match positional parameters in the handler’s signature are appended as path segments in declaration order.

Parameters:
  • path (str) – Handler path or "@endpoint_id".

  • **kwargs (Any) – Parameter values to append to the path. Only positional-or-keyword parameters are appended (in declaration order). Keyword-only parameters are ignored.

Return type:

str

Returns:

The full URL path string.

Raises:

ValueError – If the path does not resolve to a valid handler.

Example:

# Given: @route(endpoint_id="invoice.detail")
#        def detail(self, invoice_id): ...
# Mounted at: billing/detail

router.get_url("@invoice.detail", invoice_id=123)
# → "billing/detail/123"

router.get_url("billing/detail", invoice_id=123)
# → "billing/detail/123"
router_at_path(path, _alias_seen=None)[source]

Find the router at the given path.

Parameters:
  • path (str) – Path to navigate (e.g., “child/grandchild”).

  • _alias_seen (frozenset[int] | None) – Internal — alias spec ids already followed (cycle guard).

Return type:

BaseRouter | None

Returns:

The router at the path, or None if not found.

nodes(basepath=None, lazy=False, pattern=None, forbidden=False, _eager=False, _alias_seen=None, **kwargs)[source]

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

Output is dialect-neutral: each entry carries name/doc/metadata, plugin config, and (when available) a result block {schema, media_type}. Dialect translators (OpenAPI, MCP) are readers of this tree and live in the transport layer, not in the routing core.

Parameters:
  • basepath (str | None) – Optional path to start from (e.g., “child/grandchild”). If provided, returns nodes starting from that point in the hierarchy instead of from this router.

  • lazy (bool) – If True, child routers are returned as router references instead of recursively expanded. Use basepath to navigate and expand specific children on demand.

  • pattern (str | None) – Optional regex pattern to filter entry names. Only entries whose name matches the pattern are included. Applied before plugin deny_reason() checks.

  • forbidden (bool) – If True, include entries that are not allowed (e.g., due to authorization or capability requirements). These entries will have a forbidden field with the reason (e.g., “not_authorized”, “not_available”). Default False.

  • _eager (bool) – If True, expand EVERYTHING: materialize all declared lazy branches and resolve alias branches to their target subtree. Default False: lazy branches and aliases appear as unresolved markers, nothing is constructed.

  • _alias_seen (frozenset[int] | None) – Internal — alias spec ids already expanded (cycle guard).

  • **kwargs (Any) – Filter arguments passed to plugins via deny_reason().

Returns:

  • name: Router name

  • description: Router description (if set)

  • owner_doc: Owner class docstring (for documentation)

  • router: Reference to this router

  • instance: Owner instance

  • plugin_info: Plugin configuration info

  • entries: Dict of entry names to entry info (if any)

  • routers: Dict of child names to child nodes (if any)

Return type:

A dict containing

node(path, errors=None, **kwargs)[source]

Return info about a single node (router or entry) at the given path.

Unlike nodes() which returns the full subtree, this method returns information about just one specific node without recursion.

This method always performs best-match resolution: it walks the path as far as possible, tracking the last valid callable node (entry or router with default_entry). If the exact path is not found, it falls back to that last valid node and passes unconsumed path segments as positional arguments when the node is invoked.

The returned RouterNode is callable - invoking it executes the handler.

Parameters:
  • path (str) – Path to the node (e.g., “entry_name” or “child/grandchild/entry”).

  • errors (dict[str, type[Exception]] | None) –

    Optional dict mapping error codes to custom exception classes. Available codes (see RouterNode.ERROR_CODES):

    • not_found: Path not found or varargs_required

    • not_authorized: Auth tags don’t match (403)

    • not_authenticated: Auth required but not provided (401)

    • validation_error: Bad arguments - pydantic validation failed or arguments were unbindable (TypeError)

    Example:

    node = router.node("handler", errors={
        'not_found': HTTPNotFound,
        'not_authorized': HTTPForbidden,
    })
    

  • **kwargs (Any) – Plugin-prefixed filter kwargs (e.g., auth_tags=”x”).

Returns:

  • path: Full path to this node
    • error: Error code (None if ok, else “not_found”, “not_authorized”, etc.)

    • doc: Entry docstring

    • metadata: Entry metadata dict

The RouterNode is callable:

node = router.node("my_handler")
result = node()  # Invoke the handler

If error is set, calling the node raises the mapped exception.

Return type:

A RouterNode with these public properties

iter_plugins()[source]
Return type:

list[Any]

Router with plugin pipeline for Genro Routes.

Router extends BaseRouter with a global plugin registry, per-router plugin instances, middleware wrapping, and plugin state stored on the router.

Internal state

  • _plugin_specs: list of _PluginSpec (factory, kwargs copy).

  • _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.

Attaching plugins

plug(plugin_name, **config) looks up the plugin class by name in the global registry. It stores a _PluginSpec, instantiates the plugin, appends to _plugins and _plugins_by_name, applies plugin.on_decore to all existing entries, rebuilds handlers, and returns self.

Wrapping pipeline

_wrap_handler(entry, call_next) builds middleware layers from the current _plugins in reverse order (last attached closest to the handler).

Inheritance behaviour

_on_attached_to_parent(parent) runs when a child router is attached. Parent specs are cloned once per parent. Cloned specs are instantiated into new plugins that are prepended ahead of existing child plugins.

Example:

from genro_routes import Router, RoutingClass, route

class MyService(RoutingClass):
    def __init__(self):
        self.route.plug("logging")

    @route()
    def hello(self):
        return "Hello!"
class genro_routes.core.router.Router(*args, **kwargs)[source]

Bases: BaseRouter

Router with plugin registry and pipeline support.

Extends BaseRouter with:
  • Global plugin registry for registering plugin classes

  • Per-router plugin instances with middleware wrapping

  • Plugin state management and configuration

  • Plugin inheritance when attaching child routers

__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 (str | None) – Optional override name. If provided, overwrites any existing registration. If not provided, uses plugin_code and raises if already registered with a different class.

Raises:
  • TypeError – If plugin_class is not a BasePlugin subclass.

  • ValueError – If plugin_code is missing or name collision occurs.

Return type:

None

classmethod available_plugins()[source]

Return a copy of the global plugin registry.

Return type:

dict[str, type[BasePlugin]]

plug(plugin, **config)[source]

Attach one or more plugins by name (previously registered globally).

Parameters:
  • plugin (str | list[dict[str, Any]]) – Either a plugin name (single attach) or a list of plugin dicts {"name": ..., <options>} (batch attach). Each dict carries the plugin name plus its own options; shared kwargs are not allowed with a list.

  • **config (Any) – Configuration options passed to the plugin (single form only).

Return type:

Router

Returns:

self (for method chaining).

Raises:
  • TypeError – If plugin is not a string or a list of dicts.

  • ValueError – If a plugin is not registered, already attached, a list is mixed with shared kwargs, or a dict lacks ‘name’.

iter_plugins()[source]

Return attached plugin instances in application order.

Return type:

list[BasePlugin]

get_config(plugin_name, method_name=None)[source]

Return merged plugin configuration.

Retrieves the effective configuration for a plugin, merging global (router-level) settings with optional per-handler overrides.

Parameters:
  • plugin_name (str) – Name of the attached plugin.

  • method_name (str | None) – If provided, includes handler-specific overrides merged on top of global config.

Return type:

dict[str, Any]

Returns:

Dict of configuration values. Per-handler values override global.

Raises:

AttributeError – If no plugin with that name is attached.

Example

>>> router.plug("logging")
>>> router.logging.configure(before=False)
>>> router.logging.configure(_target="slow_handler", after=True)
>>> router.get_config("logging")
{'enabled': True, 'before': False}
>>> router.get_config("logging", "slow_handler")
{'enabled': True, 'before': False, 'after': True}
__getattr__(name)[source]

Access attached plugins by name as attributes.

Enables fluent plugin configuration via attribute access syntax. Only works for attached plugins; other attribute access follows normal Python behavior.

Parameters:

name (str) – Plugin name (e.g., “logging”, “auth”, “pydantic”).

Return type:

Any

Returns:

The BasePlugin instance attached under that name.

Raises:

AttributeError – If no plugin with that name is attached.

Example

>>> router.plug("logging").plug("auth")
>>> router.logging.configure(before=False)
>>> router.auth.configure(rule="admin")
set_plugin_enabled(method_name, plugin_name, enabled=True)[source]

Enable or disable a plugin for a specific handler at runtime.

Sets a runtime override in the “locals” store, which takes precedence over static configuration. Use “_all_” as method_name to affect all handlers globally.

Parameters:
  • method_name (str) – Handler name or “_all_” for global setting.

  • plugin_name (str) – Name of the attached plugin.

  • enabled (bool) – True to enable, False to disable.

Raises:

AttributeError – If no plugin with that name is attached.

Return type:

None

Example

>>> router.set_plugin_enabled("slow_handler", "logging", False)
>>> router.set_plugin_enabled("_all_", "pydantic", False)
is_plugin_enabled(method_name, plugin_name)[source]

Check if a plugin is enabled for a specific handler.

Resolution order (first found wins): 1. entry locals (runtime override via set_plugin_enabled) 2. entry config (static via configure(_target=method_name, enabled=…)) 3. global locals (runtime override via set_plugin_enabled for _all_) 4. global config (static via configure(enabled=…)) 5. default: True

Parameters:
  • method_name (str)

  • plugin_name (str)

Return type:

bool

set_runtime_data(method_name, plugin_name, key, value)[source]

Store arbitrary runtime data for a plugin/handler combination.

Plugins can use this to store handler-specific state that persists across invocations but is not part of the configuration schema.

Parameters:
  • method_name (str) – Handler name or “_all_” for global data.

  • plugin_name (str) – Name of the attached plugin.

  • key (str) – Data key to store.

  • value (Any) – Value to store (any type).

Raises:

AttributeError – If no plugin with that name is attached.

Return type:

None

Example

>>> router.set_runtime_data("handler", "auth", "last_access", time.time())
get_runtime_data(method_name, plugin_name, key, default=None)[source]

Retrieve runtime data for a plugin/handler combination.

Parameters:
  • method_name (str) – Handler name or “_all_” for global data.

  • plugin_name (str) – Name of the attached plugin.

  • key (str) – Data key to retrieve.

  • default (Any) – Value to return if key not found.

Return type:

Any

Returns:

The stored value, or default if not found.

Raises:

AttributeError – If no plugin with that name is attached.

Example

>>> last = router.get_runtime_data("handler", "auth", "last_access")
instance
name: str | None
prefix
description
default_entry

Decorator helpers for marking routed methods.

This module contains only marker helpers; no router mutation happens at decoration time.

route(*, name=None, endpoint_id=None, media_type=None, **kwargs)

Returns a decorator storing metadata on the function under _route_decorator_kw as a list of dicts. All markers belong to the class’s single router (one router per RoutingClass).

  • Explicit logical name: if name is provided, the payload sets entry_name to that value. Otherwise the handler name defaults to the function name.

  • Result media type: if media_type is provided (RFC 9110 type/subtype, e.g. "application/json"), it is stored under metadata["meta"]["media_type"] and surfaced both at runtime (RouterNode.metadata) and in the neutral result block of nodes().

  • Extra **kwargs are copied verbatim into the payload (e.g. plugin flags).

  • Stacking the decorator registers the same function under multiple entry names (aliases).

  • The decorator returns the original function unchanged aside from the marker.

Re-exports

This module re-exports RoutingClass and Router for convenience so user code can import everything from one place.

genro_routes.core.decorators.route(*, name=None, endpoint_id=None, media_type=None, **kwargs)[source]

Mark a bound method for inclusion in the class’s router.

Parameters:
  • name (str | None) – Optional explicit entry name (overrides function name/prefix stripping).

  • endpoint_id (str | None) – Optional globally unique identifier for reverse lookup. When set, the handler can be resolved via router.node("@endpoint_id").

  • media_type (str | None) – Optional result media type (RFC 9110 type/subtype, e.g. "application/json"). Stored under metadata["meta"]["media_type"]; surfaced at runtime via RouterNode.metadata and in the neutral result block of nodes().

  • **kwargs (Any) – Extra metadata merged into handler entry (e.g. plugin flags).

Return type:

Callable[[Callable], Callable]

Returns:

Decorator that marks the function for the router.

Example:

class Table(RoutingClass):
    @route()
    def list_users(self):
        return ["alice", "bob"]

    @route(name="custom_name", logging_enabled=False)
    def get_user(self, user_id):
        return {"id": user_id}

    @route(media_type="text/html")
    def render(self):
        return "<h1>hi</h1>"
class genro_routes.core.decorators.RoutingClass[source]

Bases: object

Mixin binding the instance to its single router.

Subclass this to get the route router (created lazily) and the routing configuration proxy.

property route: Router

Return the instance’s router, creating it on first access.

add_branches(specs)[source]

Declare child branches (factory specs) on this instance’s router.

Accepts one spec dict, a list of dicts, or a generator. Each spec is {"name", "lazy", "cls", "params"}. Delegates to the router; nothing is constructed until materialization (see the Branches section above).

Parameters:

specs (Any)

Return type:

None

remove_branch(name)[source]

Remove a declared branch; detach its child if already materialized.

Parameters:

name (str)

Return type:

None

property branches: dict[str, dict[str, Any]]

Read-only view of declared (not-yet-materialized) branch specs.

attach_instance(child, *, name=None)[source]

Attach a child RoutingClass instance.

Sets child._routing_parent = self. When name is given, child.route is linked into self.route under that alias (plugin inheritance is triggered by the link).

Parameters:
  • child (RoutingClass) – The RoutingClass instance to attach.

  • name (str | None) – Alias under which the child’s router is reachable from this instance’s router. If omitted, only the parent relationship is set (no routing link).

Raises:
  • TypeError – If child is not a RoutingClass instance.

  • ValueError – If child is already bound to another parent.

  • ValueError – If the alias collides with an existing child.

Return type:

None

Example:

self.attach_instance(child, name="sales")
property routing: _RoutingProxy

Return a proxy for router configuration and lookup.

property ctx: RoutingContext | None

Return the execution context, walking up the parent chain.

property capabilities

Return the capabilities declared by this instance.

Capabilities represent what features/dependencies this service has available at runtime. Used by EnvPlugin to filter entries based on capability requirements.

Capabilities must be a CapabilitiesSet subclass instance. Each capability is defined as a method decorated with @capability that returns True if the capability is currently available.

Returns:

A CapabilitiesSet instance, or empty set if not configured.

Example:

from genro_routes.plugins.env import CapabilitiesSet, capability

class PaymentCapabilities(CapabilitiesSet):
    def __init__(self, service):
        self._service = service

    @capability
    def stripe(self) -> bool:
        return self._service._stripe_configured

    @capability
    def paypal(self) -> bool:
        return self._service._paypal_configured

class PaymentService(RoutingClass):
    def __init__(self):
        self.route.plug("env")
        self._stripe_configured = True
        self._paypal_configured = False
        self.capabilities = PaymentCapabilities(self)
result_wrapper(value, **metadata)[source]

Wrap a handler result with metadata.

Use this when a handler needs to return additional metadata (e.g., mime_type) along with the result value.

Parameters:
  • value (Any) – The actual result to return.

  • **metadata (Any) – Key-value pairs of metadata (e.g., mime_type=”text/html”).

Return type:

ResultWrapper

Returns:

A ResultWrapper instance containing value and metadata.

Example

@route() def _resource(self, name: str):

content, mime_type = self.load_resource(name) return self.result_wrapper(content, mime_type=mime_type)

class genro_routes.core.decorators.Router(*args, **kwargs)[source]

Bases: BaseRouter

Router with plugin registry and pipeline support.

Extends BaseRouter with:
  • Global plugin registry for registering plugin classes

  • Per-router plugin instances with middleware wrapping

  • Plugin state management and configuration

  • Plugin inheritance when attaching child routers

__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 (str | None) – Optional override name. If provided, overwrites any existing registration. If not provided, uses plugin_code and raises if already registered with a different class.

Raises:
  • TypeError – If plugin_class is not a BasePlugin subclass.

  • ValueError – If plugin_code is missing or name collision occurs.

Return type:

None

classmethod available_plugins()[source]

Return a copy of the global plugin registry.

Return type:

dict[str, type[BasePlugin]]

plug(plugin, **config)[source]

Attach one or more plugins by name (previously registered globally).

Parameters:
  • plugin (str | list[dict[str, Any]]) – Either a plugin name (single attach) or a list of plugin dicts {"name": ..., <options>} (batch attach). Each dict carries the plugin name plus its own options; shared kwargs are not allowed with a list.

  • **config (Any) – Configuration options passed to the plugin (single form only).

Return type:

Router

Returns:

self (for method chaining).

Raises:
  • TypeError – If plugin is not a string or a list of dicts.

  • ValueError – If a plugin is not registered, already attached, a list is mixed with shared kwargs, or a dict lacks ‘name’.

iter_plugins()[source]

Return attached plugin instances in application order.

Return type:

list[BasePlugin]

get_config(plugin_name, method_name=None)[source]

Return merged plugin configuration.

Retrieves the effective configuration for a plugin, merging global (router-level) settings with optional per-handler overrides.

Parameters:
  • plugin_name (str) – Name of the attached plugin.

  • method_name (str | None) – If provided, includes handler-specific overrides merged on top of global config.

Return type:

dict[str, Any]

Returns:

Dict of configuration values. Per-handler values override global.

Raises:

AttributeError – If no plugin with that name is attached.

Example

>>> router.plug("logging")
>>> router.logging.configure(before=False)
>>> router.logging.configure(_target="slow_handler", after=True)
>>> router.get_config("logging")
{'enabled': True, 'before': False}
>>> router.get_config("logging", "slow_handler")
{'enabled': True, 'before': False, 'after': True}
__getattr__(name)[source]

Access attached plugins by name as attributes.

Enables fluent plugin configuration via attribute access syntax. Only works for attached plugins; other attribute access follows normal Python behavior.

Parameters:

name (str) – Plugin name (e.g., “logging”, “auth”, “pydantic”).

Return type:

Any

Returns:

The BasePlugin instance attached under that name.

Raises:

AttributeError – If no plugin with that name is attached.

Example

>>> router.plug("logging").plug("auth")
>>> router.logging.configure(before=False)
>>> router.auth.configure(rule="admin")
set_plugin_enabled(method_name, plugin_name, enabled=True)[source]

Enable or disable a plugin for a specific handler at runtime.

Sets a runtime override in the “locals” store, which takes precedence over static configuration. Use “_all_” as method_name to affect all handlers globally.

Parameters:
  • method_name (str) – Handler name or “_all_” for global setting.

  • plugin_name (str) – Name of the attached plugin.

  • enabled (bool) – True to enable, False to disable.

Raises:

AttributeError – If no plugin with that name is attached.

Return type:

None

Example

>>> router.set_plugin_enabled("slow_handler", "logging", False)
>>> router.set_plugin_enabled("_all_", "pydantic", False)
is_plugin_enabled(method_name, plugin_name)[source]

Check if a plugin is enabled for a specific handler.

Resolution order (first found wins): 1. entry locals (runtime override via set_plugin_enabled) 2. entry config (static via configure(_target=method_name, enabled=…)) 3. global locals (runtime override via set_plugin_enabled for _all_) 4. global config (static via configure(enabled=…)) 5. default: True

Parameters:
  • method_name (str)

  • plugin_name (str)

Return type:

bool

set_runtime_data(method_name, plugin_name, key, value)[source]

Store arbitrary runtime data for a plugin/handler combination.

Plugins can use this to store handler-specific state that persists across invocations but is not part of the configuration schema.

Parameters:
  • method_name (str) – Handler name or “_all_” for global data.

  • plugin_name (str) – Name of the attached plugin.

  • key (str) – Data key to store.

  • value (Any) – Value to store (any type).

Raises:

AttributeError – If no plugin with that name is attached.

Return type:

None

Example

>>> router.set_runtime_data("handler", "auth", "last_access", time.time())
get_runtime_data(method_name, plugin_name, key, default=None)[source]

Retrieve runtime data for a plugin/handler combination.

Parameters:
  • method_name (str) – Handler name or “_all_” for global data.

  • plugin_name (str) – Name of the attached plugin.

  • key (str) – Data key to retrieve.

  • default (Any) – Value to return if key not found.

Return type:

Any

Returns:

The stored value, or default if not found.

Raises:

AttributeError – If no plugin with that name is attached.

Example

>>> last = router.get_runtime_data("handler", "auth", "last_access")
instance
name: str | None
prefix
description
default_entry