When I use the protoc-gen-mypy
plugin from mypy-protobuf
with protoc
to generate mypy stubs for my gRPC Greeter service, I get an error about generics.
Here is the command I used to generate the greeter_pb2_grpc.pyi
file:
python -m grpc_tools.protoc --plugin=protoc-gen-mypy=`which protoc-gen-mypy` -Iprotos --mypy_grpc_out=grpc protos/greeter.proto
Here is the content of greeter_pb2_grpc.pyi
:
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
import abc
import greeter_pb2
import grpc
class GreeterStub:
"""The greeting service definition."""
def __init__(self, channel: grpc.Channel) -> None: ...
SayHello: grpc.UnaryUnaryMultiCallable[
greeter_pb2.HelloRequest,
greeter_pb2.HelloReply]
"""Sends a greeting"""
class GreeterServicer(metaclass=abc.ABCMeta):
"""The greeting service definition."""
@abc.abstractmethod
def SayHello(self,
request: greeter_pb2.HelloRequest,
context: grpc.ServicerContext,
) -> greeter_pb2.HelloReply:
"""Sends a greeting"""
pass
def add_GreeterServicer_to_server(servicer: GreeterServicer, server: grpc.Server) -> None: ...
When I run mypy
, I get this error in the greeter_pb2_grpc.pyi
file:
"UnaryUnaryMultiCallable" expects no type arguments, but 2 given
The actual definition in the grpc
library is:
class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)): ...
So, stubgen
generates a stub like this:
class UnaryUnaryMultiCallable(metaclass=abc.ABCMeta):
I don't want to edit what mypy-protobuf
generates because what I usually edit is what stubgen
generates.
How should I edit the grpc/__init__.pyi
file that stubgen
generates to make mypy
not complain?
You don't need to generate your own stubs for grpc
because grpc-stubs
already does that.
And this library uses this for the class definition (see here):
class UnaryUnaryClientInterceptor(typing.Generic[TRequest, TResponse]):
So, just doing pip install grpc-stubs
and removing your grpc/**/*.pyi
stubs for grpc
should do the trick.
The above is a good solution if you are not using grpc.aio
.
However, if you use grpc.aio
and have, for instance, a class inheriting from a grpc.aio.ServerInterceptor
like this:
class LoggingInterceptor(grpc.aio.ServerInterceptor):
Because of this grpc-stubs
issue, you'll need to do something more manual.
I personally had to create my own stubs from scratch (with the help of stubgen
) because I couldn't find a way to merge custom stubs with stubs coming from grpc-stubs
(like how Declaration Merging would work in TypeScript).
Don't uninstall grpc-stubs
because you'll still need it to have types for grpc_health
and grpc_reflection
.
I'm not including what I did in this StackOverflow answer because it is only has a partial coverage of grpc
and grpc.aio
and it depends on my server code.