-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix UnaryStreamMultiCallable and StreamStreamMultiCallable Future/Call #42
base: master
Are you sure you want to change the base?
Conversation
@@ -669,7 +669,7 @@ class UnaryUnaryMultiCallable(typing.Generic[TRequest, TResponse]): | |||
... | |||
|
|||
|
|||
class UnaryStreamMultiCallable(typing.Generic[TRequest, TResponse]): | |||
class UnaryStreamMultiCallable(CallFuture[TResponse], typing.Generic[TRequest, TResponse]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not quite it. The UnaryStreamMultiCallable
is not itself the stream. Calling the UnaryStreamMultiCallable
(i.e. the __call__
method) returns the stream.
CallIterator[TResponse]
currently inherits from Call
. I think it should inherit from CallFuture[TResponse]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correction: CallFuture[TResponse]
implies that stream.result()
returns a TResponse
, but that doesn't seem to be the case.
The behavior of stream.result()
doesn't seem to be documented, but as far as I can tell from testing: for server-streaming RPCs, result()
waits for the RPC to complete (stream closed, canceled, or error). When the stream is closed, it returns None
.
Tested with a modified version of https://github.com/grpc/grpc/blob/master/examples/python/hellostreamingworld/async_greeter_client.py:
import logging
import grpc
import hellostreamingworld_pb2
import hellostreamingworld_pb2_grpc
def run() -> None:
with grpc.insecure_channel("localhost:50051") as channel:
stub = hellostreamingworld_pb2_grpc.MultiGreeterStub(channel)
hello_stream = stub.sayHello(
hellostreamingworld_pb2.HelloRequest(name="you"))
while True:
try:
response = hello_stream.result(timeout=0.1)
print(f"result() returned {type(response)}: {repr(response)}")
if response is None:
break
except grpc.FutureTimeoutError:
response = next(hello_stream, None)
print(f"next() returned {type(response)}: {repr(response)}")
if response is None:
break
if __name__ == "__main__":
logging.basicConfig()
run()
python greeter_client.py
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 0, you!"
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 1, you!"
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 2, you!"
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 3, you!"
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 4, you!"
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 5, you!"
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 6, you!"
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 7, you!"
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 8, you!"
next() returned <class 'hellostreamingworld_pb2.HelloReply'>: message: "Hello number 9, you!"
result() returned <class 'NoneType'>: None
def unary_stream() -> grpc.UnaryStreamMultiCallable[int, int]: | ||
return typing.cast(grpc.UnaryStreamMultiCallable[int, int], None) | ||
|
||
stream = unary_stream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function returns the multi-callable object, not the stream. Call the multi-callable to get the stream.
See #41