def make_method(
        name: str, input_message: wrappers.MessageType = None,
        output_message: wrappers.MessageType = None,
        package: str = 'foo.bar.v1', module: str = 'baz',
        **kwargs) -> wrappers.Method:
    # Use default input and output messages if they are not provided.
    input_message = input_message or make_message('MethodInput')
    output_message = output_message or make_message('MethodOutput')

    # Create the method pb2.
    method_pb = descriptor_pb2.MethodDescriptorProto(
        name=name,
        input_type=str(input_message.meta.address),
        output_type=str(output_message.meta.address),
    )

    # Instantiate the wrapper class.
    return wrappers.Method(
        method_pb=method_pb,
        input=input_message,
        output=output_message,
        meta=metadata.Metadata(address=metadata.Address(
            package=package,
            module=module,
        )),
    )
Beispiel #2
0
def get_method(
    name: str,
    in_type: str,
    out_type: str,
    lro_response_type: str = '',
    lro_metadata_type: str = '',
    http_rule: http_pb2.HttpRule = None,
) -> wrappers.Method:
    input_ = get_message(in_type)
    output = get_message(out_type)

    # Define a method descriptor. Set the field headers if appropriate.
    method_pb = descriptor_pb2.MethodDescriptorProto(
        name=name,
        input_type=input_.proto_path,
        output_type=output.proto_path,
    )
    if lro_response_type:
        output = wrappers.OperationType(
            lro_response=get_message(lro_response_type),
            lro_metadata=get_message(lro_metadata_type),
        )
    if http_rule:
        ext_key = annotations_pb2.http
        method_pb.options.Extensions[ext_key].MergeFrom(http_rule)

    return wrappers.Method(
        method_pb=method_pb,
        input=input_,
        output=output,
    )
Beispiel #3
0
def get_method(name: str,
        in_type: str,
        out_type: str,
        lro_response_type: str = '',
        lro_metadata_type: str = '', *,
        in_fields: typing.Tuple[descriptor_pb2.FieldDescriptorProto] = (),
        http_rule: http_pb2.HttpRule = None,
        method_signature: str = '',
        ) -> wrappers.Method:
    input_ = get_message(in_type, fields=in_fields)
    output = get_message(out_type)

    # Define a method descriptor. Set the field headers if appropriate.
    method_pb = descriptor_pb2.MethodDescriptorProto(
        name=name,
        input_type=input_.ident.proto,
        output_type=output.ident.proto,
    )
    if lro_response_type:
        output = wrappers.OperationType(
            lro_response=get_message(lro_response_type),
            lro_metadata=get_message(lro_metadata_type),
        )
    if http_rule:
        ext_key = annotations_pb2.http
        method_pb.options.Extensions[ext_key].MergeFrom(http_rule)
    if method_signature:
        ext_key = client_pb2.method_signature
        method_pb.options.Extensions[ext_key].append(method_signature)

    return wrappers.Method(
        method_pb=method_pb,
        input=input_,
        output=output,
    )
def make_method(
        name: str,
        input_message: wrappers.MessageType = None,
        output_message: wrappers.MessageType = None,
        package: typing.Union[typing.Tuple[str], str] = 'foo.bar.v1',
        module: str = 'baz',
        http_rule: http_pb2.HttpRule = None,
        signatures: typing.Sequence[str] = (),
        is_deprecated: bool = False,
        routing_rule: routing_pb2.RoutingRule = None,
        **kwargs
) -> wrappers.Method:
    # Use default input and output messages if they are not provided.
    input_message = input_message or make_message('MethodInput')
    output_message = output_message or make_message('MethodOutput')

    # Create the method pb2.
    method_pb = desc.MethodDescriptorProto(
        name=name,
        input_type=str(input_message.meta.address),
        output_type=str(output_message.meta.address),
        **kwargs
    )

    if routing_rule:
        ext_key = routing_pb2.routing
        method_pb.options.Extensions[ext_key].MergeFrom(routing_rule)

    # If there is an HTTP rule, process it.
    if http_rule:
        ext_key = annotations_pb2.http
        method_pb.options.Extensions[ext_key].MergeFrom(http_rule)

    # If there are signatures, include them.
    for sig in signatures:
        ext_key = client_pb2.method_signature
        method_pb.options.Extensions[ext_key].append(sig)

    if isinstance(package, str):
        package = tuple(package.split('.'))

    if is_deprecated:
        method_pb.options.deprecated = True

    # Instantiate the wrapper class.
    return wrappers.Method(
        method_pb=method_pb,
        input=input_message,
        output=output_message,
        meta=metadata.Metadata(address=metadata.Address(
            name=name,
            package=package,
            module=module,
            parent=(f'{name}Service',),
        )),
    )
