grpc-stubs
grpc-stubs copied to clipboard
The object returned from `UnaryStreamMultiCallable` and `StreamStreamMultiCallable` should also be a `Future`
Description of issue
The object returned from grpc.UnaryStreamMultiCallable
and grpc.StreamStreamMultiCallable
is a Call
, an iterator of response values, and a Future
, but the grpc-stubs definition of CallIterator[TResponse]
is only a Call
and an iterator of response values.
Here's a link to the documentation for this return value: https://grpc.github.io/grpc/python/grpc.html#grpc.UnaryStreamMultiCallable
Returns:
An object that is a Call for the RPC, an iterator of response values, and a Future for the RPC. Drawing response values from the returned Call-iterator may raise RpcError indicating termination of the RPC with non-OK status.
I attached an example main.py
that calls a UnaryStreamMultiCallable
and uses Future
methods done()
and exception()
to query its status. This works correctly at runtime (the exception is expected).
Exception (expected): <_MultiThreadedRendezvous of RPC that terminated with:
status = StatusCode.UNAVAILABLE
details = "failed to connect to all addresses; last error: UNKNOWN: ipv4:127.0.0.1:1234: Failed to connect to remote host: Connection refused"
debug_error_string = "UNKNOWN:failed to connect to all addresses; last error: UNKNOWN: ipv4:127.0.0.1:1234: Failed to connect to remote host: Connection refused {created_time:"2023-05-22T19:30:15.558641584-05:00", grpc_status:14}"
>
However, it fails type checking with mypy:
main.py:12: error: "CallIterator[HelloReply]" has no attribute "done" [attr-defined]
main.py:12: error: "CallIterator[HelloReply]" has no attribute "exception" [attr-defined]
main.py:13: error: "CallIterator[HelloReply]" has no attribute "exception" [attr-defined]
Found 3 errors in 1 file (checked 1 source file)
Minimum Reproducible Example
main.py
from __future__ import annotations
import grpc
from hellostreamingworld_pb2 import HelloRequest, HelloReply
from hellostreamingworld_pb2_grpc import MultiGreeterStub
if __name__ == "__main__":
channel = grpc.insecure_channel("localhost:1234")
stub = MultiGreeterStub(channel)
stream = stub.sayHello(HelloRequest(name="world", num_greetings="3"))
stream.initial_metadata()
if stream.done() and stream.exception() is not None:
ex = stream.exception()
print(f"Exception (expected): {ex}")
run.sh
#!/usr/bin/env bash
set -o errexit -o nounset -o pipefail
python -m venv venv
source ./venv/bin/activate
pip install grpcio grpcio-tools grpc-stubs mypy mypy-protobuf
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. --pyi_out=. --mypy_grpc_out=. hellostreamingworld.proto
python main.py
python -m mypy main.py
hellostreamingworld.proto
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
option java_package = "ex.grpc";
option objc_class_prefix = "HSW";
package hellostreamingworld;
// The greeting service definition.
service MultiGreeter {
// Sends multiple greetings
rpc sayHello (HelloRequest) returns (stream HelloReply) {}
}
// The request message containing the user's name and how many greetings
// they want.
message HelloRequest {
string name = 1;
string num_greetings = 2;
}
// A response message containing a greeting
message HelloReply {
string message = 1;
}
Full output
Requirement already satisfied: grpcio in ./venv/lib/python3.9/site-packages (1.55.0)
Requirement already satisfied: grpcio-tools in ./venv/lib/python3.9/site-packages (1.55.0)
Requirement already satisfied: grpc-stubs in ./venv/lib/python3.9/site-packages (1.53.0.2)
Requirement already satisfied: mypy in ./venv/lib/python3.9/site-packages (1.3.0)
Requirement already satisfied: mypy-protobuf in ./venv/lib/python3.9/site-packages (3.4.0)
Requirement already satisfied: protobuf<5.0dev,>=4.21.6 in ./venv/lib/python3.9/site-packages (from grpcio-tools) (4.23.1)
Requirement already satisfied: setuptools in ./venv/lib/python3.9/site-packages (from grpcio-tools) (58.1.0)
Requirement already satisfied: mypy-extensions>=1.0.0 in ./venv/lib/python3.9/site-packages (from mypy) (1.0.0)
Requirement already satisfied: typing-extensions>=3.10 in ./venv/lib/python3.9/site-packages (from mypy) (4.6.0)
Requirement already satisfied: tomli>=1.1.0 in ./venv/lib/python3.9/site-packages (from mypy) (2.0.1)
Requirement already satisfied: types-protobuf>=3.20.4 in ./venv/lib/python3.9/site-packages (from mypy-protobuf) (4.23.0.1)
WARNING: You are using pip version 22.0.4; however, version 23.1.2 is available.
You should consider upgrading via the '/tmp/unary_stream_call_future/venv/bin/python -m pip install --upgrade pip' command.
Writing mypy to hellostreamingworld_pb2_grpc.pyi
Exception (expected): <_MultiThreadedRendezvous of RPC that terminated with:
status = StatusCode.UNAVAILABLE
details = "failed to connect to all addresses; last error: UNKNOWN: ipv4:127.0.0.1:1234: Failed to connect to remote host: Connection refused"
debug_error_string = "UNKNOWN:failed to connect to all addresses; last error: UNKNOWN: ipv4:127.0.0.1:1234: Failed to connect to remote host: Connection refused {created_time:"2023-05-22T19:47:20.563451309-05:00", grpc_status:14}"
>
main.py:12: error: "CallIterator[HelloReply]" has no attribute "done" [attr-defined]
main.py:12: error: "CallIterator[HelloReply]" has no attribute "exception" [attr-defined]
main.py:13: error: "CallIterator[HelloReply]" has no attribute "exception" [attr-defined]
Found 3 errors in 1 file (checked 1 source file)
Nice find! Thank you for the bug report, and thank you very much for the MRE. I've taken a run at a fix here, your MRE made verifying this and writing the test trivial. Does this look like it will solve your problem? https://github.com/shabbyrobe/grpc-stubs/pull/42
Thanks, I tried it out and left feedback on the PR.