Add firstresult=True and wrapper=True support to AHook async dispatch#258
Open
schuyler wants to merge 2 commits intonextline-dev:mainfrom
Open
Add firstresult=True and wrapper=True support to AHook async dispatch#258schuyler wants to merge 2 commits intonextline-dev:mainfrom
schuyler wants to merge 2 commits intonextline-dev:mainfrom
Conversation
apluggy's AHook dispatched all hooks through pluggy's _multicall, which returns a single coroutine (not a list) for firstresult=True hooks. asyncio.gather(*coro) then crashes with TypeError. Add _call_firstresult() that bypasses _multicall: detects firstresult via hook.spec.opts, iterates reversed(hook.get_hookimpls()) to match pluggy's execution order (tryfirst → plain → trylast), awaits each sequentially, and stops on the first non-None result. The firstresult=False path is unchanged.
Add _async_multicall to drive sync-generator wrappers around async non-wrapper hookimpls. Wrappers yield once and receive the aggregate result (or exception) via send/throw, matching pluggy's protocol. AHook.__getattr__ now routes through _async_multicall when any wrapper hookimpl is present, preserving the existing gather and firstresult fast paths for the common no-wrapper case.
AHook async dispatch for firstresult=True hooks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two related additions to
AHookasync dispatch, building on each other:1.
firstresult=TruesupportAHook.__getattr__crashes on any async hook withfirstresult=True—_multicallreturns a single coroutine, andasyncio.gather(*coro)raisesTypeError. This adds_call_firstresult()to bypass_multicalland drive dispatch manually: iteratereversed(hookimpls), await each sequentially, return the first non-None result.9 tests in
tests/wrap/test_ahook_firstresult.py.2.
wrapper=TruesupportAdds
_async_multicall()to handlewrapper=Truehookimpls — sync generator wrappers that form middleware chains around async non-wrappers. Wrappers yield once, receive the aggregate result (or exception) viasend/throw, and return a (possibly modified) result viaStopIteration.value. This matches pluggy's protocol exactly.AHook.__getattr__now has three dispatch paths:_async_multicall(handles both firstresult modes)firstresult=True→_call_firstresultfirstresult=False→hook()+asyncio.gather()(unchanged)17 tests in
tests/wrap/test_ahook_wrapper.py.Test plan
tests/wrap/)