Beispiel #5
0
    def _get_methods(
        self,
        methods: Sequence[descriptor_pb2.MethodDescriptorProto],
        address: metadata.Address,
        path: Tuple[int, ...],
    ) -> Mapping[str, wrappers.Method]:
        """Return a dictionary of wrapped methods for the given service.

        Args:
            methods (Sequence[~.descriptor_pb2.MethodDescriptorProto]): A
                sequence of protobuf method objects.
            address (~.metadata.Address): An address object denoting the
                location of these methods.
            path (Tuple[int]): The source location path thus far, as understood
                by ``SourceCodeInfo.Location``.

        Returns:
            Mapping[str, ~.wrappers.Method]: A ordered mapping of
                :class:`~.wrappers.Method` objects.
        """
        # Iterate over the methods and collect them into a dictionary.
        answer: Dict[str, wrappers.Method] = collections.OrderedDict()
        for meth_pb, i in zip(methods, range(0, sys.maxsize)):
            lro = None

            # If the output type is google.longrunning.Operation, we use
            # a specialized object in its place.
            if meth_pb.output_type.endswith('google.longrunning.Operation'):
                op = meth_pb.options.Extensions[operations_pb2.operation_info]
                if not op.response_type or not op.metadata_type:
                    raise TypeError(
                        f'rpc {meth_pb.name} returns a google.longrunning.'
                        'Operation, but is missing a response type or '
                        'metadata type.', )
                lro = wrappers.OperationInfo(
                    response_type=self.api_messages[address.resolve(
                        op.response_type, )],
                    metadata_type=self.api_messages[address.resolve(
                        op.metadata_type, )],
                )

            # Create the method wrapper object.
            answer[meth_pb.name] = wrappers.Method(
                input=self.api_messages[meth_pb.input_type.lstrip('.')],
                lro=lro,
                method_pb=meth_pb,
                meta=metadata.Metadata(
                    address=address.child(meth_pb.name, path + (i, )),
                    documentation=self.docs.get(path + (i, ), self.EMPTY),
                ),
                output=self.api_messages[meth_pb.output_type.lstrip('.')],
            )

        # Done; return the answer.
        return answer
    def _get_methods(
        self,
        methods: List[descriptor_pb2.MethodDescriptorProto],
        address: metadata.Address,
        path: Tuple[int],
    ) -> Mapping[str, wrappers.Method]:
        """Return a dictionary of wrapped methods for the given service.

        Args:
            methods (Sequence[~.descriptor_pb2.MethodDescriptorProto]): A
                sequence of protobuf method objects.
            address (~.metadata.Address): An address object denoting the
                location of these methods.
            path (Tuple[int]): The source location path thus far, as understood
                by ``SourceCodeInfo.Location``.

        Returns:
            Mapping[str, ~.wrappers.Method]: A ordered mapping of
                :class:`~.wrappers.Method` objects.
        """
        # Iterate over the methods and collect them into a dictionary.
        answer = collections.OrderedDict()
        for meth_pb, i in zip(methods, range(0, sys.maxsize)):
            types = meth_pb.options.Extensions[operations_pb2.operation_types]

            # If the output type is google.longrunning.Operation, we use
            # a specialized object in its place.
            output_type = self.all_messages[meth_pb.output_type.lstrip('.')]
            if meth_pb.output_type.endswith('google.longrunning.Operation'):
                output_type = self._get_operation_type(
                    response_type=self.all_messages[address.resolve(
                        types.response)],
                    metadata_type=self.all_messages.get(
                        address.resolve(types.metadata), ),
                )

            # Create the method wrapper object.
            answer[meth_pb.name] = wrappers.Method(
                input=self.all_messages[meth_pb.input_type.lstrip('.')],
                method_pb=meth_pb,
                meta=metadata.Metadata(
                    address=address,
                    documentation=self.docs.get(path + (i, ), self.EMPTY),
                ),
                output=output_type,
            )

        # Done; return the answer.
        return answer
    def _get_methods(self,
                     methods: Sequence[descriptor_pb2.MethodDescriptorProto],
                     service_address: metadata.Address, path: Tuple[int, ...],
                     ) -> Mapping[str, wrappers.Method]:
        """Return a dictionary of wrapped methods for the given service.

        Args:
            methods (Sequence[~.descriptor_pb2.MethodDescriptorProto]): A
                sequence of protobuf method objects.
            service_address (~.metadata.Address): An address object for the
                service, denoting the location of these methods.
            path (Tuple[int]): The source location path thus far, as understood
                by ``SourceCodeInfo.Location``.

        Returns:
            Mapping[str, ~.wrappers.Method]: A ordered mapping of
                :class:`~.wrappers.Method` objects.
        """
        # Iterate over the methods and collect them into a dictionary.
        answer: Dict[str, wrappers.Method] = collections.OrderedDict()
        for i, meth_pb in enumerate(methods):
            retry, timeout = self._get_retry_and_timeout(
                service_address,
                meth_pb
            )

            # Create the method wrapper object.
            answer[meth_pb.name] = wrappers.Method(
                input=self.api_messages[meth_pb.input_type.lstrip('.')],
                lro=self._maybe_get_lro(service_address, meth_pb),
                extended_lro=self._maybe_get_extended_lro(
                    service_address,
                    meth_pb,
                ),
                method_pb=meth_pb,
                meta=metadata.Metadata(
                    address=service_address.child(meth_pb.name, path + (i,)),
                    documentation=self.docs.get(path + (i,), self.EMPTY),
                ),
                output=self.api_messages[meth_pb.output_type.lstrip('.')],
                retry=retry,
                timeout=timeout,
            )

        # Done; return the answer.
        return answer
