mirror of https://github.com/grpc/grpc.git
This makes grpc.early_adopter much more independent of RPC Framework and cleaner at the cost of reexporting most of the interfaces and writing several delegation classes.pull/785/head
parent
517aa0c535
commit
9280790a5d
10 changed files with 1013 additions and 347 deletions
@ -0,0 +1,168 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
import abc |
||||
import collections |
||||
|
||||
# assembly_interfaces is referenced from specification in this module. |
||||
from grpc.framework.assembly import interfaces as assembly_interfaces # pylint: disable=unused-import |
||||
from grpc.framework.assembly import utilities as assembly_utilities |
||||
from grpc.early_adopter import _reexport |
||||
from grpc.early_adopter import interfaces |
||||
|
||||
|
||||
# TODO(issue 726): Kill the "implementations" attribute of this in favor |
||||
# of the same-information-less-bogusly-represented "cardinalities". |
||||
class InvocationBreakdown(object): |
||||
"""An intermediate representation of invocation-side views of RPC methods. |
||||
|
||||
Attributes: |
||||
cardinalities: A dictionary from RPC method name to interfaces.Cardinality |
||||
value. |
||||
implementations: A dictionary from RPC method name to |
||||
assembly_interfaces.MethodImplementation describing the method. |
||||
request_serializers: A dictionary from RPC method name to callable |
||||
behavior to be used serializing request values for the RPC. |
||||
response_deserializers: A dictionary from RPC method name to callable |
||||
behavior to be used deserializing response values for the RPC. |
||||
""" |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
|
||||
class _EasyInvocationBreakdown( |
||||
InvocationBreakdown, |
||||
collections.namedtuple( |
||||
'_EasyInvocationBreakdown', |
||||
('cardinalities', 'implementations', 'request_serializers', |
||||
'response_deserializers'))): |
||||
pass |
||||
|
||||
|
||||
class ServiceBreakdown(object): |
||||
"""An intermediate representation of service-side views of RPC methods. |
||||
|
||||
Attributes: |
||||
implementations: A dictionary from RPC method name |
||||
assembly_interfaces.MethodImplementation implementing the RPC method. |
||||
request_deserializers: A dictionary from RPC method name to callable |
||||
behavior to be used deserializing request values for the RPC. |
||||
response_serializers: A dictionary from RPC method name to callable |
||||
behavior to be used serializing response values for the RPC. |
||||
""" |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
|
||||
class _EasyServiceBreakdown( |
||||
ServiceBreakdown, |
||||
collections.namedtuple( |
||||
'_EasyServiceBreakdown', |
||||
('implementations', 'request_deserializers', 'response_serializers'))): |
||||
pass |
||||
|
||||
|
||||
def break_down_invocation(method_descriptions): |
||||
"""Derives an InvocationBreakdown from several RPC method descriptions. |
||||
|
||||
Args: |
||||
method_descriptions: A dictionary from RPC method name to |
||||
interfaces.RpcMethodInvocationDescription describing the RPCs. |
||||
|
||||
Returns: |
||||
An InvocationBreakdown corresponding to the given method descriptions. |
||||
""" |
||||
cardinalities = {} |
||||
implementations = {} |
||||
request_serializers = {} |
||||
response_deserializers = {} |
||||
for name, method_description in method_descriptions.iteritems(): |
||||
cardinality = method_description.cardinality() |
||||
cardinalities[name] = cardinality |
||||
if cardinality is interfaces.Cardinality.UNARY_UNARY: |
||||
implementations[name] = assembly_utilities.unary_unary_inline(None) |
||||
elif cardinality is interfaces.Cardinality.UNARY_STREAM: |
||||
implementations[name] = assembly_utilities.unary_stream_inline(None) |
||||
elif cardinality is interfaces.Cardinality.STREAM_UNARY: |
||||
implementations[name] = assembly_utilities.stream_unary_inline(None) |
||||
elif cardinality is interfaces.Cardinality.STREAM_STREAM: |
||||
implementations[name] = assembly_utilities.stream_stream_inline(None) |
||||
request_serializers[name] = method_description.serialize_request |
||||
response_deserializers[name] = method_description.deserialize_response |
||||
return _EasyInvocationBreakdown( |
||||
cardinalities, implementations, request_serializers, |
||||
response_deserializers) |
||||
|
||||
|
||||
def break_down_service(method_descriptions): |
||||
"""Derives a ServiceBreakdown from several RPC method descriptions. |
||||
|
||||
Args: |
||||
method_descriptions: A dictionary from RPC method name to |
||||
interfaces.RpcMethodServiceDescription describing the RPCs. |
||||
|
||||
Returns: |
||||
A ServiceBreakdown corresponding to the given method descriptions. |
||||
""" |
||||
implementations = {} |
||||
request_deserializers = {} |
||||
response_serializers = {} |
||||
for name, method_description in method_descriptions.iteritems(): |
||||
cardinality = method_description.cardinality() |
||||
if cardinality is interfaces.Cardinality.UNARY_UNARY: |
||||
def service( |
||||
request, face_rpc_context, |
||||
service_behavior=method_description.service_unary_unary): |
||||
return service_behavior( |
||||
request, _reexport.rpc_context(face_rpc_context)) |
||||
implementations[name] = assembly_utilities.unary_unary_inline(service) |
||||
elif cardinality is interfaces.Cardinality.UNARY_STREAM: |
||||
def service( |
||||
request, face_rpc_context, |
||||
service_behavior=method_description.service_unary_stream): |
||||
return service_behavior( |
||||
request, _reexport.rpc_context(face_rpc_context)) |
||||
implementations[name] = assembly_utilities.unary_stream_inline(service) |
||||
elif cardinality is interfaces.Cardinality.STREAM_UNARY: |
||||
def service( |
||||
request_iterator, face_rpc_context, |
||||
service_behavior=method_description.service_stream_unary): |
||||
return service_behavior( |
||||
request_iterator, _reexport.rpc_context(face_rpc_context)) |
||||
implementations[name] = assembly_utilities.stream_unary_inline(service) |
||||
elif cardinality is interfaces.Cardinality.STREAM_STREAM: |
||||
def service( |
||||
request_iterator, face_rpc_context, |
||||
service_behavior=method_description.service_stream_stream): |
||||
return service_behavior( |
||||
request_iterator, _reexport.rpc_context(face_rpc_context)) |
||||
implementations[name] = assembly_utilities.stream_stream_inline(service) |
||||
request_deserializers[name] = method_description.deserialize_request |
||||
response_serializers[name] = method_description.serialize_response |
||||
|
||||
return _EasyServiceBreakdown( |
||||
implementations, request_deserializers, response_serializers) |
@ -1,178 +0,0 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
import abc |
||||
import collections |
||||
|
||||
from grpc.framework.face import interfaces as face_interfaces |
||||
|
||||
from grpc.early_adopter import interfaces |
||||
|
||||
|
||||
class _InlineUnaryUnaryMethod(face_interfaces.InlineValueInValueOutMethod): |
||||
|
||||
def __init__(self, unary_unary_server_rpc_method): |
||||
self._method = unary_unary_server_rpc_method |
||||
|
||||
def service(self, request, context): |
||||
"""See face_interfaces.InlineValueInValueOutMethod.service for spec.""" |
||||
return self._method.service_unary_unary(request) |
||||
|
||||
|
||||
class _InlineUnaryStreamMethod(face_interfaces.InlineValueInStreamOutMethod): |
||||
|
||||
def __init__(self, unary_stream_server_rpc_method): |
||||
self._method = unary_stream_server_rpc_method |
||||
|
||||
def service(self, request, context): |
||||
"""See face_interfaces.InlineValueInStreamOutMethod.service for spec.""" |
||||
return self._method.service_unary_stream(request) |
||||
|
||||
|
||||
class _InlineStreamUnaryMethod(face_interfaces.InlineStreamInValueOutMethod): |
||||
|
||||
def __init__(self, stream_unary_server_rpc_method): |
||||
self._method = stream_unary_server_rpc_method |
||||
|
||||
def service(self, request_iterator, context): |
||||
"""See face_interfaces.InlineStreamInValueOutMethod.service for spec.""" |
||||
return self._method.service_stream_unary(request_iterator) |
||||
|
||||
|
||||
class _InlineStreamStreamMethod(face_interfaces.InlineStreamInStreamOutMethod): |
||||
|
||||
def __init__(self, stream_stream_server_rpc_method): |
||||
self._method = stream_stream_server_rpc_method |
||||
|
||||
def service(self, request_iterator, context): |
||||
"""See face_interfaces.InlineStreamInStreamOutMethod.service for spec.""" |
||||
return self._method.service_stream_stream(request_iterator) |
||||
|
||||
|
||||
class ClientBreakdown(object): |
||||
"""An intermediate representation of invocation-side views of RPC methods. |
||||
|
||||
Attributes: |
||||
request_serializers: A dictionary from RPC method name to callable |
||||
behavior to be used serializing request values for the RPC. |
||||
response_deserializers: A dictionary from RPC method name to callable |
||||
behavior to be used deserializing response values for the RPC. |
||||
""" |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
|
||||
class _EasyClientBreakdown( |
||||
ClientBreakdown, |
||||
collections.namedtuple( |
||||
'_EasyClientBreakdown', |
||||
('request_serializers', 'response_deserializers'))): |
||||
pass |
||||
|
||||
|
||||
class ServerBreakdown(object): |
||||
"""An intermediate representation of implementations of RPC methods. |
||||
|
||||
Attributes: |
||||
unary_unary_methods: A dictionary from RPC method name to callable |
||||
behavior implementing the RPC method for unary-unary RPC methods. |
||||
unary_stream_methods: A dictionary from RPC method name to callable |
||||
behavior implementing the RPC method for unary-stream RPC methods. |
||||
stream_unary_methods: A dictionary from RPC method name to callable |
||||
behavior implementing the RPC method for stream-unary RPC methods. |
||||
stream_stream_methods: A dictionary from RPC method name to callable |
||||
behavior implementing the RPC method for stream-stream RPC methods. |
||||
request_deserializers: A dictionary from RPC method name to callable |
||||
behavior to be used deserializing request values for the RPC. |
||||
response_serializers: A dictionary from RPC method name to callable |
||||
behavior to be used serializing response values for the RPC. |
||||
""" |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
|
||||
|
||||
class _EasyServerBreakdown( |
||||
ServerBreakdown, |
||||
collections.namedtuple( |
||||
'_EasyServerBreakdown', |
||||
('unary_unary_methods', 'unary_stream_methods', 'stream_unary_methods', |
||||
'stream_stream_methods', 'request_deserializers', |
||||
'response_serializers'))): |
||||
pass |
||||
|
||||
|
||||
def client_break_down(methods): |
||||
"""Derives a ClientBreakdown from several interfaces.ClientRpcMethods. |
||||
|
||||
Args: |
||||
methods: A dictionary from RPC mthod name to |
||||
interfaces.ClientRpcMethod object describing the RPCs. |
||||
|
||||
Returns: |
||||
A ClientBreakdown corresponding to the given methods. |
||||
""" |
||||
request_serializers = {} |
||||
response_deserializers = {} |
||||
for name, method in methods.iteritems(): |
||||
request_serializers[name] = method.serialize_request |
||||
response_deserializers[name] = method.deserialize_response |
||||
return _EasyClientBreakdown(request_serializers, response_deserializers) |
||||
|
||||
|
||||
def server_break_down(methods): |
||||
"""Derives a ServerBreakdown from several interfaces.ServerRpcMethods. |
||||
|
||||
Args: |
||||
methods: A dictionary from RPC mthod name to |
||||
interfaces.ServerRpcMethod object describing the RPCs. |
||||
|
||||
Returns: |
||||
A ServerBreakdown corresponding to the given methods. |
||||
""" |
||||
unary_unary = {} |
||||
unary_stream = {} |
||||
stream_unary = {} |
||||
stream_stream = {} |
||||
request_deserializers = {} |
||||
response_serializers = {} |
||||
for name, method in methods.iteritems(): |
||||
cardinality = method.cardinality() |
||||
if cardinality is interfaces.Cardinality.UNARY_UNARY: |
||||
unary_unary[name] = _InlineUnaryUnaryMethod(method) |
||||
elif cardinality is interfaces.Cardinality.UNARY_STREAM: |
||||
unary_stream[name] = _InlineUnaryStreamMethod(method) |
||||
elif cardinality is interfaces.Cardinality.STREAM_UNARY: |
||||
stream_unary[name] = _InlineStreamUnaryMethod(method) |
||||
elif cardinality is interfaces.Cardinality.STREAM_STREAM: |
||||
stream_stream[name] = _InlineStreamStreamMethod(method) |
||||
request_deserializers[name] = method.deserialize_request |
||||
response_serializers[name] = method.serialize_response |
||||
|
||||
return _EasyServerBreakdown( |
||||
unary_unary, unary_stream, stream_unary, stream_stream, |
||||
request_deserializers, response_serializers) |
@ -0,0 +1,207 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
import abc |
||||
import collections |
||||
|
||||
from grpc.framework.face import exceptions as face_exceptions |
||||
from grpc.framework.face import interfaces as face_interfaces |
||||
from grpc.framework.foundation import future |
||||
from grpc.early_adopter import exceptions |
||||
from grpc.early_adopter import interfaces |
||||
|
||||
_ABORTION_REEXPORT = { |
||||
face_interfaces.Abortion.CANCELLED: interfaces.Abortion.CANCELLED, |
||||
face_interfaces.Abortion.EXPIRED: interfaces.Abortion.EXPIRED, |
||||
face_interfaces.Abortion.NETWORK_FAILURE: |
||||
interfaces.Abortion.NETWORK_FAILURE, |
||||
face_interfaces.Abortion.SERVICED_FAILURE: |
||||
interfaces.Abortion.SERVICED_FAILURE, |
||||
face_interfaces.Abortion.SERVICER_FAILURE: |
||||
interfaces.Abortion.SERVICER_FAILURE, |
||||
} |
||||
|
||||
|
||||
class _RpcError(exceptions.RpcError): |
||||
pass |
||||
|
||||
|
||||
def _reexport_error(face_rpc_error): |
||||
if isinstance(face_rpc_error, face_exceptions.CancellationError): |
||||
return exceptions.CancellationError() |
||||
elif isinstance(face_rpc_error, face_exceptions.ExpirationError): |
||||
return exceptions.ExpirationError() |
||||
else: |
||||
return _RpcError() |
||||
|
||||
|
||||
def _as_face_abortion_callback(abortion_callback): |
||||
def face_abortion_callback(face_abortion): |
||||
abortion_callback(_ABORTION_REEXPORT[face_abortion]) |
||||
return face_abortion_callback |
||||
|
||||
|
||||
class _ReexportedFuture(future.Future): |
||||
|
||||
def __init__(self, face_future): |
||||
self._face_future = face_future |
||||
|
||||
def cancel(self): |
||||
return self._face_future.cancel() |
||||
|
||||
def cancelled(self): |
||||
return self._face_future.cancelled() |
||||
|
||||
def running(self): |
||||
return self._face_future.running() |
||||
|
||||
def done(self): |
||||
return self._face_future.done() |
||||
|
||||
def result(self, timeout=None): |
||||
try: |
||||
return self._face_future.result(timeout=timeout) |
||||
except face_exceptions.RpcError as e: |
||||
raise _reexport_error(e) |
||||
|
||||
def exception(self, timeout=None): |
||||
face_error = self._face_future.exception(timeout=timeout) |
||||
return None if face_error is None else _reexport_error(face_error) |
||||
|
||||
def traceback(self, timeout=None): |
||||
return self._face_future.traceback(timeout=timeout) |
||||
|
||||
def add_done_callback(self, fn): |
||||
self._face_future.add_done_callback(lambda unused_face_future: fn(self)) |
||||
|
||||
|
||||
def _call_reexporting_errors(behavior, *args, **kwargs): |
||||
try: |
||||
return behavior(*args, **kwargs) |
||||
except face_exceptions.RpcError as e: |
||||
raise _reexport_error(e) |
||||
|
||||
|
||||
def _reexported_future(face_future): |
||||
return _ReexportedFuture(face_future) |
||||
|
||||
|
||||
class _CancellableIterator(interfaces.CancellableIterator): |
||||
|
||||
def __init__(self, face_cancellable_iterator): |
||||
self._face_cancellable_iterator = face_cancellable_iterator |
||||
|
||||
def __iter__(self): |
||||
return self |
||||
|
||||
def next(self): |
||||
return _call_reexporting_errors(self._face_cancellable_iterator.next) |
||||
|
||||
def cancel(self): |
||||
self._face_cancellable_iterator.cancel() |
||||
|
||||
|
||||
class _RpcContext(interfaces.RpcContext): |
||||
|
||||
def __init__(self, face_rpc_context): |
||||
self._face_rpc_context = face_rpc_context |
||||
|
||||
def is_active(self): |
||||
return self._face_rpc_context.is_active() |
||||
|
||||
def time_remaining(self): |
||||
return self._face_rpc_context.time_remaining() |
||||
|
||||
def add_abortion_callback(self, abortion_callback): |
||||
self._face_rpc_context.add_abortion_callback( |
||||
_as_face_abortion_callback(abortion_callback)) |
||||
|
||||
|
||||
class _UnaryUnarySyncAsync(interfaces.UnaryUnarySyncAsync): |
||||
|
||||
def __init__(self, face_unary_unary_sync_async): |
||||
self._underlying = face_unary_unary_sync_async |
||||
|
||||
def __call__(self, request, timeout): |
||||
return _call_reexporting_errors( |
||||
self._underlying, request, timeout) |
||||
|
||||
def async(self, request, timeout): |
||||
return _ReexportedFuture(self._underlying.async(request, timeout)) |
||||
|
||||
|
||||
class _StreamUnarySyncAsync(interfaces.StreamUnarySyncAsync): |
||||
|
||||
def __init__(self, face_stream_unary_sync_async): |
||||
self._underlying = face_stream_unary_sync_async |
||||
|
||||
def __call__(self, request_iterator, timeout): |
||||
return _call_reexporting_errors( |
||||
self._underlying, request_iterator, timeout) |
||||
|
||||
def async(self, request_iterator, timeout): |
||||
return _ReexportedFuture(self._underlying.async(request_iterator, timeout)) |
||||
|
||||
|
||||
class _Stub(interfaces.Stub): |
||||
|
||||
def __init__(self, assembly_stub, cardinalities): |
||||
self._assembly_stub = assembly_stub |
||||
self._cardinalities = cardinalities |
||||
|
||||
def __enter__(self): |
||||
self._assembly_stub.__enter__() |
||||
return self |
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb): |
||||
self._assembly_stub.__exit__(exc_type, exc_val, exc_tb) |
||||
return False |
||||
|
||||
def __getattr__(self, attr): |
||||
underlying_attr = self._assembly_stub.__getattr__(attr) |
||||
cardinality = self._cardinalities.get(attr) |
||||
if cardinality is interfaces.Cardinality.UNARY_UNARY: |
||||
return _UnaryUnarySyncAsync(underlying_attr) |
||||
elif cardinality is interfaces.Cardinality.UNARY_STREAM: |
||||
return lambda request, timeout: _CancellableIterator( |
||||
underlying_attr(request, timeout)) |
||||
elif cardinality is interfaces.Cardinality.STREAM_UNARY: |
||||
return _StreamUnarySyncAsync(underlying_attr) |
||||
elif cardinality is interfaces.Cardinality.STREAM_STREAM: |
||||
return lambda request_iterator, timeout: _CancellableIterator( |
||||
underlying_attr(request_iterator, timeout)) |
||||
else: |
||||
raise AttributeError(attr) |
||||
|
||||
def rpc_context(face_rpc_context): |
||||
return _RpcContext(face_rpc_context) |
||||
|
||||
|
||||
def stub(assembly_stub, cardinalities): |
||||
return _Stub(assembly_stub, cardinalities) |
@ -0,0 +1,48 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
"""Exceptions raised by GRPC. |
||||
|
||||
Only GRPC should instantiate and raise these exceptions. |
||||
""" |
||||
|
||||
import abc |
||||
|
||||
|
||||
class RpcError(Exception): |
||||
"""Common super type for all exceptions raised by GRPC.""" |
||||
__metaclass__ = abc.ABCMeta |
||||
|
||||
|
||||
class CancellationError(RpcError): |
||||
"""Indicates that an RPC has been cancelled.""" |
||||
|
||||
|
||||
class ExpirationError(RpcError): |
||||
"""Indicates that an RPC has expired ("timed out").""" |
@ -0,0 +1,176 @@ |
||||
# Copyright 2015, Google Inc. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
# TODO(nathaniel): Expand this test coverage. |
||||
|
||||
"""Test of the GRPC-backed ForeLink and RearLink.""" |
||||
|
||||
import unittest |
||||
|
||||
from grpc.early_adopter import implementations |
||||
from grpc.early_adopter import utilities |
||||
from grpc._junkdrawer import math_pb2 |
||||
|
||||
DIV = 'Div' |
||||
DIV_MANY = 'DivMany' |
||||
FIB = 'Fib' |
||||
SUM = 'Sum' |
||||
|
||||
def _fibbonacci(limit): |
||||
left, right = 0, 1 |
||||
for _ in xrange(limit): |
||||
yield left |
||||
left, right = right, left + right |
||||
|
||||
|
||||
def _div(request, unused_context): |
||||
return math_pb2.DivReply( |
||||
quotient=request.dividend / request.divisor, |
||||
remainder=request.dividend % request.divisor) |
||||
|
||||
|
||||
def _div_many(request_iterator, unused_context): |
||||
for request in request_iterator: |
||||
yield math_pb2.DivReply( |
||||
quotient=request.dividend / request.divisor, |
||||
remainder=request.dividend % request.divisor) |
||||
|
||||
|
||||
def _fib(request, unused_context): |
||||
for number in _fibbonacci(request.limit): |
||||
yield math_pb2.Num(num=number) |
||||
|
||||
|
||||
def _sum(request_iterator, unused_context): |
||||
accumulation = 0 |
||||
for request in request_iterator: |
||||
accumulation += request.num |
||||
return math_pb2.Num(num=accumulation) |
||||
|
||||
|
||||
_INVOCATION_DESCRIPTIONS = { |
||||
DIV: utilities.unary_unary_invocation_description( |
||||
math_pb2.DivArgs.SerializeToString, math_pb2.DivReply.FromString), |
||||
DIV_MANY: utilities.stream_stream_invocation_description( |
||||
math_pb2.DivArgs.SerializeToString, math_pb2.DivReply.FromString), |
||||
FIB: utilities.unary_stream_invocation_description( |
||||
math_pb2.FibArgs.SerializeToString, math_pb2.Num.FromString), |
||||
SUM: utilities.stream_unary_invocation_description( |
||||
math_pb2.Num.SerializeToString, math_pb2.Num.FromString), |
||||
} |
||||
|
||||
_SERVICE_DESCRIPTIONS = { |
||||
DIV: utilities.unary_unary_service_description( |
||||
_div, math_pb2.DivArgs.FromString, |
||||
math_pb2.DivReply.SerializeToString), |
||||
DIV_MANY: utilities.stream_stream_service_description( |
||||
_div_many, math_pb2.DivArgs.FromString, |
||||
math_pb2.DivReply.SerializeToString), |
||||
FIB: utilities.unary_stream_service_description( |
||||
_fib, math_pb2.FibArgs.FromString, math_pb2.Num.SerializeToString), |
||||
SUM: utilities.stream_unary_service_description( |
||||
_sum, math_pb2.Num.FromString, math_pb2.Num.SerializeToString), |
||||
} |
||||
|
||||
_TIMEOUT = 3 |
||||
|
||||
|
||||
class EarlyAdopterImplementationsTest(unittest.TestCase): |
||||
|
||||
def setUp(self): |
||||
self.server = implementations.insecure_server(_SERVICE_DESCRIPTIONS, 0) |
||||
self.server.start() |
||||
port = self.server.port() |
||||
self.stub = implementations.insecure_stub(_INVOCATION_DESCRIPTIONS, 'localhost', port) |
||||
|
||||
def tearDown(self): |
||||
self.server.stop() |
||||
|
||||
def testUpAndDown(self): |
||||
with self.stub: |
||||
pass |
||||
|
||||
def testUnaryUnary(self): |
||||
divisor = 59 |
||||
dividend = 973 |
||||
expected_quotient = dividend / divisor |
||||
expected_remainder = dividend % divisor |
||||
|
||||
with self.stub: |
||||
response = self.stub.Div( |
||||
math_pb2.DivArgs(divisor=divisor, dividend=dividend), _TIMEOUT) |
||||
self.assertEqual(expected_quotient, response.quotient) |
||||
self.assertEqual(expected_remainder, response.remainder) |
||||
|
||||
def testUnaryStream(self): |
||||
stream_length = 43 |
||||
|
||||
with self.stub: |
||||
response_iterator = self.stub.Fib( |
||||
math_pb2.FibArgs(limit=stream_length), _TIMEOUT) |
||||
numbers = tuple(response.num for response in response_iterator) |
||||
for early, middle, later in zip(numbers, numbers[:1], numbers[:2]): |
||||
self.assertEqual(early + middle, later) |
||||
self.assertEqual(stream_length, len(numbers)) |
||||
|
||||
def testStreamUnary(self): |
||||
stream_length = 127 |
||||
|
||||
with self.stub: |
||||
response_future = self.stub.Sum.async( |
||||
(math_pb2.Num(num=index) for index in range(stream_length)), |
||||
_TIMEOUT) |
||||
self.assertEqual( |
||||
(stream_length * (stream_length - 1)) / 2, |
||||
response_future.result().num) |
||||
|
||||
def testStreamStream(self): |
||||
stream_length = 179 |
||||
divisor_offset = 71 |
||||
dividend_offset = 1763 |
||||
|
||||
with self.stub: |
||||
response_iterator = self.stub.DivMany( |
||||
(math_pb2.DivArgs( |
||||
divisor=divisor_offset + index, |
||||
dividend=dividend_offset + index) |
||||
for index in range(stream_length)), |
||||
_TIMEOUT) |
||||
for index, response in enumerate(response_iterator): |
||||
self.assertEqual( |
||||
(dividend_offset + index) / (divisor_offset + index), |
||||
response.quotient) |
||||
self.assertEqual( |
||||
(dividend_offset + index) % (divisor_offset + index), |
||||
response.remainder) |
||||
self.assertEqual(stream_length, index + 1) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
unittest.main() |
Loading…
Reference in new issue