1# Copyright 2018 Google LLC 
    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#     https://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 
    15 
    16class MessageRule: 
    17    """A marshal for converting between a descriptor and proto.Message.""" 
    18 
    19    def __init__(self, descriptor: type, wrapper: type): 
    20        self._descriptor = descriptor 
    21        self._wrapper = wrapper 
    22 
    23    def to_python(self, value, *, absent: bool = None): 
    24        if isinstance(value, self._descriptor): 
    25            return self._wrapper.wrap(value) 
    26        return value 
    27 
    28    def to_proto(self, value): 
    29        if isinstance(value, self._wrapper): 
    30            return self._wrapper.pb(value) 
    31        if isinstance(value, dict) and not self.is_map: 
    32            # We need to use the wrapper's marshaling to handle 
    33            # potentially problematic nested messages. 
    34            try: 
    35                # Try the fast path first. 
    36                return self._descriptor(**value) 
    37            except (TypeError, ValueError, AttributeError) as ex: 
    38                # If we have a TypeError, ValueError or AttributeError, 
    39                # try the slow path in case the error 
    40                # was: 
    41                # - an int64/string issue. 
    42                # - a missing key issue in case a key only exists with a `_` suffix. 
    43                #   See related issue: https://github.com/googleapis/python-api-core/issues/227. 
    44                # - a missing key issue due to nested struct. See: https://github.com/googleapis/proto-plus-python/issues/424. 
    45                # - a missing key issue due to nested duration. See: https://github.com/googleapis/google-cloud-python/issues/13350. 
    46                return self._wrapper(value)._pb 
    47        return value 
    48 
    49    @property 
    50    def is_map(self): 
    51        """Return True if the descriptor is a map entry, False otherwise.""" 
    52        desc = self._descriptor.DESCRIPTOR 
    53        return desc.has_options and desc.GetOptions().map_entry