• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 The gRPC Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Reference implementation for status mapping in gRPC Python."""
15
16import collections
17import sys
18
19import grpc
20
21from google.rpc import status_pb2
22from ._common import code_to_grpc_status_code, GRPC_DETAILS_METADATA_KEY
23
24
25class _Status(
26        collections.namedtuple('_Status',
27                               ('code', 'details', 'trailing_metadata')),
28        grpc.Status):
29    pass
30
31
32def from_call(call):
33    """Returns a google.rpc.status.Status message corresponding to a given grpc.Call.
34
35    This is an EXPERIMENTAL API.
36
37    Args:
38      call: A grpc.Call instance.
39
40    Returns:
41      A google.rpc.status.Status message representing the status of the RPC.
42
43    Raises:
44      ValueError: If the gRPC call's code or details are inconsistent with the
45        status code and message inside of the google.rpc.status.Status.
46    """
47    if call.trailing_metadata() is None:
48        return None
49    for key, value in call.trailing_metadata():
50        if key == GRPC_DETAILS_METADATA_KEY:
51            rich_status = status_pb2.Status.FromString(value)
52            if call.code().value[0] != rich_status.code:
53                raise ValueError(
54                    'Code in Status proto (%s) doesn\'t match status code (%s)'
55                    % (code_to_grpc_status_code(rich_status.code), call.code()))
56            if call.details() != rich_status.message:
57                raise ValueError(
58                    'Message in Status proto (%s) doesn\'t match status details (%s)'
59                    % (rich_status.message, call.details()))
60            return rich_status
61    return None
62
63
64def to_status(status):
65    """Convert a google.rpc.status.Status message to grpc.Status.
66
67    This is an EXPERIMENTAL API.
68
69    Args:
70      status: a google.rpc.status.Status message representing the non-OK status
71        to terminate the RPC with and communicate it to the client.
72
73    Returns:
74      A grpc.Status instance representing the input google.rpc.status.Status message.
75    """
76    return _Status(code=code_to_grpc_status_code(status.code),
77                   details=status.message,
78                   trailing_metadata=((GRPC_DETAILS_METADATA_KEY,
79                                       status.SerializeToString()),))
80
81
82__all__ = [
83    'from_call',
84    'to_status',
85]
86
87if sys.version_info[0] >= 3 and sys.version_info[1] >= 6:
88    from . import _async as aio  # pylint: disable=unused-import
89    __all__.append('aio')
90