[grpcio] Type async handler factories and mixed aio interceptor chains by Mogost · Pull Request #16580 · python/typeshed · GitHub
Skip to content

[grpcio] Type async handler factories and mixed aio interceptor chains - #16580

Open
Mogost wants to merge 4 commits into
python:mainfrom
Mogost:fix/grpc-aio-handlers
Open

Mogost wants to merge 4 commits into
python:mainfrom
Mogost:fix/grpc-aio-handlers

Conversation

@Mogost

@Mogost Mogost commented Oct 20, 2026

Copy link
Copy Markdown

Fixes #15495.
Closes #16461.

Builds on @wolfgang-aura's work in #16461, extending it to handler factories and registration while accounting for synchronous handlers in aio interceptor chains.

An aio server can run both synchronous and asynchronous handlers. Its interceptor continuation returns the original handler without adapting its behavior, so the return type must allow both. Synchronous handlers are dispatched through a thread pool.

This PR:

  • Adds async overloads for all four RPC handler factories, including streaming handlers that use context.write().
  • Preserves handler types through generic handler registration, with synchronous defaults for existing users.
  • Accepts both handler types in aio generic and registered method handlers.
  • Types aio interceptor continuations and return values as synchronous or asynchronous handlers.
  • Adds regression cases for factory inference, custom generic handlers, mixed registration, and an interceptor that checks the handler before awaiting it.

The private, type-check-only _AsyncRpcMethodHandler follows the naming guidance from the review of #15497.

Runtime references:

Copilot AI balanced review requested due to automatic review settings October 20, 2026 19:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Async-first overloads can misclassify dynamically typed synchronous callbacks, compromising synchronous registration compatibility.

1 open issue
What changed in this PR

Extends grpcio stubs to support asynchronous handler factories and mixed synchronous/asynchronous aio interceptor chains.

Changes:

  • Adds async overloads for all four handler factories.
  • Preserves handler types through generic registration and expands aio handler support.
  • Adds regression cases for inference, registration, and interceptor wrapping.
File Description
stubs/​grpcio/​grpc/​aio/​__init__.pyi Models async handlers and mixed aio registration and interception.
stubs/​grpcio/​grpc/​__init__.pyi Adds async factory overloads and generic handler typing.
stubs/​grpcio/​@tests/​test_cases/​check_server_interceptor.py Covers mixed-handler continuations and async wrapping.
stubs/​grpcio/​@tests/​test_cases/​check_rpc_method_handlers.py Covers factory inference and handler registration.

Review effort: Balanced

Comment thread stubs/grpcio/grpc/__init__.pyi
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Support async factories, generic and registered handlers, and mixed
sync/async interceptor continuations while retaining sync defaults.

Builds on the async handler helper introduced by wolfgang-aura in
python#16461, with a mixed-handler continuation contract.
Prefer synchronous signatures when a response serializer is supplied.
Keep callbacks with insufficient type information gradual instead of
inferring an incorrect synchronous or asynchronous handler type.

Cover all four factories, keyword serializers, raw callbacks, and
partially annotated async behaviors in regression tests.
@Mogost
Mogost force-pushed the fix/grpc-aio-handlers branch from 3c5c1c3 to 93bc2b4 Compare October 21, 2026 08:59
@github-actions

This comment has been minimized.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Optional serializers can still cause synchronous streaming callbacks to be inferred as asynchronous handlers.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread stubs/grpcio/grpc/__init__.pyi Outdated
Apply the gradual overload to optional response serializers in all four
factories so Any-typed synchronous callbacks remain registrable.

Cover optional codecs and keyword serializers without contextual handler
types, and preserve precise inference for explicitly typed aio callbacks.
@github-actions

This comment has been minimized.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Factory overloads can erase synchronous handler types or misclassify asynchronous callbacks as synchronous.

No open issues 🎉

2 previously missed issues

In code that hasn't changed since last review

Medium severity Serializer overload misclassifies asynchronous callbacks as synchronous

stubs/​grpcio/​grpc/​__init__.pyi:166

A non-None serializer does not always distinguish synchronous from asynchronous callbacks. Calling this factory with the test's partial_async_unary and a Callable[[object], bytes] serializer matches this first synchronous overload: the callback accepts the synchronous context through Any, and _TResponse can accommodate its coroutine return. The result is classified as RpcMethodHandler, incorrectly allowing synchronous-server registration. The positional and keyword-only overloads have this problem; stream_unary_rpc_method_handler also has it when both callback inputs are typed Any. Handle awaitable-returning ambiguity before these synchronous overloads, retaining an unknown handler type where necessary without regressing Any-returning synchronous callbacks. Add regression cases using a serializer that accepts object.

Medium severity Any fallback misclassifies synchronous callbacks without codecs

stubs/​grpcio/​grpc/​__init__.pyi:173

The Any fallback also matches unambiguously synchronous callbacks. For example, a callback annotated (bytes, grpc.ServicerContext) -> bytes, passed without codecs, now returns Any instead of retaining the RpcMethodHandler interface. This disables checks on subsequent handler use. The corresponding overloads in all four factories have the same problem, including when the serializer is optional. Restrict these ambiguity overloads to callbacks accepting both context types, for example by using ServicerContext | aio.ServicerContext[_TRequest, _TResponse] for their context parameter, so synchronous-only callbacks reach the typed fallback. Add regression assertions for fully annotated synchronous callbacks without codecs.

1 resolved since last review

Review effort: Balanced

Limit gradual inference to callbacks that accept both sync and aio inputs.
Keep typed synchronous handlers precise without codecs, and avoid treating
coroutines as synchronous responses when serializers accept object.

Remove serializer-specific overloads and cover both review regressions.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Overload resolution and generic registration compatibility need final human verification across supported type checkers.

No open issues 🎉

Review effort: Balanced

@github-actions

Copy link
Copy Markdown
Contributor

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

grpc.aio.ServerInterceptor is incompatible with async RPC methods

2 participants