API Reference
Below is the Sphinx API reference. For more context or quick-start guides, see:
Quick Start - Get started in 5 minutes
Basic Usage Guide - Core features with examples
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)
owneris required;NoneraisesValueError. Routers are bound to this instance and never re-bound. Every router is created by its owning RoutingClass (lazyrouteproperty) and registers itself with the owner; itsnameis always"route".description: optional human-readable description of this router’s purpose. Included innodes()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_callablecreates aMethodEntryand stores it in_entries._rebuild_handlersupdates each entry’shandlerattribute by passing through_wrap_handler(default: passthrough). Subclasses may inject middleware.
Lookup and execution
node(path, **kwargs)resolvespathusing best-match resolution. Returns aRouterNodewrapper 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 withentriesandrouterskeys only if non-empty. Output includesdescription(router’s description) andowner_doc(owner class docstring) for documentation purposes.Each entry may carry a dialect-neutral
resultblock{"schema": <json schema | None>, "media_type": <str | None>}describing the return type and declared media type. It is produced by the plugin-enabledRouter(from the pydanticresponse_schemaand@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:
RouterInterfacePlugin-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
@routedecorator. Useadd_entrydirectly 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:
- 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_parentis 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 fromnode().name (
str|None) – Alias in this router. For Router sources, defaults tosource.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_branchesand 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:
- 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
resultblock{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 aforbiddenfield 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 namedescription: Router description (if set)owner_doc: Owner class docstring (for documentation)router: Reference to this routerinstance: Owner instanceplugin_info: Plugin configuration infoentries: 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_requirednot_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 nodeerror: Error code (None if ok, else “not_found”, “not_authorized”, etc.)doc: Entry docstringmetadata: 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
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:
BaseRouterRouter 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
- 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:
- 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_kwas a list of dicts. All markers belong to the class’s single router (one router per RoutingClass).Explicit logical name: if
nameis provided, the payload setsentry_nameto that value. Otherwise the handler name defaults to the function name.Result media type: if
media_typeis provided (RFC 9110type/subtype, e.g."application/json"), it is stored undermetadata["meta"]["media_type"]and surfaced both at runtime (RouterNode.metadata) and in the neutralresultblock ofnodes().Extra
**kwargsare 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 viarouter.node("@endpoint_id").media_type (
str|None) – Optional result media type (RFC 9110type/subtype, e.g."application/json"). Stored undermetadata["meta"]["media_type"]; surfaced at runtime viaRouterNode.metadataand in the neutralresultblock ofnodes().**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:
objectMixin binding the instance to its single router.
Subclass this to get the
routerouter (created lazily) and theroutingconfiguration proxy.- 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. Whennameis given,child.routeis linked intoself.routeunder 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
CapabilitiesSetsubclass instance. Each capability is defined as a method decorated with@capabilitythat returnsTrueif 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:
BaseRouterRouter 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
- 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:
- 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