App
App base classes and configuration for building Home Assistant automations.
This module provides clean access to the app framework for creating both async and sync applications with typed configuration.
BlockingIOBehavior
Bases: StrEnum
Controls what happens when blocking I/O is detected on the shared event loop.
Source code in src/hassette/types/enums.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | |
IGNORE = auto()
class-attribute
instance-attribute
Suppress detection entirely — no warning AND no blocking_events row is written.
This is the deliberate exception to the persist-before-warn rule: IGNORE means
"I know this app blocks; treat it as if detection never fired," so there is no audit
trail for ignored events.
WARN = auto()
class-attribute
instance-attribute
Emit a HassetteBlockingIOWarning (default). Integrates with -W error.
ERROR = auto()
class-attribute
instance-attribute
Emit HassetteBlockingIOWarning in a form that filterwarnings("error") escalates
to a raised exception. Under normal filters, behaves identically to WARN — the framework
does not raise on its own; escalation requires the caller to install the error filter
(-W error, a pytest filterwarnings marker, or warnings.filterwarnings at startup).
The effect of escalation differs by detection tier:
- Tier 2 (call-site interception) detects before the blocking primitive runs, so an escalated warning raises at the call site and prevents the blocking call from executing.
- Tier 1 (loop watchdog) is warn-after: the stall has already completed when the warning
fires on the off-loop daemon thread. The daemon suppresses the escalation to stay alive, so
ERRORcannot retroactively interrupt a Tier 1 stall — it only records and warns.
ForgottenAwaitBehavior
Bases: StrEnum
Controls what happens when a protected method is called without await.
Source code in src/hassette/types/enums.py
4 5 6 7 8 9 10 11 12 13 14 15 | |
IGNORE = auto()
class-attribute
instance-attribute
Suppress the warning entirely — the forgotten await is silently ignored.
WARN = auto()
class-attribute
instance-attribute
Emit a HassetteForgottenAwaitWarning (default). Integrates with -W error.
ERROR = auto()
class-attribute
instance-attribute
Emit HassetteForgottenAwaitWarning in a form that filterwarnings("error") escalates
to a raised exception. Under normal filters, behaves identically to WARN.
App
Bases: Generic[AppConfigT], Resource
Base class for applications in the Hassette framework.
This class provides a structure for applications, allowing them to be initialized and managed
within the Hassette ecosystem. Lifecycle will generally be managed for you via the service status events,
which send an event to the Bus and set the status attribute, based on the app's lifecycle.
Source code in src/hassette/app/app.py
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | |
default_cache_ttl: int | None = None
class-attribute
Default TTL (seconds) for this app's cache entries. Falls back to
hassette.config.default_cache_ttl when unset, and to no expiration when both are unset.
role: ResourceRole = ResourceRole.APP
class-attribute
Role of the resource, e.g. 'App', 'Service', etc.
app_manifest: AppManifest | None = app_manifest
instance-attribute
Manifest describing this app instance, set at construction from its config section.
Stored per instance, not on the class: two config sections can point at the same App subclass, so each instance carries its own manifest rather than reading a class-shared one — otherwise the section loaded last would overwrite display_name, enabled, and auto_loaded for every instance. Mirrors how app_key is stored per instance. None only when an App is constructed directly without a manifest; the factory and the test harness both pass one.
app_config_cls: type[AppConfig]
class-attribute
Config class to use for instances of the created app. Configuration from hassette.toml or other sources will be validated by this class.
logger: Logger
instance-attribute
Logger for the instance.
api: Api = cast('Api', self.add_child(api_factory or Api))
instance-attribute
API instance for interacting with Home Assistant.
scheduler: Scheduler = self.add_child(Scheduler)
instance-attribute
Scheduler instance for scheduled tasks owned by this app.
bus: Bus = self.add_child(Bus, priority=0)
instance-attribute
Event bus instance for event handlers owned by this app.
states: StateManager = self.add_child(StateManager)
instance-attribute
States manager instance for accessing Home Assistant states.
app_config: AppConfigT = app_config
instance-attribute
Configuration for this app instance.
index: int = index
instance-attribute
Index of this app instance, used for unique naming.
cache: CacheProtocol
instance-attribute
Cache instance for storing arbitrary data, scoped to this app instance.
unique_name: str
property
Unique name for the app instance, used for logging and ownership of resources.
config_log_level: LOG_LEVEL_TYPE
property
Return the log level from the config for this resource.
app_key: str
property
Key for this app in the hassette.toml configuration.
Set per instance at construction. Two config sections can point at the same App subclass, so each instance stores its own key — reading it from a class-shared attribute would let the last section loaded clobber it for all.
instance_name: str
property
Name for the instance of the app. Used for logging and ownership of resources.
cache_key: str
property
Key used to scope this app instance's cache directory.
Returns the manifest's explicit cache_key when set; otherwise defaults to
f"{app_key}/{index}" so each app instance gets its own cache directory.
now() -> ZonedDateTime
Return the current date and time.
Source code in src/hassette/app/app.py
223 224 225 | |
before_initialize() -> None
async
Optional: prepare to accept new work, allocate sockets, queues, temp files, etc.
Initializes the cache (opens connections, creates schema, checks integrity) when
it is a real AsyncCache. When a cache was injected via the constructor (e.g. a
DummyCache in tests), initialization is skipped -- DummyCache.initialize()
is a no-op, but the guard avoids the call entirely for clarity.
Source code in src/hassette/app/app.py
227 228 229 230 231 232 233 234 235 236 | |
cleanup(timeout: float | None = None) -> None
async
Cleanup resources owned by the instance.
This method is called during shutdown to cancel tasks and close caches. Child cleanup (Bus, Scheduler, etc.) is handled by _finalize_shutdown() propagation, not by this method.
Source code in src/hassette/app/app.py
238 239 240 241 242 243 244 245 246 247 248 249 250 251 | |
AppSync
Bases: App[AppConfigT]
Synchronous adapter for App.
Source code in src/hassette/app/app.py
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | |
before_shutdown() -> None
async
Optional: stop accepting new work, signal loops to wind down, etc.
Source code in src/hassette/app/app.py
260 261 262 263 | |
on_shutdown() -> None
async
Primary hook: release your own stuff (sockets, queues, temp files…).
Source code in src/hassette/app/app.py
265 266 267 268 | |
after_shutdown() -> None
async
Optional: last-chance actions after on_shutdown, before cleanup/STOPPED.
Source code in src/hassette/app/app.py
270 271 272 273 | |
before_initialize() -> None
async
Optional: prepare to accept new work, allocate sockets, queues, temp files, etc.
Source code in src/hassette/app/app.py
275 276 277 278 279 | |
on_initialize() -> None
async
Primary hook: perform your own initialization (sockets, queues, temp files…).
Source code in src/hassette/app/app.py
281 282 283 284 | |
after_initialize() -> None
async
Optional: finalize initialization, signal readiness, etc.
Source code in src/hassette/app/app.py
286 287 288 289 | |
before_shutdown_sync() -> None
Optional: stop accepting new work, signal loops to wind down, etc.
Source code in src/hassette/app/app.py
291 292 293 | |
on_shutdown_sync() -> None
Primary hook: release your own stuff (sockets, queues, temp files…).
Source code in src/hassette/app/app.py
295 296 297 | |
after_shutdown_sync() -> None
Optional: last-chance actions after on_shutdown, before cleanup/STOPPED.
Source code in src/hassette/app/app.py
299 300 301 | |
before_initialize_sync() -> None
Optional: prepare to accept new work, allocate sockets, queues, temp files, etc.
Source code in src/hassette/app/app.py
303 304 305 | |
on_initialize_sync() -> None
Primary hook: perform your own initialization (sockets, queues, temp files…).
Source code in src/hassette/app/app.py
307 308 309 | |
after_initialize_sync() -> None
Optional: finalize initialization, signal readiness, etc.
Source code in src/hassette/app/app.py
311 312 313 | |
initialize_sync() -> None
Use on_initialize_sync instead.
Source code in src/hassette/app/app.py
315 316 317 318 | |
shutdown_sync() -> None
Use on_shutdown_sync instead.
Source code in src/hassette/app/app.py
320 321 322 323 | |
AppConfig
Bases: BaseSettings
Base configuration class for applications in the Hassette framework.
This default class allows all extras, so arbitrary additional configuration data can be passed without needing to define a custom subclass, at the cost of type safety.
Fields can be set on subclasses and extra can be overridden by assigning a new value to model_config.
Source code in src/hassette/app/app_config.py
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
instance_name: str = ''
class-attribute
instance-attribute
Name for the instance of the app.
log_level: LOG_LEVEL_TYPE = Field(default_factory=log_level_default_factory)
class-attribute
instance-attribute
Log level for the app instance. Defaults to INFO if not provided.
app_key: str = ''
class-attribute
instance-attribute
Configuration-level app key. Reserved: 'hassette' and 'hassette.*' prefixes are rejected.
forgotten_await_behavior: ForgottenAwaitBehavior | None = None
class-attribute
instance-attribute
Per-app control for forgotten-await detection behavior.
When None (default), the global HassetteConfig.forgotten_await_behavior is used,
which itself defaults to "warn". Set to "ignore" to suppress warnings for this app,
or "error" to treat forgotten awaits as errors (escalated by filterwarnings("error")).
blocking_io_behavior: BlockingIOBehavior | None = None
class-attribute
instance-attribute
Per-app control for blocking-IO detection behavior.
When None (default), the global HassetteConfig.blocking_io.behavior is used,
which itself defaults to "warn". Set to "ignore" to suppress detection for this app,
or "error" to escalate via filterwarnings("error").
only_app(app_cls: type[AppT]) -> type[AppT]
Decorator to mark an app class as the only one to run. If more than one app is marked with this decorator, an exception will be raised during initialization.
This is useful for development and testing, where you may want to run only a specific app without modifying configuration files.
Source code in src/hassette/app/app.py
73 74 75 76 77 78 79 80 81 | |