Merge c85d8ae062 into ce220f01a5
This commit is contained in:
commit
0af7031e67
|
|
@ -68,6 +68,10 @@ ARTIFACTS += interceptors/headers/helloworld_pb2.py
|
|||
ARTIFACTS += interceptors/headers/helloworld_pb2_grpc.py
|
||||
ARTIFACTS += interceptors/headers/helloworld_pb2.pyi
|
||||
|
||||
ARTIFACTS += interceptors/streaming/hellostreamingworld_pb2.py
|
||||
ARTIFACTS += interceptors/streaming/hellostreamingworld_pb2_grpc.py
|
||||
ARTIFACTS += interceptors/streaming/hellostreamingworld_pb2.pyi
|
||||
|
||||
ARTIFACTS += metadata/helloworld_pb2.py
|
||||
ARTIFACTS += metadata/helloworld_pb2_grpc.py
|
||||
ARTIFACTS += metadata/helloworld_pb2.pyi
|
||||
|
|
@ -131,6 +135,9 @@ interceptors/default_value/helloworld_pb2.py interceptors/default_value/hellowor
|
|||
interceptors/headers/helloworld_pb2.py interceptors/headers/helloworld_pb2_grpc.py interceptors/headers/helloworld_pb2.pyi: ../protos/helloworld.proto
|
||||
python3 -m grpc_tools.protoc --python_out=interceptors/headers --grpc_python_out=interceptors/headers --pyi_out=interceptors/headers -I ../protos ../protos/helloworld.proto
|
||||
|
||||
interceptors/streaming/hellostreamingworld_pb2.py interceptors/streaming/hellostreamingworld_pb2_grpc.py interceptors/streaming/hellostreamingworld_pb2.pyi: ../protos/hellostreamingworld.proto
|
||||
python3 -m grpc_tools.protoc --python_out=interceptors/streaming --grpc_python_out=interceptors/streaming --pyi_out=interceptors/streaming -I ../protos ../protos/hellostreamingworld.proto
|
||||
|
||||
metadata/helloworld_pb2.py metadata/helloworld_pb2_grpc.py metadata/helloworld_pb2.pyi: ../protos/helloworld.proto
|
||||
python3 -m grpc_tools.protoc --python_out=metadata --grpc_python_out=metadata --pyi_out=metadata -I ../protos ../protos/helloworld.proto
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
# gRPC Python Client/Server Streaming Interceptor Example
|
||||
|
||||
This example demonstrates the usage of streaming client/server interceptors.
|
||||
|
||||
## How to run this example
|
||||
|
||||
1. Start server: `python3 greeter_server.py`
|
||||
1. Start client: `python3 greeter_client.py`
|
||||
|
||||
### Expected outcome
|
||||
|
||||
#### unary_stream
|
||||
|
||||
server
|
||||
|
||||
```
|
||||
INFO:root:interceptor1: before RPC
|
||||
INFO:root:interceptor2: before RPC
|
||||
INFO:root:interceptor3: before RPC
|
||||
INFO:root:SayHelloServerStreaming: received request 0 # ---------------
|
||||
INFO:root:interceptor3: before response 0 returned # |
|
||||
INFO:root:interceptor2: before response 0 returned # |
|
||||
INFO:root:interceptor1: before response 0 returned # | 1st response
|
||||
INFO:root:interceptor1: after response 0 returned # |
|
||||
INFO:root:interceptor2: after response 0 returned # |
|
||||
INFO:root:interceptor3: after response 0 returned # ---------------
|
||||
INFO:root:SayHelloServerStreaming: received request 1 # ---------------
|
||||
INFO:root:interceptor3: before response 1 returned # |
|
||||
INFO:root:interceptor2: before response 1 returned # |
|
||||
INFO:root:interceptor1: before response 1 returned # | 2nd response
|
||||
INFO:root:interceptor1: after response 1 returned # |
|
||||
INFO:root:interceptor2: after response 1 returned # |
|
||||
INFO:root:interceptor3: after response 1 returned # ---------------
|
||||
INFO:root:interceptor3: after RPC
|
||||
INFO:root:interceptor2: after RPC
|
||||
INFO:root:interceptor1: after RPC
|
||||
```
|
||||
|
||||
client
|
||||
|
||||
```
|
||||
INFO:root:interceptor1: before RPC
|
||||
INFO:root:interceptor2: before RPC
|
||||
INFO:root:interceptor3: before RPC
|
||||
INFO:root:interceptor3: before response 0 returned # ---------------
|
||||
INFO:root:interceptor2: before response 0 returned # |
|
||||
INFO:root:interceptor1: before response 0 returned # |
|
||||
INFO:root:Hello number 0, Alice! # | 1st response
|
||||
INFO:root:interceptor1: after response 0 returned # |
|
||||
INFO:root:interceptor2: after response 0 returned # |
|
||||
INFO:root:interceptor3: after response 0 returned # ---------------
|
||||
INFO:root:interceptor3: before response 1 returned # ---------------
|
||||
INFO:root:interceptor2: before response 1 returned # |
|
||||
INFO:root:interceptor1: before response 1 returned # |
|
||||
INFO:root:Hello number 1, Alice! # | 2nd response
|
||||
INFO:root:interceptor1: after response 1 returned # |
|
||||
INFO:root:interceptor2: after response 1 returned # |
|
||||
INFO:root:interceptor3: after response 1 returned # ---------------
|
||||
INFO:root:interceptor3: after RPC
|
||||
INFO:root:interceptor2: after RPC
|
||||
INFO:root:interceptor1: after RPC
|
||||
```
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
# Copyright 2023 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.
|
||||
"""The Python implementation of the GRPC hellostreamingworld.MultiGreeter client."""
|
||||
|
||||
import logging
|
||||
|
||||
import grpc
|
||||
|
||||
import hellostreamingworld_pb2
|
||||
import hellostreamingworld_pb2_grpc
|
||||
|
||||
|
||||
def _wrap_response_iterator(interceptor_id, response_iterator):
|
||||
for i, response in enumerate(response_iterator):
|
||||
logging.info(f"{interceptor_id}: before response {i} returned")
|
||||
yield response
|
||||
logging.info(f"{interceptor_id}: after response {i} returned")
|
||||
logging.info(f"{interceptor_id}: after RPC")
|
||||
|
||||
|
||||
class UnaryStreamClientInterceptor(grpc.UnaryStreamClientInterceptor):
|
||||
def __init__(self, interceptor_id):
|
||||
self._interceptor_id = interceptor_id
|
||||
|
||||
def intercept_unary_stream(
|
||||
self, continuation, client_call_details, request
|
||||
):
|
||||
logging.info(f"{self._interceptor_id}: before RPC")
|
||||
response_iterator = continuation(client_call_details, request)
|
||||
new_response_iterator = _wrap_response_iterator(
|
||||
self._interceptor_id, response_iterator
|
||||
)
|
||||
return new_response_iterator
|
||||
|
||||
|
||||
def run() -> None:
|
||||
with grpc.insecure_channel(f"localhost:50051") as channel:
|
||||
intercept_channel = grpc.intercept_channel(
|
||||
channel,
|
||||
UnaryStreamClientInterceptor("interceptor1"),
|
||||
UnaryStreamClientInterceptor("interceptor2"),
|
||||
UnaryStreamClientInterceptor("interceptor3"),
|
||||
)
|
||||
stub = hellostreamingworld_pb2_grpc.MultiGreeterStub(intercept_channel)
|
||||
|
||||
request = hellostreamingworld_pb2.HelloRequest(
|
||||
name="Alice", num_greetings="2"
|
||||
)
|
||||
for response in stub.sayHello(request):
|
||||
logging.info(response.message)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level="INFO")
|
||||
run()
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
# Copyright 2023 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.
|
||||
"""The Python implementation of the GRPC hellostreamingworld.MultiGreeter server."""
|
||||
|
||||
import logging
|
||||
from concurrent import futures
|
||||
|
||||
import grpc
|
||||
|
||||
import hellostreamingworld_pb2
|
||||
import hellostreamingworld_pb2_grpc
|
||||
|
||||
|
||||
def _wrap_handler(handler, behavior_wrapper):
|
||||
factory = grpc.unary_stream_rpc_method_handler
|
||||
behavior = handler.unary_stream
|
||||
return factory(
|
||||
behavior_wrapper(behavior),
|
||||
request_deserializer=handler.request_deserializer,
|
||||
response_serializer=handler.response_serializer,
|
||||
)
|
||||
|
||||
|
||||
def _wrap_request_iterator(interceptor_id, request_iterator):
|
||||
for i, request in enumerate(request_iterator):
|
||||
logging.info(f"{interceptor_id}: before request {i} sent")
|
||||
yield request
|
||||
logging.info(f"{interceptor_id}: after request {i} sent")
|
||||
|
||||
|
||||
def _wrap_response_iterator(interceptor_id, response_iterator):
|
||||
for i, response in enumerate(response_iterator):
|
||||
logging.info(f"{interceptor_id}: before response {i} returned")
|
||||
yield response
|
||||
logging.info(f"{interceptor_id}: after response {i} returned")
|
||||
logging.info(f"{interceptor_id}: after RPC")
|
||||
|
||||
|
||||
class ServerInterceptor(grpc.ServerInterceptor):
|
||||
def __init__(self, interceptor_id: str):
|
||||
self._interceptor_id = interceptor_id
|
||||
|
||||
def intercept_service(self, continuation, handler_call_details):
|
||||
def wrap_behavior(behavior):
|
||||
def _unary_stream(request, context):
|
||||
logging.info(f"{self._interceptor_id}: before RPC")
|
||||
response_iterator = behavior(request, context)
|
||||
new_response_iterator = _wrap_response_iterator(
|
||||
self._interceptor_id, response_iterator
|
||||
)
|
||||
return new_response_iterator
|
||||
|
||||
return _unary_stream
|
||||
|
||||
handler = continuation(handler_call_details)
|
||||
return _wrap_handler(handler, wrap_behavior)
|
||||
|
||||
|
||||
class MultiGreeter(hellostreamingworld_pb2_grpc.MultiGreeterServicer):
|
||||
def sayHello(self, request, context):
|
||||
num_greetings = int(request.num_greetings)
|
||||
for i in range(num_greetings):
|
||||
logging.info(f"SayHelloServerStreaming: received request {i}")
|
||||
yield hellostreamingworld_pb2.HelloReply(
|
||||
message=f"Hello number {i}, {request.name}!"
|
||||
)
|
||||
|
||||
|
||||
def serve():
|
||||
server = grpc.server(
|
||||
futures.ThreadPoolExecutor(max_workers=1),
|
||||
interceptors=[
|
||||
ServerInterceptor("interceptor1"),
|
||||
ServerInterceptor("interceptor2"),
|
||||
ServerInterceptor("interceptor3"),
|
||||
],
|
||||
)
|
||||
hellostreamingworld_pb2_grpc.add_MultiGreeterServicer_to_server(
|
||||
MultiGreeter(), server
|
||||
)
|
||||
listen_addr = "[::]:50051"
|
||||
server.add_insecure_port(listen_addr)
|
||||
server.start()
|
||||
server.wait_for_termination()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
serve()
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: hellostreamingworld.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19hellostreamingworld.proto\x12\x13hellostreamingworld\"3\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x15\n\rnum_greetings\x18\x02 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2b\n\x0cMultiGreeter\x12R\n\x08sayHello\x12!.hellostreamingworld.HelloRequest\x1a\x1f.hellostreamingworld.HelloReply\"\x00\x30\x01\x42\x0f\n\x07\x65x.grpc\xa2\x02\x03HSWb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'hellostreamingworld_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\007ex.grpc\242\002\003HSW'
|
||||
_globals['_HELLOREQUEST']._serialized_start=50
|
||||
_globals['_HELLOREQUEST']._serialized_end=101
|
||||
_globals['_HELLOREPLY']._serialized_start=103
|
||||
_globals['_HELLOREPLY']._serialized_end=132
|
||||
_globals['_MULTIGREETER']._serialized_start=134
|
||||
_globals['_MULTIGREETER']._serialized_end=232
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from typing import ClassVar as _ClassVar, Optional as _Optional
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class HelloRequest(_message.Message):
|
||||
__slots__ = ["name", "num_greetings"]
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
NUM_GREETINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
name: str
|
||||
num_greetings: str
|
||||
def __init__(self, name: _Optional[str] = ..., num_greetings: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class HelloReply(_message.Message):
|
||||
__slots__ = ["message"]
|
||||
MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
message: str
|
||||
def __init__(self, message: _Optional[str] = ...) -> None: ...
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
|
||||
import hellostreamingworld_pb2 as hellostreamingworld__pb2
|
||||
|
||||
|
||||
class MultiGreeterStub(object):
|
||||
"""The greeting service definition.
|
||||
"""
|
||||
|
||||
def __init__(self, channel):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
channel: A grpc.Channel.
|
||||
"""
|
||||
self.sayHello = channel.unary_stream(
|
||||
'/hellostreamingworld.MultiGreeter/sayHello',
|
||||
request_serializer=hellostreamingworld__pb2.HelloRequest.SerializeToString,
|
||||
response_deserializer=hellostreamingworld__pb2.HelloReply.FromString,
|
||||
)
|
||||
|
||||
|
||||
class MultiGreeterServicer(object):
|
||||
"""The greeting service definition.
|
||||
"""
|
||||
|
||||
def sayHello(self, request, context):
|
||||
"""Sends multiple greetings
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
|
||||
def add_MultiGreeterServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
'sayHello': grpc.unary_stream_rpc_method_handler(
|
||||
servicer.sayHello,
|
||||
request_deserializer=hellostreamingworld__pb2.HelloRequest.FromString,
|
||||
response_serializer=hellostreamingworld__pb2.HelloReply.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
'hellostreamingworld.MultiGreeter', rpc_method_handlers)
|
||||
server.add_generic_rpc_handlers((generic_handler,))
|
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API.
|
||||
class MultiGreeter(object):
|
||||
"""The greeting service definition.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def sayHello(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_stream(request, target, '/hellostreamingworld.MultiGreeter/sayHello',
|
||||
hellostreamingworld__pb2.HelloRequest.SerializeToString,
|
||||
hellostreamingworld__pb2.HelloReply.FromString,
|
||||
options, channel_credentials,
|
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
||||
Loading…
Reference in New Issue