Beispiel #8
0
def make_method(name: str,
                input_message: wrappers.MessageType = None,
                output_message: wrappers.MessageType = None,
                package: str = 'foo.bar.v1',
                module: str = 'baz',
                http_rule: http_pb2.HttpRule = None,
                signatures: Sequence[str] = (),
                **kwargs) -> wrappers.Method:
    # Use default input and output messages if they are not provided.
    input_message = input_message or make_message('MethodInput')
    output_message = output_message or make_message('MethodOutput')

    # Create the method pb2.
    method_pb = descriptor_pb2.MethodDescriptorProto(
        name=name,
        input_type=str(input_message.meta.address),
        output_type=str(output_message.meta.address),
        **kwargs)

    # If there is an HTTP rule, process it.
    if http_rule:
        ext_key = annotations_pb2.http
        method_pb.options.Extensions[ext_key].MergeFrom(http_rule)

    # If there are signatures, include them.
    for sig in signatures:
        ext_key = client_pb2.method_signature
        method_pb.options.Extensions[ext_key].append(sig)

    # Instantiate the wrapper class.
    return wrappers.Method(
        method_pb=method_pb,
        input=input_message,
        output=output_message,
        meta=metadata.Metadata(address=metadata.Address(
            name=name,
            package=package,
            module=module,
            parent=(f'{name}Service', ),
        )),
    )
