Skip to content

Unexpected type arguments in generated code for synchronous UnaryUnaryMultiCallable #629

@ArthurBook

Description

@ArthurBook

Hi, thanks for the work on this project. It really improves the development workflow to have the proto and grpc interfaces recognizable by the language server (vscode pyright in my case).

The confusion / bug

When inspecting the generated .pyi file, I notice that the method type referenced in the client stub: grpc.UnaryUnaryMultiCallable is hinted with two type parameters:

class Service1Stub:
    def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ...
    GetUser: grpc.UnaryUnaryMultiCallable[
        service_pb2.GetUserRequest,
        service_pb2.GetUserResponse,
    ]

However, in the source implementation there are no generic typevars bound to the grpc.UnaryUnaryMultiCallable.

It looks like there are typevars bound to the async version of the async version of unary-unary RPC that can be found here.

Let me know if something might be misconfigured on my side -- elsewise, more than happy to open a PR that suggests adding in the RequestType and ResponseType generics to the synchronous unary-unary in the grpc repo!

Background / replication

protobuf : 5.27.3   
grpcio-tools : 1.65.4                           
mypy-protobuf : 3.6.0                                        

Simplen sample client stub .proto file:

syntax = "proto3";

package common;

message User {
  int32 id = 1;
  string name = 2;
}

service Service1 {
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
}

message GetUserRequest {
  int32 user_id = 1;
}

message GetUserResponse {
  User user = 1;
}

By running:

python -m grpc_tools.protoc \
                -Iproto \
                --python_out=client/generated \
                --mypy_out=client/generated \
                --grpc_python_out=client/generated \
                --mypy_grpc_out=client/generated \
                proto/*.proto

...It produces the following pb2_grpc_.pyi stub file:

"""
@generated by mypy-protobuf.  Do not edit manually!
isort:skip_file
"""

import abc
import collections.abc
import grpc
import grpc.aio
import service_pb2
import typing

_T = typing.TypeVar("_T")

class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ...

class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext):  # type: ignore[misc, type-arg]
    ...

class Service1Stub:
    def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ...
    GetUser: grpc.UnaryUnaryMultiCallable[
        service_pb2.GetUserRequest,
        service_pb2.GetUserResponse,
    ]

class Service1AsyncStub:
    GetUser: grpc.aio.UnaryUnaryMultiCallable[
        service_pb2.GetUserRequest,
        service_pb2.GetUserResponse,
    ]

class Service1Servicer(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def GetUser(
        self,
        request: service_pb2.GetUserRequest,
        context: _ServicerContext,
    ) -> typing.Union[service_pb2.GetUserResponse, collections.abc.Awaitable[service_pb2.GetUserResponse]]: ...

def add_Service1Servicer_to_server(servicer: Service1Servicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions