Added per-instance state field documentation to ModuleContext reference.
@@ -27,12 +27,56 @@ async def setup(ctx: ModuleContext) -> None:
|
|||||||
| `routes` | `ModuleRoutes` | HTTP route registration and URL building ([details](Modules-Routes)). |
|
| `routes` | `ModuleRoutes` | HTTP route registration and URL building ([details](Modules-Routes)). |
|
||||||
| `http` | `HttpClient` | Shared HTTP client for external requests ([details](Modules-HTTP-Client)). |
|
| `http` | `HttpClient` | Shared HTTP client for external requests ([details](Modules-HTTP-Client)). |
|
||||||
| `admin_client` | `OwncastAdminClient \| None` | Owncast Admin API client, or `None` if admin is not enabled in config ([details](Modules-Owncast-API)). |
|
| `admin_client` | `OwncastAdminClient \| None` | Owncast Admin API client, or `None` if admin is not enabled in config ([details](Modules-Owncast-API)). |
|
||||||
|
| `state` | `dict[str, Any]` | Per-instance state storage for runtime objects. See [Per-Instance State](#per-instance-state) below. |
|
||||||
| `logger` | `logging.Logger` | Logger named `owlbot.modules.<module_name>`. Auto-derived from `module_name`. |
|
| `logger` | `logging.Logger` | Logger named `owlbot.modules.<module_name>`. Auto-derived from `module_name`. |
|
||||||
|
|
||||||
`ModuleContext` is a dataclass. All fields except `logger` are set during construction. `logger` is derived from `module_name` in `__post_init__`.
|
`ModuleContext` is a dataclass. All fields except `logger` are set during construction. `logger` is derived from `module_name` in `__post_init__`.
|
||||||
|
|
||||||
The service wrapper types (`ModuleCommands`, `ModuleEvents`, `ModuleRoutes`) are importable from `owlbot.api` for use in type annotations on helper functions:
|
The service wrapper types (`ModuleCommands`, `ModuleEvents`, `ModuleRoutes`) are importable from `owlbot.api` for use in type annotations on helper functions:
|
||||||
|
|
||||||
|
### Per-Instance State
|
||||||
|
|
||||||
|
Modules that need to hold in-memory runtime objects (managers, schedulers, caches) across handler invocations should use the `state` dict instead of module-level globals. This ensures multiple bot instances running in the same Python process maintain fully independent state.
|
||||||
|
|
||||||
|
Store objects during setup using string keys, and retrieve them in handlers via `ctx.module.state`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from owlbot.api import ModuleContext, on_setup, on_teardown
|
||||||
|
|
||||||
|
class MyManager:
|
||||||
|
"""Example stateful manager."""
|
||||||
|
def __init__(self, greeting: str) -> None:
|
||||||
|
self.greeting = greeting
|
||||||
|
|
||||||
|
@on_setup
|
||||||
|
async def setup(ctx: ModuleContext) -> None:
|
||||||
|
ctx.state["manager"] = MyManager(greeting="hello")
|
||||||
|
|
||||||
|
@on_teardown
|
||||||
|
async def teardown(ctx: ModuleContext) -> None:
|
||||||
|
ctx.state.pop("manager", None)
|
||||||
|
```
|
||||||
|
|
||||||
|
For type safety, wrap access in a typed helper function. The `isinstance` check narrows the return type so callers get full type information:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from owlbot.api import CommandContext, ModuleContext, on_command
|
||||||
|
|
||||||
|
|
||||||
|
def get_manager(ctx: ModuleContext) -> MyManager:
|
||||||
|
"""Return the MyManager for this module instance."""
|
||||||
|
manager = ctx.state.get("manager")
|
||||||
|
if not isinstance(manager, MyManager):
|
||||||
|
raise RuntimeError("MyManager is not initialized.")
|
||||||
|
return manager
|
||||||
|
|
||||||
|
|
||||||
|
@on_command("greet")
|
||||||
|
async def greet(ctx: CommandContext) -> None:
|
||||||
|
manager = get_manager(ctx.module) # Fully typed as MyManager
|
||||||
|
await ctx.owncast_client.send_message(manager.greeting)
|
||||||
|
```
|
||||||
|
|
||||||
## EventContext\[E\]
|
## EventContext\[E\]
|
||||||
|
|
||||||
Event handlers receive an `EventContext` parameterized by the event type. It wraps the event data and provides access to all services from `ModuleContext`:
|
Event handlers receive an `EventContext` parameterized by the event type. It wraps the event data and provides access to all services from `ModuleContext`:
|
||||||
|
|||||||
Reference in New Issue
Block a user