Beispiel #9
0
    def _get_methods(
        self,
        methods: Sequence[descriptor_pb2.MethodDescriptorProto],
        service_address: metadata.Address,
        path: Tuple[int, ...],
    ) -> Mapping[str, wrappers.Method]:
        """Return a dictionary of wrapped methods for the given service.

        Args:
            methods (Sequence[~.descriptor_pb2.MethodDescriptorProto]): A
                sequence of protobuf method objects.
            service_address (~.metadata.Address): An address object for the
                service, denoting the location of these methods.
            path (Tuple[int]): The source location path thus far, as understood
                by ``SourceCodeInfo.Location``.

        Returns:
            Mapping[str, ~.wrappers.Method]: A ordered mapping of
                :class:`~.wrappers.Method` objects.
        """
        # Iterate over the methods and collect them into a dictionary.
        answer: Dict[str, wrappers.Method] = collections.OrderedDict()
        for meth_pb, i in zip(methods, range(0, sys.maxsize)):
            lro = None

            # If the output type is google.longrunning.Operation, we use
            # a specialized object in its place.
            if meth_pb.output_type.endswith('google.longrunning.Operation'):
                op = meth_pb.options.Extensions[operations_pb2.operation_info]
                if not op.response_type or not op.metadata_type:
                    raise TypeError(
                        f'rpc {meth_pb.name} returns a google.longrunning.'
                        'Operation, but is missing a response type or '
                        'metadata type.', )
                lro = wrappers.OperationInfo(
                    response_type=self.api_messages[service_address.resolve(
                        op.response_type, )],
                    metadata_type=self.api_messages[service_address.resolve(
                        op.metadata_type, )],
                )

            # If we got a gRPC service config, get the appropriate retry
            # and timeout information from it.
            retry = None
            timeout = None

            # This object should be a dictionary that conforms to the
            # gRPC service config proto:
            #   Repo: https://github.com/grpc/grpc-proto/
            #   Filename: grpc/service_config/service_config.proto
            #
            # We only care about a small piece, so we are just leaving
            # it as a dictionary and parsing accordingly.
            if self.opts.retry:
                # The gRPC service config uses a repeated `name` field
                # with a particular format, which we match against.
                # This defines the expected selector for *this* method.
                selector = {
                    'service':
                    '{package}.{service_name}'.format(
                        package='.'.join(service_address.package),
                        service_name=service_address.name,
                    ),
                    'method':
                    meth_pb.name,
                }

                # Find the method config that applies to us, if any.
                mc = next((i for i in self.opts.retry.get('methodConfig', [])
                           if selector in i.get('name')), None)
                if mc:
                    # Set the timeout according to this method config.
                    if mc.get('timeout'):
                        timeout = self._to_float(mc['timeout'])

                    # Set the retry according to this method config.
                    if 'retryPolicy' in mc:
                        r = mc['retryPolicy']
                        retry = wrappers.RetryInfo(
                            max_attempts=r.get('maxAttempts', 0),
                            initial_backoff=self._to_float(
                                r.get('initialBackoff', '0s'), ),
                            max_backoff=self._to_float(
                                r.get('maxBackoff', '0s'), ),
                            backoff_multiplier=r.get('backoffMultiplier', 0.0),
                            retryable_exceptions=frozenset(
                                exceptions.exception_class_for_grpc_status(
                                    getattr(grpc.StatusCode, code), )
                                for code in r.get('retryableStatusCodes', [])),
                        )

            # Create the method wrapper object.
            answer[meth_pb.name] = wrappers.Method(
                input=self.api_messages[meth_pb.input_type.lstrip('.')],
                lro=lro,
                method_pb=meth_pb,
                meta=metadata.Metadata(
                    address=service_address.child(meth_pb.name, path + (i, )),
                    documentation=self.docs.get(path + (i, ), self.EMPTY),
                ),
                output=self.api_messages[meth_pb.output_type.lstrip('.')],
                retry=retry,
                timeout=timeout,
            )

        # Done; return the answer.
        return answer