stubgen配合mypy-protobuf使用时泛型报错的修复方法
问题场景
当结合protoc使用mypy-protobuf提供的protoc-gen-mypy插件搭配protoc,为gRPC Greeter服务生成mypy类型存根时,会遇到泛型相关的类型检查错误。
用于生成greeter_pb2_grpc.pyi文件的执行命令如下:
python -m grpc_tools.protoc --plugin=protoc-gen-mypy=`which protoc-gen-mypy` -Iprotos --mypy_grpc_out=grpc protos/greeter.proto
生成的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: ...
运行mypy执行类型检查时,greeter_pb2_grpc.pyi文件抛出如下错误信息:
"UnaryUnaryMultiCallable" expects no type arguments, but 2 given
grpc官方库中UnaryUnaryMultiCallable类的实际定义为:
class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)): ...
stubgen工具默认生成的对应类型存根为:
class UnaryUnaryMultiCallable(metaclass=abc.ABCMeta):
需求为不修改mypy-protobuf自动生成的文件,仅调整stubgen生成的存根文件,通过编辑stubgen生成的grpc/__init__.pyi文件消除该mypy类型检查报错。
解决方案
在grpc/__init__.pyi文件中导入typing模块的泛型基类,将所有gRPC调用相关的MultiCallable类声明为接收两个类型参数的泛型类即可,具体修改如下:
- 在文件顶部添加导入与类型变量声明:
from typing import TypeVar, Generic _RequestType = TypeVar("_RequestType") _ResponseType = TypeVar("_ResponseType") - 找到stubgen原先生成的
UnaryUnaryMultiCallable定义,修改为继承Generic[_RequestType, _ResponseType]的泛型类,类下原有方法定义全部保留:class UnaryUnaryMultiCallable(Generic[_RequestType, _ResponseType], metaclass=abc.ABCMeta): ... - (可选,避免后续其他调用模式报同类错误) 对剩下三种MultiCallable类型做同样的泛型声明:
class UnaryStreamMultiCallable(Generic[_RequestType, _ResponseType], metaclass=abc.ABCMeta): ... class StreamUnaryMultiCallable(Generic[_RequestType, _ResponseType], metaclass=abc.ABCMeta): ... class StreamStreamMultiCallable(Generic[_RequestType, _ResponseType], metaclass=abc.ABCMeta): ... - (可选,避免服务端实现报类型匹配错误) 给
ServicerContext也补上对应泛型参数声明,类下原有方法全部保留:class ServicerContext(Generic[_RequestType, _ResponseType]): ...
修改完成后重新运行mypy,UnaryUnaryMultiCallable泛型参数数量不匹配的报错就会消除。
内容的提问来源于stack exchange,提问作者Drarig29
相关产品推荐
相关产品推荐

