mirror of https://github.com/grpc/grpc.git
Merge pull request #21232 from lidizheng/aio-streaming
[Aio] Streaming API - Server side streamingpull/21442/head
commit
4955cda816
37 changed files with 1885 additions and 775 deletions
@ -0,0 +1,157 @@ |
||||
# Copyright 2019 The 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. |
||||
"""Abstract base classes for client-side Call objects. |
||||
|
||||
Call objects represents the RPC itself, and offer methods to access / modify |
||||
its information. They also offer methods to manipulate the life-cycle of the |
||||
RPC, e.g. cancellation. |
||||
""" |
||||
|
||||
from abc import ABCMeta, abstractmethod |
||||
from typing import Any, AsyncIterable, Awaitable, Callable, Generic, Text, Optional |
||||
|
||||
import grpc |
||||
|
||||
from ._typing import MetadataType, RequestType, ResponseType |
||||
|
||||
__all__ = 'RpcContext', 'Call', 'UnaryUnaryCall', 'UnaryStreamCall' |
||||
|
||||
|
||||
class RpcContext(metaclass=ABCMeta): |
||||
"""Provides RPC-related information and action.""" |
||||
|
||||
@abstractmethod |
||||
def cancelled(self) -> bool: |
||||
"""Return True if the RPC is cancelled. |
||||
|
||||
The RPC is cancelled when the cancellation was requested with cancel(). |
||||
|
||||
Returns: |
||||
A bool indicates whether the RPC is cancelled or not. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
def done(self) -> bool: |
||||
"""Return True if the RPC is done. |
||||
|
||||
An RPC is done if the RPC is completed, cancelled or aborted. |
||||
|
||||
Returns: |
||||
A bool indicates if the RPC is done. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
def time_remaining(self) -> Optional[float]: |
||||
"""Describes the length of allowed time remaining for the RPC. |
||||
|
||||
Returns: |
||||
A nonnegative float indicating the length of allowed time in seconds |
||||
remaining for the RPC to complete before it is considered to have |
||||
timed out, or None if no deadline was specified for the RPC. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
def cancel(self) -> bool: |
||||
"""Cancels the RPC. |
||||
|
||||
Idempotent and has no effect if the RPC has already terminated. |
||||
|
||||
Returns: |
||||
A bool indicates if the cancellation is performed or not. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
def add_done_callback(self, callback: Callable[[Any], None]) -> None: |
||||
"""Registers a callback to be called on RPC termination. |
||||
|
||||
Args: |
||||
callback: A callable object will be called with the context object as |
||||
its only argument. |
||||
""" |
||||
|
||||
|
||||
class Call(RpcContext, metaclass=ABCMeta): |
||||
"""The abstract base class of an RPC on the client-side.""" |
||||
|
||||
@abstractmethod |
||||
async def initial_metadata(self) -> MetadataType: |
||||
"""Accesses the initial metadata sent by the server. |
||||
|
||||
Returns: |
||||
The initial :term:`metadata`. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
async def trailing_metadata(self) -> MetadataType: |
||||
"""Accesses the trailing metadata sent by the server. |
||||
|
||||
Returns: |
||||
The trailing :term:`metadata`. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
async def code(self) -> grpc.StatusCode: |
||||
"""Accesses the status code sent by the server. |
||||
|
||||
Returns: |
||||
The StatusCode value for the RPC. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
async def details(self) -> Text: |
||||
"""Accesses the details sent by the server. |
||||
|
||||
Returns: |
||||
The details string of the RPC. |
||||
""" |
||||
|
||||
|
||||
class UnaryUnaryCall( |
||||
Generic[RequestType, ResponseType], Call, metaclass=ABCMeta): |
||||
"""The abstract base class of an unary-unary RPC on the client-side.""" |
||||
|
||||
@abstractmethod |
||||
def __await__(self) -> Awaitable[ResponseType]: |
||||
"""Await the response message to be ready. |
||||
|
||||
Returns: |
||||
The response message of the RPC. |
||||
""" |
||||
|
||||
|
||||
class UnaryStreamCall( |
||||
Generic[RequestType, ResponseType], Call, metaclass=ABCMeta): |
||||
|
||||
@abstractmethod |
||||
def __aiter__(self) -> AsyncIterable[ResponseType]: |
||||
"""Returns the async iterable representation that yields messages. |
||||
|
||||
Under the hood, it is calling the "read" method. |
||||
|
||||
Returns: |
||||
An async iterable object that yields messages. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
async def read(self) -> ResponseType: |
||||
"""Reads one message from the RPC. |
||||
|
||||
For each streaming RPC, concurrent reads in multiple coroutines are not |
||||
allowed. If you want to perform read in multiple coroutines, you needs |
||||
synchronization. So, you can start another read after current read is |
||||
finished. |
||||
|
||||
Returns: |
||||
A response message of the RPC. |
||||
""" |
@ -0,0 +1,32 @@ |
||||
# Copyright 2019 The 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. |
||||
|
||||
package( |
||||
default_testonly = 1, |
||||
default_visibility = ["//visibility:public"], |
||||
) |
||||
|
||||
py_binary( |
||||
name = "server", |
||||
srcs = ["server.py"], |
||||
python_version = "PY3", |
||||
deps = [ |
||||
"//external:six", |
||||
"//src/proto/grpc/testing:benchmark_service_py_pb2", |
||||
"//src/proto/grpc/testing:benchmark_service_py_pb2_grpc", |
||||
"//src/proto/grpc/testing:py_messages_proto", |
||||
"//src/python/grpcio/grpc:grpcio", |
||||
"//src/python/grpcio_tests/tests/unit/framework/common", |
||||
], |
||||
) |
@ -0,0 +1,50 @@ |
||||
# Copyright 2019 The 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. |
||||
"""Tests AioRpcError class.""" |
||||
|
||||
import logging |
||||
import unittest |
||||
|
||||
import grpc |
||||
|
||||
from grpc.experimental.aio._call import AioRpcError |
||||
from tests_aio.unit._test_base import AioTestBase |
||||
|
||||
_TEST_INITIAL_METADATA = ('initial metadata',) |
||||
_TEST_TRAILING_METADATA = ('trailing metadata',) |
||||
_TEST_DEBUG_ERROR_STRING = '{This is a debug string}' |
||||
|
||||
|
||||
class TestAioRpcError(unittest.TestCase): |
||||
|
||||
def test_attributes(self): |
||||
aio_rpc_error = AioRpcError( |
||||
grpc.StatusCode.CANCELLED, |
||||
'details', |
||||
initial_metadata=_TEST_INITIAL_METADATA, |
||||
trailing_metadata=_TEST_TRAILING_METADATA, |
||||
debug_error_string=_TEST_DEBUG_ERROR_STRING) |
||||
self.assertEqual(aio_rpc_error.code(), grpc.StatusCode.CANCELLED) |
||||
self.assertEqual(aio_rpc_error.details(), 'details') |
||||
self.assertEqual(aio_rpc_error.initial_metadata(), |
||||
_TEST_INITIAL_METADATA) |
||||
self.assertEqual(aio_rpc_error.trailing_metadata(), |
||||
_TEST_TRAILING_METADATA) |
||||
self.assertEqual(aio_rpc_error.debug_error_string(), |
||||
_TEST_DEBUG_ERROR_STRING) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
unittest.main(verbosity=2) |
Loading…
Reference in new issue