Closed
Description
In #257, @maxnikulin brought up an idea which seems very natural but hasn't occurred to me beforehand. I think it will at least be interesting to discuss it on its own.
Background
_Result
is used in hookwrappers as follows (using imaginary type annotations for clarity):
from typing import Generator, TypeVar
T = TypeVar("T")
E = TypeVar("E")
@hookimpl(hookwrapper=True)
def my_hook() -> Generator[None, _Result[T, E], None]:
# ... Some setup code ...
result = yield
try:
value = result.get_result()
except Exception as exc:
# ... Use exc ...
else:
# ... Use value ...
# ... Some teardown code ...
The result
has three use cases:
- Fetch the return value[s] of the hook, if it didn't raise.
- Fetch the exception of the hook, if it did raise.
- Override (force) the return value/exception to some other return value.
Idea
Python coroutines already provide a way to distinguish between a successful yield
(-> coroutine.send(value)
) and a throwing yield
(-> coroutine.throw(exc)
). So in the above, the _Result
indirection could have been dispensed with:
@hookimpl(imaginary_hookwrapper=True)
def my_hook() -> Generator[None, T, None]:
# ... Some setup code ...
try:
value = yield
except Exception as exc:
# ... Use exc ...
else:
# ... Use value ...
# ... Some teardown code ...
This handles use cases 1 & 2. Regarding use case 3 (forcing a result), use the coroutine return value:
@hookimpl(imaginary_hookwrapper=True)
def my_hook() -> Generator[None, T, T]:
# ... Some setup code ...
try:
value = yield
except Exception as exc:
# ... Use exc ...
else:
# ... Use value ...
# ... Some teardown code ...
return new_value
Metadata
Metadata
Assignees
Labels
No labels