Skip to content

Commit ab3a82b

Browse files
authored
Tighten on_error handler type to OrchestratorHookError (#23575)
* Fix on_error type to OrchestratorHookError and remove None return types from tests * Add changelog * Make on_error and _apply_error_policy generic over wrapped error type Codex flagged that _apply_error_policy is also called from _task_wrapper with MessageProcessingError and ProcessorHookError, so narrowing it to OrchestratorHookError broke mypy. Make it generic on E: Exception and turn ErrorHandler into a generic alias so each scope keeps the relationship between the wrapped-error type and its handler. Tighten BaseProcessor.on_error to MessageProcessingError | ProcessorHookError to match its actual contract.
1 parent 452d7d2 commit ab3a82b

3 files changed

Lines changed: 54 additions & 57 deletions

File tree

ddev/changelog.d/23575.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix type annotation of on_error in the EventBusOrchestrator by narrowing it down to OrchestratorHookError. This better represents the actual error passed to the method.

ddev/src/ddev/event_bus/orchestrator.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from collections.abc import Awaitable, Callable
1111
from concurrent.futures import Executor, ThreadPoolExecutor
1212
from dataclasses import dataclass
13-
from typing import assert_never
13+
from typing import assert_never, cast
1414

1515
from .exceptions import (
1616
FatalProcessingError,
@@ -22,7 +22,7 @@
2222
SkipMessageError,
2323
)
2424

25-
ErrorHandler = Callable[[Exception], Awaitable[None]]
25+
type ErrorHandler[E: Exception] = Callable[[E], Awaitable[None]]
2626

2727

2828
@dataclass
@@ -44,7 +44,7 @@ def __init__(self, name: str):
4444
async def on_success(self, message: T) -> None:
4545
pass
4646

47-
async def on_error(self, error: Exception) -> None:
47+
async def on_error(self, error: MessageProcessingError | ProcessorHookError) -> None:
4848
"""
4949
Handle a processor-scoped failure.
5050
@@ -232,7 +232,7 @@ async def on_message_received(self, message: BaseMessage): # pragma: no cover
232232
"""
233233
pass
234234

235-
async def on_error(self, error: Exception) -> None:
235+
async def on_error(self, error: OrchestratorHookError) -> None:
236236
"""
237237
Handle an orchestrator-scoped failure.
238238
@@ -251,7 +251,7 @@ async def on_error(self, error: Exception) -> None:
251251
"""
252252
raise error
253253

254-
async def _apply_error_policy(self, wrapped_error: Exception, handler: ErrorHandler) -> None:
254+
async def _apply_error_policy[E: Exception](self, wrapped_error: E, handler: ErrorHandler[E]) -> None:
255255
"""
256256
Routes ``wrapped_error`` through ``handler`` and applies the orchestrator's policy.
257257
@@ -460,7 +460,7 @@ async def _task_wrapper(self, processor: Processor, message: BaseMessage):
460460
try:
461461
match processor:
462462
case AsyncProcessor():
463-
await processor.process_message(message)
463+
await cast(AsyncProcessor, processor).process_message(message)
464464
case SyncProcessor():
465465
await asyncio.get_running_loop().run_in_executor(self._executor, processor.process_message, message)
466466
case _:

0 commit comments

Comments
 (0)