def document_client(service_name, official_name, service_model, client):
    """
    Generate low-level client documentation for a service. This generates
    documentation for all available operations.
    """
    docs = 'Client\n------\n\n'
    docs += '.. py:class:: {0}.Client\n\n'.format(service_name)
    docs += '   A low-level client representing {0}::\n\n'.format(
        official_name)
    docs += '       import boto3\n\n'
    docs += '       {service} = boto3.client(\'{service}\')\n\n'.format(
        service=service_name)

    wdoc = ''
    if client.waiter_names:
        # This gets included in alphabetical order below!
        wdoc += '   .. py:method:: get_waiter(name)\n\n'
        wdoc += '      Get a waiter by name. Available waiters:\n\n'
        for waiter in client.waiter_names:
            wdoc += '      * `{0}`_\n'.format(waiter)
        wdoc += '\n'

    waiter_included = False
    for operation_name in service_model.operation_names:
        if not waiter_included and xform_name(operation_name) > 'get_waiter':
            docs += wdoc
            waiter_included = True

        operation = service_model.operation_model(operation_name)
        docs += document_operation(
            operation, service_name,
            paginated=client.can_paginate(xform_name(operation_name)),
            example_instance='client', example_response='response')

    return docs
def document_collection(service_name, official_name, collection_model,
                        resource_model, service_model):
    """
    Generate reference documentation about a collection and any
    batch actions it might have.
    """
    title = collection_model.name + 'Collection'
    docs = '{0}\n{1}\n\n'.format(title, '-' * len(title))
    docs += '.. py:class:: {0}.{1}CollectionManager()\n\n'.format(
        service_name, collection_model.name)
    docs += ('   A collection of :py:class:`{0}.{1}` resources for {2}. See'
             '   the'
             '   :py:class:`~boto3.resources.collection.CollectionManager`'
             '   base class for additional methods.\n\n'
             '   This collection uses the :py:meth:`{3}.Client.{4}`'
             '   operation to get items, and its parameters can be'
             '   used as filters::\n\n').format(
                service_name, resource_model.name, official_name,
                service_name, xform_name(collection_model.request.operation))
    docs += ('       for {0} in {1}.{2}.all():\n'
             '           print({0})\n\n').format(
                xform_name(collection_model.resource.type),
                collection_model.parent_name,
                xform_name(collection_model.name),
                xform_name(collection_model.resource.type))

    if collection_model.batch_actions:
        docs += ('   .. rst-class:: admonition-title\n\n   Batch Actions\n\n'
                 '   Batch actions provide a way to manipulate groups of'
                 '   resources in a single service operation call.\n\n')
    for action in sorted(collection_model.batch_actions, key=lambda i:i.name):
        docs += document_action(action, service_name, resource_model,
                                service_model)

    return docs
def document_client_waiter(session, official_name, service_name,
                           service_model, client):
    waiter_spec_doc = ''
    if client.waiter_names:
        waiter_spec_doc = 'Waiter\n------\n\n'
        service_waiter_model = session.get_waiter_model(service_name)
        for waiter in service_waiter_model.waiter_names:
            snake_cased = xform_name(waiter)
            waiter_spec_doc += '{0}\n{1}\n\n'.format(snake_cased,
                '~' * len(snake_cased))
            waiter_model = service_waiter_model.get_waiter(waiter)
            operation_model = service_model.operation_model(
                waiter_model.operation)
            description = (
                '      This polls :py:meth:`{0}.Client.{1}` every {2} '
                'seconds until a successful state is reached. An error is '
                'returned after {3} failed checks.'.format(
                    service_name, xform_name(waiter_model.operation),
                    waiter_model.delay, waiter_model.max_attempts)
            )
            waiter_spec_doc += document_operation(
                operation_model=operation_model, service_name=service_name,
                operation_name='wait', rtype=None, description=description,
                example_instance='client.get_waiter(\'{0}\')'.format(
                    snake_cased))
        waiter_spec_doc += '\n'

    return waiter_spec_doc
Beispiel #4
0
def document_action(action, service_name, resource_model, service_model,
                    action_type='action'):
    """
    Document a resource action, including the low-level client operation
    and parameters.
    """
    try:
        operation_model = service_model.operation_model(
            action.request.operation)
    except:
        print('Cannot get operation ' + action.request.operation)
        return ''

    ignore_params = [p.target for p in action.request.params]

    rtype = 'dict'
    if action_type == 'action':
        description = ('      This method calls'
                       ' :py:meth:`{0}.Client.{1}`.').format(
                            service_name,
                            xform_name(action.request.operation))
        if action.resource:
            rtype = ':py:class:`{0}.{1}`'.format(
                service_name, action.resource.type)

            # Is the response plural? If so we are returning a list!
            if action.path and '[]' in action.path:
                rtype = 'list({0})'.format(rtype)

    return document_operation(
        operation_model, service_name, operation_name=xform_name(action.name),
        description=description, ignore_params=ignore_params, rtype=rtype)
def document_waiter(waiter, service_name, resource_model, service_model,
                    service_waiter_model):
    """
    Document a resource waiter, including the low-level client waiter
    and parameters.
    """
    try:
        waiter_model = service_waiter_model.get_waiter(waiter.waiter_name)
    except:
        print('Cannot get waiter ' + waiter.waiter_name)
        return ''

    try:
        operation_model = service_model.operation_model(waiter_model.operation)
    except:
        print('Cannot get operation ' + action.request.operation +
              ' for waiter ' + waiter.waiter_name)
        return ''
    description = ('      Waits until this {0} is {1}.\n'
                   '      This method calls ``wait()`` on'
                   ' :py:meth:`{2}.Client.get_waiter` using `{3}`_ .').format(
                        resource_model.name,
                        ' '.join(waiter.name.split('_')[2:]),
                        service_name,
                        xform_name(waiter.waiter_name))

    # Here we split because we only care about top-level parameter names
    ignore_params = [p.target.split('.')[0].strip('[]') for p in waiter.params]

    return document_operation(
        operation_model=operation_model, service_name=service_name,
        operation_name=xform_name(waiter.name),
        description=description,
        example_instance = xform_name(resource_model.name),
        ignore_params=ignore_params, rtype=None)
def _add_py_input_token(config):
    input_token = config['input_token']
    if isinstance(input_token, list):
        py_input_token = []
        for token in input_token:
            py_input_token.append(xform_name(token))
        config['py_input_token'] = py_input_token
    else:
        config['py_input_token'] = xform_name(input_token)
Beispiel #7
0
 def _make_client_call(self, client, operation_name, parameters,
                       parsed_globals):
     py_operation_name = xform_name(operation_name)
     if client.can_paginate(py_operation_name) and parsed_globals.paginate:
         paginator = client.get_paginator(py_operation_name)
         response = paginator.paginate(**parameters)
     else:
         response = getattr(client, xform_name(operation_name))(
             **parameters)
     return response
Beispiel #8
0
def _get_all_cli_input_tokens(operation):
    # Get all input tokens including the limit_key
    # if it exists.
    tokens = _get_input_tokens(operation)
    for token_name in tokens:
        cli_name = xform_name(token_name, '-')
        yield cli_name
    if 'limit_key' in operation.pagination:
        key_name = operation.pagination['limit_key']
        cli_name = xform_name(key_name, '-')
        yield cli_name
Beispiel #9
0
def _get_all_cli_input_tokens(pagination_config):
    # Get all input tokens including the limit_key
    # if it exists.
    tokens = _get_input_tokens(pagination_config)
    for token_name in tokens:
        cli_name = xform_name(token_name, "-")
        yield cli_name
    if "limit_key" in pagination_config:
        key_name = pagination_config["limit_key"]
        cli_name = xform_name(key_name, "-")
        yield cli_name
Beispiel #10
0
 def get_waiter(self, waiter_name):
     config = self._get_waiter_config()
     mapping = {}
     for name in config:
         mapping[xform_name(name)] = name
     if waiter_name not in mapping:
         raise ValueError("Waiter does not exist: %s" % waiter_name)
     single_waiter_config = config[mapping[waiter_name]]
     return waiter.Waiter(
         waiter_name,
         getattr(self, xform_name(single_waiter_config['operation'])),
         single_waiter_config)
Beispiel #11
0
    def document_resource_waiters(self, section):
        waiters = self._resource.meta.resource_model.waiters
        add_resource_type_overview(
            section=section,
            resource_type="Waiters",
            description=("Waiters provide an interface to wait for a resource" " to reach a specific state."),
            intro_link="waiters_intro",
        )
        waiter_list = []
        self.member_map["waiters"] = waiter_list
        for waiter in waiters:
            waiter_section = section.add_new_section(waiter.name)
            waiter_list.append(waiter.name)
            waiter_model = self._service_waiter_model.get_waiter(waiter.waiter_name)
            operation_model = self._service_model.operation_model(waiter_model.operation)

            ignore_params = get_resource_ignore_params(waiter.params)
            description = (
                "Waits until this %s is %s. This method calls "
                ":py:meth:`%s.Waiter.%s.wait` which polls. "
                ":py:meth:`%s.Client.%s` every %s seconds until "
                "a successful state is reached. An error is returned "
                "after %s failed checks."
                % (
                    self._resource_name,
                    " ".join(waiter.name.split("_")[2:]),
                    self._service_docs_name,
                    xform_name(waiter.waiter_name),
                    self._service_docs_name,
                    xform_name(waiter_model.operation),
                    waiter_model.delay,
                    waiter_model.max_attempts,
                )
            )
            example_prefix = "%s.%s" % (xform_name(self._resource_name), waiter.name)
            document_model_driven_method(
                section=waiter_section,
                method_name=waiter.name,
                operation_model=operation_model,
                event_emitter=self._resource.meta.client.meta.events,
                example_prefix=example_prefix,
                method_description=description,
                exclude_input=ignore_params,
            )
            if "return" in waiter_section.available_sections:
                # Waiters do not return anything so we should remove
                # any sections that may document the underlying return
                # value of the client method.
                return_section = waiter_section.get_section("return")
                return_section.clear_text()
                return_section.remove_all_sections()
                return_section.write(":returns: None")
Beispiel #12
0
def document_batch_action(section, resource_name, event_emitter,
                          batch_action_model, service_model, collection_model,
                          include_signature=True):
    """Documents a collection's batch action

    :param section: The section to write to

    :param resource_name: The name of the resource

    :param action_name: The name of collection action. Currently only
        can be all, filter, limit, or page_size

    :param event_emitter: The event emitter to use to emit events

    :param batch_action_model: The model of the batch action

    :param collection_model: The model of the collection

    :param service_model: The model of the service

    :param include_signature: Whether or not to include the signature.
        It is useful for generating docstrings.
    """
    operation_model = service_model.operation_model(
        batch_action_model.request.operation)
    ignore_params = get_resource_ignore_params(
        batch_action_model.request.params)

    example_return_value = 'response'
    if batch_action_model.resource:
        example_return_value = xform_name(batch_action_model.resource.type)

    example_resource_name = xform_name(resource_name)
    if service_model.service_name == resource_name:
        example_resource_name = resource_name
    example_prefix = '%s = %s.%s.%s' % (
        example_return_value, example_resource_name,
        collection_model.name, batch_action_model.name
    )
    document_model_driven_resource_method(
        section=section, method_name=batch_action_model.name,
        operation_model=operation_model,
        event_emitter=event_emitter,
        method_description=operation_model.documentation,
        example_prefix=example_prefix,
        exclude_input=ignore_params,
        resource_action_model=batch_action_model,
        include_signature=include_signature
    )
Beispiel #13
0
def add_pagination_configs(new_model, pagination):
    # Adding in pagination configs means copying the config to a top level
    # 'pagination' key in the new model, and it also means adding the
    # pagination config to each individual operation.
    # Also, the input_token needs to be transformed to the python specific
    # name, so we're adding a py_input_token (e.g. NextToken -> next_token).
    if pagination:
        new_model['pagination'] = pagination
    for name in pagination:
        config = pagination[name]
        _check_known_pagination_keys(config)
        if 'py_input_token' not in config:
            input_token = config['input_token']
            if isinstance(input_token, list):
                py_input_token = []
                for token in input_token:
                    py_input_token.append(xform_name(token))
                config['py_input_token'] = py_input_token
            else:
                config['py_input_token'] = xform_name(input_token)
        # result_key must be defined
        if 'result_key' not in config:
            raise ValueError("Required key 'result_key' is missing from "
                             "from pagination config: %s" % config)
        if name not in new_model['operations']:
            raise ValueError("Trying to add pagination config for non "
                             "existent operation: %s" % name)
        operation = new_model['operations'].get(name)
        # result_key must match a key in the output.
        if not isinstance(config['result_key'], list):
            result_keys = [config['result_key']]
        else:
            result_keys = config['result_key']
        if result_keys and not operation['output']:
            raise ValueError("Trying to add pagination config for an "
                             "operation with no output members: %s" % name)
        for result_key in result_keys:
            if resembles_jmespath_exp(result_key):
                continue
            if result_key not in operation['output']['members']:
                raise ValueError("result_key %r is not an output member: %s" %
                                (result_key,
                                 operation['output']['members'].keys()))
        _check_input_keys_match(config, operation)
        if operation is None:
            raise ValueError("Tried to add a pagination config for non "
                             "existent operation '%s'" % name)
        operation['pagination'] = config.copy()
Beispiel #14
0
    def _document_sub_resource(self, sub_resource_section, sub_resource):
        identifiers_needed = []
        for identifier in sub_resource.resource.identifiers:
            if identifier.source == 'input':
                identifiers_needed.append(xform_name(identifier.target))

        signature_args = get_identifier_args_for_signature(identifiers_needed)
        sub_resource_section.style.start_sphinx_py_method(
            sub_resource.name, signature_args)

        method_intro_section = sub_resource_section.add_new_section(
            'method-intro')
        description = 'Creates a %s resource.' % sub_resource.resource.type
        method_intro_section.include_doc_string(description)

        example_section = sub_resource_section.add_new_section('example')
        example_values = get_identifier_values_for_example(identifiers_needed)
        resource_name = xform_name(self._resource_name)
        if self.represents_service_resource:
            resource_name = self._resource_name
        example = '%s = %s.%s(%s)' % (
            xform_name(sub_resource.resource.type),
            resource_name,
            sub_resource.name, example_values
        )
        example_section.style.start_codeblock()
        example_section.write(example)
        example_section.style.end_codeblock()

        param_section = sub_resource_section.add_new_section('params')
        for identifier in identifiers_needed:
            description = get_identifier_description(
                sub_resource.name, identifier)
            param_section.write(':type %s: string' % identifier)
            param_section.style.new_line()
            param_section.write(':param %s: %s' % (
                identifier, description))
            param_section.style.new_line()

        return_section = sub_resource_section.add_new_section('return')
        return_section.style.new_line()
        return_section.write(
            ':rtype: :py:class:`%s.%s`' % (
                self._service_docs_name, sub_resource.resource.type))
        return_section.style.new_line()
        return_section.write(
            ':returns: A %s resource' % sub_resource.resource.type)
        return_section.style.new_line()
Beispiel #15
0
 def retrieve_candidate_values(self, service, operation, param):
     if service not in self._services_with_completions:
         return
     # Example call:
     # service='ec2', operation='terminate-instances',
     # param='--instance-ids'.
     # We need to convert this to botocore syntax.
     # First try to load the resource model.
     LOG.debug("Called with: %s, %s, %s", service, operation, param)
     # Now convert operation to the name used by botocore.
     client = self._get_client(service)
     api_operation_name = client.meta.method_to_api_mapping.get(
         operation.replace('-', '_'))
     if api_operation_name is None:
         return
     # Now we need to convert the param name to the
     # casing used by the API.
     completer = self._get_completer_for_service(service)
     result = completer.describe_autocomplete(
         service, api_operation_name, param)
     if result is None:
         return
     # DEBUG:awsshell.resource.index:RESULTS:
         # ServerCompletion(service=u'ec2', operation=u'DescribeInstances',
         # params={}, path=u'Reservations[].Instances[].InstanceId')
     try:
         response = getattr(client, xform_name(result.operation, '_'))()
     except Exception:
         return
     results = jmespath.search(result.path, response)
     return results
Beispiel #16
0
def create_request_parameters(parent, request_model):
    """
    Handle request parameters that can be filled in from identifiers,
    resource data members or constants.

    :type parent: ServiceResource
    :param parent: The resource instance to which this action is attached.
    :type request_model: :py:class:`~boto3.resources.model.Request`
    :param request_model: The action request model.
    :rtype: dict
    :return: Pre-filled parameters to be sent to the request operation.
    """
    params = {}

    for param in request_model.params:
        source = param.source
        source_type = param.source_type
        target = param.target

        if source_type in ['identifier', 'dataMember']:
            # Resource identifier, e.g. queue.url
            # If this is a dataMember then it may incur a load
            # action before returning the value.
            value = getattr(parent, xform_name(source))
        elif source_type in ['string', 'integer', 'boolean']:
            # These are hard-coded values in the definition
            value = source
        else:
            raise NotImplementedError(
                'Unsupported source type: {0}'.format(source_type))

        build_param_structure(params, target, value)

    return params
Beispiel #17
0
 def _create_methods(self, service_model):
     op_dict = {}
     for operation_name in service_model.operation_names:
         py_operation_name = xform_name(operation_name)
         op_dict[py_operation_name] = self._create_api_method(
             py_operation_name, operation_name, service_model)
     return op_dict
Beispiel #18
0
    def __call__(self, parent, *args, **kwargs):
        """
        Perform the wait operation after building operation
        parameters.

        :type parent: :py:class:`~boto3.resources.base.ServiceResource`
        :param parent: The resource instance to which this action is attached.
        """
        client_waiter_name = xform_name(self._waiter_model.waiter_name)

        # First, build predefined params and then update with the
        # user-supplied kwargs, which allows overriding the pre-built
        # params if needed.
        params = create_request_parameters(parent, self._waiter_model)
        params.update(kwargs)

        logger.info('Calling %s:%s with %r',
                    parent.meta.service_name,
                    self._waiter_resource_name, params)

        client = parent.meta.client
        waiter = client.get_waiter(client_waiter_name)
        response = waiter.wait(**params)

        logger.debug('Response: %r', response)
Beispiel #19
0
def select_service_and_operation():
    service_names = Session().get_available_services()
    service_completer = WordCompleter(service_names)
    service_name = prompt(u'Select service: ', completer=service_completer)
    if service_name not in service_names:
        click.secho(u'{} is not valid service'.format(service_name), fg='red')
        raise click.Abort()
    moto_client = get_moto_implementation(service_name)
    real_client = boto3.client(service_name, region_name='us-east-1')
    implemented = []
    not_implemented = []

    operation_names = [xform_name(op) for op in real_client.meta.service_model.operation_names]
    for op in operation_names:
        if moto_client and op in dir(moto_client):
            implemented.append(op)
        else:
            not_implemented.append(op)
    operation_completer = WordCompleter(operation_names)

    click.echo('==Current Implementation Status==')
    for operation_name in operation_names:
        check = 'X' if operation_name in implemented else ' '
        click.secho('[{}] {}'.format(check, operation_name))
    click.echo('=================================')
    operation_name = prompt(u'Select Operation: ', completer=operation_completer)

    if operation_name not in operation_names:
        click.secho('{} is not valid operation'.format(operation_name), fg='red')
        raise click.Abort()

    if operation_name in implemented:
        click.secho('{} is already implemented'.format(operation_name), fg='red')
        raise click.Abort()
    return service_name, operation_name
Beispiel #20
0
    def _load_name_with_category(self, names, name, category,
                                 snake_case=True):
        """
        Load a name with a given category, possibly renaming it
        if that name is already in use. The name will be stored
        in ``names`` and possibly be set up in ``self._renamed``.

        :type names: set
        :param names: Existing names (Python attributes, properties, or
                      methods) on the resource.
        :type name: string
        :param name: The original name of the value.
        :type category: string
        :param category: The value type, such as 'identifier' or 'action'
        :type snake_case: bool
        :param snake_case: True (default) if the name should be snake cased.
        """
        if snake_case:
            name = xform_name(name)

        if name in names:
            logger.debug('Renaming %s %s %s' % (self.name, category, name))
            self._renamed[(category, name)] = name + '_' + category
            name += '_' + category

            if name in names:
                # This isn't good, let's raise instead of trying to keep
                # renaming this value.
                raise ValueError('Problem renaming {0} {1} to {2}!'.format(
                    self.name, category, name))

        names.add(name)
Beispiel #21
0
 def _create_name_mapping(self, service_model):
     # py_name -> OperationName
     mapping = {}
     for operation_name in service_model.operation_names:
         py_operation_name = xform_name(operation_name)
         mapping[py_operation_name] = operation_name
     return mapping
Beispiel #22
0
    def __call__(self, parent, *args, **kwargs):
        """
        Perform the action's request operation after building operation
        parameters and build any defined resources from the response.

        :type parent: ServiceResource
        :param parent: The resource instance to which this action is attached.
        :rtype: dict or ServiceResource or list(ServiceResource)
        :return: The response, either as a raw dict or resource instance(s).
        """
        operation_name = xform_name(self.action_model.request.operation)

        # First, build predefined params and then update with the
        # user-supplied kwargs, which allows overriding the pre-built
        # params if needed.
        params = create_request_parameters(parent, self.action_model.request)
        params.update(kwargs)

        logger.info('Calling %s:%s with %r', parent.meta['service_name'],
            operation_name, params)

        response = getattr(parent.meta['client'], operation_name)(**params)

        logger.debug('Response: %r', response)

        return self.response_handler(parent, params, response)
Beispiel #23
0
def convert_keyname(obj):
    for key in obj.keys():
        new_key = xform_name(key)
        if new_key != key:
            obj[new_key] = obj[key]
            del obj[key]
    return obj
Beispiel #24
0
 def __init__(self, name, required=False, ptype='string',
              documentation=None):
     self.name = name
     self.py_name = xform_name(name)
     self.required = required
     self.type = ptype
     self.documentation = documentation
Beispiel #25
0
 def _create_argument_table(self):
     argument_table = OrderedDict()
     input_shape = self._operation_model.input_shape
     required_arguments = []
     arg_dict = {}
     if input_shape is not None:
         required_arguments = input_shape.required_members
         arg_dict = input_shape.members
     for arg_name, arg_shape in arg_dict.items():
         cli_arg_name = xform_name(arg_name, '-')
         arg_class = self.ARG_TYPES.get(arg_shape.type_name,
                                        self.DEFAULT_ARG_CLASS)
         is_required = arg_name in required_arguments
         event_emitter = self._session.get_component('event_emitter')
         arg_object = arg_class(
             name=cli_arg_name,
             argument_model=arg_shape,
             is_required=is_required,
             operation_model=self._operation_model,
             serialized_name=arg_name,
             event_emitter=event_emitter)
         arg_object.add_to_arg_table(argument_table)
     LOG.debug(argument_table)
     self._emit('building-argument-table.%s.%s' % (self._parent_name,
                                                   self._name),
                operation_model=self._operation_model,
                session=self._session,
                command=self,
                argument_table=argument_table)
     return argument_table
    def _add_paginator(self, section, paginator_name):
        section = section.add_new_section(paginator_name)

        # Docment the paginator class
        section.style.start_sphinx_py_class(
            class_name='%s.Paginator.%s' % (
                self._client.__class__.__name__, paginator_name))
        section.style.start_codeblock()
        section.style.new_line()

        # Document how to instantiate the paginator.
        section.write(
            'paginator = client.get_paginator(\'%s\')' % xform_name(
                paginator_name)
        )
        section.style.end_codeblock()
        section.style.new_line()
        # Get the pagination model for the particular paginator.
        paginator_config = self._service_paginator_model.get_paginator(
            paginator_name)
        document_paginate_method(
            section=section,
            paginator_name=paginator_name,
            event_emitter=self._client.meta.events,
            service_model=self._client.meta.service_model,
            paginator_config=paginator_config
        )
def test_json_errors_parsing():
    # The outputs/ directory has sample output responses
    # For each file in outputs/ there's a corresponding file
    # in expected/ that has the expected parsed response.
    base_dir = os.path.join(os.path.dirname(__file__), 'json')
    json_responses_dir = os.path.join(base_dir, 'errors')
    expected_parsed_dir = os.path.join(base_dir, 'expected')
    session = botocore.session.get_session()
    for json_response_file in os.listdir(json_responses_dir):
        # Files look like: 'datapipeline-create-pipeline.json'
        service_name, operation_name = os.path.splitext(
            json_response_file)[0].split('-', 1)
        expected_parsed_response = os.path.join(expected_parsed_dir,
                                                json_response_file)
        raw_response_file = os.path.join(json_responses_dir,
                                         json_response_file)
        with open(expected_parsed_response) as f:
            expected = json.load(f)
        service_model = session.get_service_model(service_name)
        operation_names = service_model.operation_names
        operation_model = None
        for op_name in operation_names:
            if xform_name(op_name) == operation_name.replace('-', '_'):
                operation_model = service_model.operation_model(op_name)
        with open(raw_response_file, 'rb') as f:
            raw_response_body = f.read()
        yield _test_parsed_response, raw_response_file, \
            raw_response_body, operation_model, expected
Beispiel #28
0
    def _build_waiter_state_cmd(self, waiter_name):
        # Get the waiter
        waiter_config = self._model.get_waiter(waiter_name)

        # Create the cli name for the waiter operation
        waiter_cli_name = xform_name(waiter_name, '-')

        # Obtain the name of the service operation that is used to implement
        # the specified waiter.
        operation_name = waiter_config.operation

        # Create an operation object to make a command for the waiter. The
        # operation object is used to generate the arguments for the waiter
        # state command.
        operation_model = self._service_model.operation_model(operation_name)

        waiter_state_command = WaiterStateCommand(
            name=waiter_cli_name, parent_name='wait',
            operation_caller=WaiterCaller(self._session, waiter_name),
            session=self._session,
            operation_model=operation_model,
        )
        # Build the top level description for the waiter state command.
        # Most waiters do not have a description so they need to be generated
        # using the waiter configuration.
        waiter_state_doc_builder = WaiterStateDocBuilder(waiter_config)
        description = waiter_state_doc_builder.build_waiter_state_description()
        waiter_state_command.DESCRIPTION = description
        return waiter_state_command
Beispiel #29
0
 def __init__(self, model, parent, handler, **kwargs):
     self._model = model
     self._parent = parent
     self._py_operation_name = xform_name(
         model.request.operation)
     self._handler = handler
     self._params = kwargs
Beispiel #30
0
    def get_attributes(self, shape):
        """
        Get a dictionary of attribute names to original name and shape
        models that represent the attributes of this resource. Looks
        like the following:

            {
                'some_name': ('SomeName', <Shape...>)
            }

        :type shape: botocore.model.Shape
        :param shape: The underlying shape for this resource.
        :rtype: dict
        :return: Mapping of resource attributes.
        """
        attributes = {}
        identifier_names = [i.name for i in self.identifiers]

        for name, member in shape.members.items():
            snake_cased = xform_name(name)
            if snake_cased in identifier_names:
                # Skip identifiers, these are set through other means
                continue
            snake_cased = self._get_name('attribute', snake_cased,
                                         snake_case=False)
            attributes[snake_cased] = (name, member)

        return attributes
Beispiel #31
0
 def _create_command_table(self):
     command_table = OrderedDict()
     service_model = self._get_service_model()
     for operation_name in service_model.operation_names:
         cli_name = xform_name(operation_name, '-')
         operation_model = service_model.operation_model(operation_name)
         command_table[cli_name] = ServiceOperation(
             name=cli_name,
             parent_name=self._name,
             session=self.session,
             operation_model=operation_model,
             operation_caller=CLIOperationCaller(self.session),
         )
     self.session.emit('building-command-table.%s' % self._name,
                       command_table=command_table,
                       session=self.session,
                       command_object=self)
     self._add_lineage(command_table)
     return command_table
Beispiel #32
0
 def invoke(self,
            service,
            operation,
            api_params,
            plan_variables,
            optional_api_params=None,
            query=None):
     # TODO: All of the params that come from prompting the user
     # are strings.  We need a way to convert values to their
     # appropriate types.  We can either add typing into the wizard
     # spec or we possibly auto-convert based on the service
     # model (or both).
     client = self._session.create_client(service)
     resolved_params = self._resolve_params(api_params, optional_api_params,
                                            plan_variables)
     response = getattr(client, xform_name(operation))(**resolved_params)
     if query is not None:
         response = jmespath.search(query, response)
     return response
Beispiel #33
0
    def _load_attributes(self, attrs, meta, model, service_model):
        """
        Load resource attributes based on the resource shape. The shape
        name is referenced in the resource JSON, but the shape itself
        is defined in the Botocore service JSON, hence the need for
        access to the ``service_model``.
        """
        if 'shape' in model:
            shape = service_model.shape_for(model.get('shape'))

            for name, member in shape.members.items():
                snake_cased = xform_name(name)
                if snake_cased in meta['identifiers']:
                    # Skip identifiers, these are set through other means
                    continue

                self._check_allowed_name(attrs, snake_cased)
                attrs[snake_cased] = self._create_autoload_property(
                    name, snake_cased)
Beispiel #34
0
def create_request_parameters(parent, request_def):
    """
    Handle request parameters that can be filled in from identifiers,
    resource data members or constants.

    :type parent: ServiceResource
    :param parent: The resource instance to which this action is attached.
    :type request_def: dict
    :param request_def: The action request definition.
    :rtype: dict
    :return: Pre-filled parameters to be sent to the request operation.
    """
    params = {}

    for param in request_def.get('params', []):
        source = param.get('source', '')
        source_type = param.get('sourceType', '')
        target = param.get('target', '')

        if source_type in ['identifier', 'dataMember']:
            # Resource identifier, e.g. queue.url
            # If this is a dataMember then it may incur a load
            # action before returning the value.
            value = getattr(parent, xform_name(source))
        elif source_type in ['string', 'integer', 'boolean']:
            # These are hard-coded values in the definition
            value = source
        else:
            raise NotImplementedError(
                'Unsupported source type: {0}'.format(source_type))

        # Basic reverse jmespath support for lists
        # TODO: I believe this may get added into jmespath eventually?
        # TODO: support foo.bar.baz and foo.bar[0].baz
        # jmespath.create_structure(params, target, value)
        if target.endswith('[]'):
            params[target[:-2]] = [value]
        elif target.endswith('[0]'):
            params[target[:-3]] = [value]
        else:
            params[target] = value

    return params
Beispiel #35
0
def _assert_collection_has_paginator_if_needed(client, service_name,
                                               resource_name,
                                               collection_model):
    underlying_operation_name = collection_model.request.operation
    # See if the operation can be paginated from the client.
    can_paginate_operation = client.can_paginate(
        xform_name(underlying_operation_name))
    # See if the operation looks paginated.
    looks_paginated = operation_looks_paginated(
        client.meta.service_model.operation_model(underlying_operation_name))
    # Make sure that if the operation looks paginated then there is
    # a paginator for the client to use for the collection.
    if not can_paginate_operation:
        assert_false(
            looks_paginated,
            'Collection %s on resource %s of service %s uses the operation '
            '%s, but the operation has no paginator even though it looks '
            'paginated.' % (collection_model.name, resource_name, service_name,
                            underlying_operation_name))
Beispiel #36
0
 def test_special_cases(self):
     # Some patterns don't actually match the rules we expect.
     self.assertEqual(xform_name('SwapEnvironmentCNAMEs'),
                      'swap_environment_cnames')
     self.assertEqual(xform_name('SwapEnvironmentCNAMEs', '-'),
                      'swap-environment-cnames')
     self.assertEqual(xform_name('CreateCachediSCSIVolume', '-'),
                      'create-cached-iscsi-volume')
     self.assertEqual(xform_name('DescribeCachediSCSIVolumes', '-'),
                      'describe-cached-iscsi-volumes')
     self.assertEqual(xform_name('DescribeStorediSCSIVolumes', '-'),
                      'describe-stored-iscsi-volumes')
     self.assertEqual(xform_name('CreateStorediSCSIVolume', '-'),
                      'create-stored-iscsi-volume')
def parse_fake_service_package(session: Session,
                               service_name: ServiceName) -> ServicePackage:
    """
    Create fake boto3 service module structure.

    Used by stubs and master package.

    Arguments:
        session -- boto3 session.
        service_name -- Target service name.

    Returns:
        ServiceModule structure.
    """
    shape_parser = ShapeParser(session, service_name)

    result = ServicePackage(
        name=service_name.module_name,
        pypi_name=service_name.pypi_name,
        service_name=service_name,
        client=Client(),
    )

    boto3_client = get_boto3_client(session, service_name)
    boto3_resource = get_boto3_resource(session, service_name)

    if boto3_resource is not None:
        result.service_resource = ServiceResource()

    for waiter_name in boto3_client.waiter_names:
        real_class_name = get_class_prefix(waiter_name)
        waiter_class_name = f"{real_class_name}Waiter"
        result.waiters.append(
            Waiter(waiter_class_name, waiter_name=waiter_name))

    for paginator_name in shape_parser.get_paginator_names():
        operation_name = xform_name(paginator_name)
        result.paginators.append(
            Paginator(f"{paginator_name}Paginator",
                      operation_name=operation_name))

    return result
Beispiel #38
0
def _assert_collection_has_paginator_if_needed(client, service_name,
                                               resource_name,
                                               collection_model):
    underlying_operation_name = collection_model.request.operation
    # See if the operation can be paginated from the client.
    can_paginate_operation = client.can_paginate(
        xform_name(underlying_operation_name))
    # See if the operation looks paginated.
    looks_paginated = operation_looks_paginated(
        client.meta.service_model.operation_model(underlying_operation_name))
    # Make sure that if the operation looks paginated then there is
    # a paginator for the client to use for the collection.
    if not can_paginate_operation:
        error_msg = (
            f'Collection {collection_model.name} on resource {resource_name} '
            f'of service {service_name} uses the operation '
            f'{underlying_operation_name}, but the operation has no paginator '
            f'even though it looks paginated.')

        assert not looks_paginated, error_msg
Beispiel #39
0
    def _get_name(self, category, name, snake_case=True):
        """
        Get a possibly renamed value given a category and name. This
        uses the rename map set up in ``load_rename_map``, so that
        method must be called once first.

        :type category: string
        :param category: The value type, such as 'identifier' or 'action'
        :type name: string
        :param name: The original name of the value
        :type snake_case: bool
        :param snake_case: True (default) if the name should be snake cased.
        :rtype: string
        :return: Either the renamed value if it is set, otherwise the
                 original name.
        """
        if snake_case:
            name = xform_name(name)

        return self._renamed.get((category, name), name)
Beispiel #40
0
    def _add_single_waiter(self, section, waiter_name):
        section = section.add_new_section(waiter_name)
        section.style.start_sphinx_py_class(
            class_name='%s.Waiter.%s' %
            (self._client.__class__.__name__, waiter_name))

        # Add example on how to instantiate waiter.
        section.style.start_codeblock()
        section.style.new_line()
        section.write('waiter = client.get_waiter(\'%s\')' %
                      xform_name(waiter_name))
        section.style.end_codeblock()

        # Add information on the wait() method
        section.style.new_line()
        document_wait_method(section=section,
                             waiter_name=waiter_name,
                             event_emitter=self._client.meta.events,
                             service_model=self._client.meta.service_model,
                             service_waiter_model=self._service_waiter_model)
Beispiel #41
0
    def _add_wait_method(self, section, waiter_name):
        waiter_model = self._service_waiter_model.get_waiter(waiter_name)
        operation_model = self._client.meta.service_model.operation_model(
            waiter_model.operation)

        wait_description = (
            'This polls :py:meth:`{0}.Client.{1}` every {2} '
            'seconds until a successful state is reached. An error is '
            'returned after {3} failed checks.'.format(
                self._client.__class__.__name__,
                xform_name(waiter_model.operation), waiter_model.delay,
                waiter_model.max_attempts))

        document_model_driven_method(section,
                                     'wait',
                                     operation_model,
                                     event_emitter=self._client.meta.events,
                                     method_description=wait_description,
                                     example_prefix='waiter.wait',
                                     document_output=False)
Beispiel #42
0
 def side_effect(self, *args, **kwargs):
     global account_id
     side_effect.self = self
     result = original_method(self, *args, **kwargs)
     if "ResponseMetadata" in result:
         result.pop("ResponseMetadata")
     result["ResponseMetadata"] = {
         "Parameters": args[1],
         "OperationName": args[0],
         "Generater": datetime.datetime.now(),
         "Region": self.meta.region_name,
         "Account": account_id,
     }
     fn = botocore.xform_name(args[0]) + "_" + get_params_hash(
         self.meta.region_name, args)
     if args[0] != "AssumeRole":
         with open(relative_path("json/" + target + "/" + fn + ".json"),
                   "w") as outfile:
             json.dump(result, outfile, indent=2, default=str)
     return result
Beispiel #43
0
    async def __call__(self, parent, *args, **kwargs):
        service_name = None
        client = None
        responses = []
        operation_name = xform_name(self._action_model.request.operation)

        # Unlike the simple action above, a batch action must operate
        # on batches (or pages) of items. So we get each page, construct
        # the necessary parameters and call the batch operation.
        async for page in parent.pages():
            params = {}
            for index, resource in enumerate(page):
                # There is no public interface to get a service name
                # or low-level client from a collection, so we get
                # these from the first resource in the collection.
                if service_name is None:
                    service_name = resource.meta.service_name
                if client is None:
                    client = resource.meta.client

                create_request_parameters(resource,
                                          self._action_model.request,
                                          params=params,
                                          index=index)

            if not params:
                # There are no items, no need to make a call.
                break

            params.update(kwargs)

            logger.debug('Calling %s:%s with %r', service_name, operation_name,
                         params)

            response = await (getattr(client, operation_name)(**params))

            logger.debug('Response: %r', response)

            responses.append(self._response_handler(parent, params, response))

        return responses
Beispiel #44
0
    def _load_actions(self, attrs, model, resource_defs, service_model):
        """
        Actions on the resource become methods, with the ``load`` method
        being a special case which sets internal data for attributes, and
        ``reload`` is an alias for ``load``.
        """
        if model.load:
            attrs['load'] = self._create_action('load',
                                                model.load,
                                                resource_defs,
                                                service_model,
                                                is_load=True)
            attrs['reload'] = attrs['load']

        for action in model.actions:
            snake_cased = xform_name(action.name)
            snake_cased = self._check_allowed_name(attrs, snake_cased,
                                                   'action', model.name)
            attrs[snake_cased] = self._create_action(snake_cased, action,
                                                     resource_defs,
                                                     service_model)
def calculate_implementation_coverage():
    service_names = Session().get_available_services()
    coverage = {}
    for service_name in service_names:
        moto_client = get_moto_implementation(service_name)
        real_client = boto3.client(service_name, region_name='us-east-1')
        implemented = []
        not_implemented = []

        operation_names = [xform_name(op) for op in real_client.meta.service_model.operation_names]
        for op in operation_names:
            if moto_client and op in dir(moto_client):
                implemented.append(op)
            else:
                not_implemented.append(op)

        coverage[service_name] = {
            'implemented': implemented,
            'not_implemented': not_implemented,
        }
    return coverage
Beispiel #46
0
    def svc_worker(que, params):
        """Worker thread for a service in a region.

        :param Queue que: APIs to invoke
        :param dict params: parameters to use for invoking API
        """
        svc_name = params['svc_name']
        region = params['region']
        storage = params['store']
        while True:
            try:
                svc_op = que.get()
                if svc_op is None:
                    break
                if storage.has_exceptions(svc_name, svc_op):
                    continue

                # this is the way botocore does it. See botocore/__init__.py
                py_op = botocore.xform_name(svc_op)
                LOGGER.debug('[%s][%s] Invoking API "%s". Python name "%s".',
                             region,
                             svc_name,
                             svc_op,
                             py_op)

                if not params['dry_run']:
                    if params['client'].can_paginate(py_op):
                        paginator = params['client'].get_paginator(py_op)
                        response = paginator.paginate().build_full_result()
                    else:
                        response = getattr(params['client'], py_op)()
                    storage.add_response(svc_name, region, svc_op, response)
            except Exception as e:
                storage.add_exception(svc_name, region, svc_op, e)
                LOGGER.exception(
                    'Unknown error while invoking API for service "%s" in region "%s".',
                    svc_name,
                    region)
            finally:
                que.task_done()
Beispiel #47
0
def select_service_and_operation():
    service_names = Session().get_available_services()
    service_completer = WordCompleter(service_names)
    service_name = prompt(u'Select service: ', completer=service_completer)
    if service_name not in service_names:
        click.secho(u'{} is not valid service'.format(service_name), fg='red')
        raise click.Abort()
    moto_client = get_moto_implementation(service_name)
    real_client = boto3.client(service_name, region_name='us-east-1')
    implemented = []
    not_implemented = []

    operation_names = [
        xform_name(op) for op in real_client.meta.service_model.operation_names
    ]
    for op in operation_names:
        if moto_client and op in dir(moto_client):
            implemented.append(op)
        else:
            not_implemented.append(op)
    operation_completer = WordCompleter(operation_names)

    click.echo('==Current Implementation Status==')
    for operation_name in operation_names:
        check = 'X' if operation_name in implemented else ' '
        click.secho('[{}] {}'.format(check, operation_name))
    click.echo('=================================')
    operation_name = prompt(u'Select Operation: ',
                            completer=operation_completer)

    if operation_name not in operation_names:
        click.secho('{} is not valid operation'.format(operation_name),
                    fg='red')
        raise click.Abort()

    if operation_name in implemented:
        click.secho('{} is already implemented'.format(operation_name),
                    fg='red')
        raise click.Abort()
    return service_name, operation_name
Beispiel #48
0
def select_service_and_operation():
    service_names = Session().get_available_services()
    service_completer = WordCompleter(service_names)
    service_name = prompt("Select service: ", completer=service_completer)
    if service_name not in service_names:
        click.secho("{} is not valid service".format(service_name), fg="red")
        raise click.Abort()
    moto_client = get_moto_implementation(service_name)
    real_client = boto3.client(service_name, region_name="us-east-1")
    implemented = []
    not_implemented = []

    operation_names = [
        xform_name(op) for op in real_client.meta.service_model.operation_names
    ]
    for operation in operation_names:
        if moto_client and operation in dir(moto_client):
            implemented.append(operation)
        else:
            not_implemented.append(operation)
    operation_completer = WordCompleter(operation_names)

    click.echo("==Current Implementation Status==")
    for operation_name in operation_names:
        check = "X" if operation_name in implemented else " "
        click.secho("[{}] {}".format(check, operation_name))
    click.echo("=================================")
    operation_name = prompt("Select Operation: ",
                            completer=operation_completer)

    if operation_name not in operation_names:
        click.secho("{} is not valid operation".format(operation_name),
                    fg="red")
        raise click.Abort()

    if operation_name in implemented:
        click.secho("{} is already implemented".format(operation_name),
                    fg="red")
        raise click.Abort()
    return service_name, operation_name
def document_wait_method(section,
                         waiter_name,
                         event_emitter,
                         service_model,
                         service_waiter_model,
                         include_signature=True):
    """Documents a the wait method of a waiter

    :param section: The section to write to

    :param waiter_name: The name of the waiter

    :param event_emitter: The event emitter to use to emit events

    :param service_model: The service model

    :param service_waiter_model: The waiter model associated to the service

    :param include_signature: Whether or not to include the signature.
        It is useful for generating docstrings.
    """
    waiter_model = service_waiter_model.get_waiter(waiter_name)
    operation_model = service_model.operation_model(waiter_model.operation)

    wait_description = (
        'Polls :py:meth:`{0}.Client.{1}` every {2} '
        'seconds until a successful state is reached. An error is '
        'returned after {3} failed checks.'.format(
            get_service_module_name(service_model),
            xform_name(waiter_model.operation), waiter_model.delay,
            waiter_model.max_attempts))

    document_model_driven_method(section,
                                 'wait',
                                 operation_model,
                                 event_emitter=event_emitter,
                                 method_description=wait_description,
                                 example_prefix='waiter.wait',
                                 document_output=False,
                                 include_signature=include_signature)
Beispiel #50
0
    def get_waiter(self, waiter_name):
        """Returns an object that can wait for some condition.

        :type waiter_name: str
        :param waiter_name: The name of the waiter to get. See the waiters
            section of the service docs for a list of available waiters.

        :returns: The specified waiter object.
        :rtype: botocore.waiter.Waiter
        """
        config = self._get_waiter_config()
        if not config:
            raise ValueError("Waiter does not exist: %s" % waiter_name)
        model = waiter.WaiterModel(config)
        mapping = {}
        for name in model.waiter_names:
            mapping[xform_name(name)] = name
        if waiter_name not in mapping:
            raise ValueError("Waiter does not exist: %s" % waiter_name)

        return waiter.create_waiter_with_client(mapping[waiter_name], model,
                                                self)
Beispiel #51
0
    def boto3_resources(self) -> list:
        services_summary = defaultdict(list)
        for service_name in self.merged_loader.boto3_available_services:
            service = self.session.resource(service_name)
            service_model = service.meta.client.meta.service_model
            service_id = service_model.metadata["serviceId"]
            service_definition = self.botocore_loader.load_service_model(service_name, type_name="resources-1")
            for collection_name, collection in service_definition["service"].get("hasMany", {}).items():

                resource_name = collection["resource"]["type"]
                try:
                    resource = service.resource(botocore.xform_name(resource_name), empty_resource=True)
                except StopIteration:
                    print(f"Could not find resource: {resource_name}")
                    continue
                subresource_summary = []
                for dependent_resource_type in resource.dependent_resource_types:
                    friendly_name = dependent_resource_type.replace("_", " ").title().replace(" ", "")
                    subresource_summary.append((friendly_name, friendly_name))
                services_summary[service_id].append((service_name, collection_name, resource_name, subresource_summary))

        return services_summary
Beispiel #52
0
        def resource(self,
                     resource_type: str,
                     identifiers: List[str] = None,
                     empty_resource=False) -> "CloudWandererServiceResource":
            """Get a Boto3 ServiceResource object for a resource that exists in this service.

            Specifying empty_resource=True will return a ServiceResource object which does not
            correspond to a specific resource in AWS but allows access to resource type metadata.

            Raises:
                UnsupportedResourceTypeError: Tried to get a collection model for a resource which does not have one.
            """
            for resource in self.meta.resource_model.subresources:
                resource_name = xform_name(resource.name)
                if resource_name == resource_type:
                    if empty_resource:
                        identifiers = [
                            "" for _ in resource.resource.model.identifiers
                        ]
                    return getattr(self, resource.name)(*identifiers)
            raise UnsupportedResourceTypeError(
                f"Could not find Boto3 resource for {resource_type}")
Beispiel #53
0
 def _unpack_argument(self, value):
     service_name = self.operation_object.service.endpoint_prefix
     operation_name = xform_name(self.operation_object.name, '-')
     # This is a two step process.  First we "load" the value.
     value_override = self._emit_first_response(
         'load-cli-arg.%s.%s' % (service_name, operation_name),
         param=self.argument_object, value=value,
         operation=self.operation_object)
     if value_override is not None:
         value = value_override
     # Then we "process/parse" the argument.
     override = self._emit_first_response('process-cli-arg.%s.%s' % (
         service_name, operation_name), param=self.argument_object,
         value=value,
         operation=self.operation_object)
     if override is not None:
         # A plugin supplied an alternate conversion,
         # use it instead.
         return override
     else:
         # Fall back to the default arg processing.
         return unpack_cli_arg(self.argument_object, value)
Beispiel #54
0
 def factory(
     cls,
     name: str,
     service_map: ServiceMap,
     definition: Dict[str, Any],
 ) -> "ResourceMap":
     return cls(
         name=name,
         type=ResourceIndependenceType[camel_to_snake(
             definition.get("type", "baseResource"))],
         region_request=ResourceRegionRequest.factory(
             definition.get("regionRequest")),
         regional_resource=definition.get("regionalResource", True),
         default_aws_resource_type_filter=AWSResourceTypeFilter(
             service=service_map.name,
             resource_type=botocore.xform_name(name),
             botocore_filters=definition.get("defaultBotocoreFilters", {}),
             jmespath_filters=definition.get("defaultJMESPathFilters", []),
         ),
         service_map=service_map,
         relationships=[
             RelationshipSpecification.factory(relationship_specification)
             for relationship_specification in definition.get(
                 "relationships", [])
         ],
         secondary_attribute_maps=[
             SecondaryAttributeMap(
                 source_path=mapping["sourcePath"],
                 destination_name=mapping["destinationName"])
             for mapping in definition.get("secondaryAttributeMaps", [])
         ],
         urn_overrides=[
             IdPartSpecification.factory(urn_override)
             for urn_override in definition.get("urnOverrides", [])
         ],
         requires_load=definition.get("requiresLoad", False),
         id_uniqueness_scope=ResourceIdUniquenessScope.factory(
             definition.get("idUniquenessScope", {})),
     )
Beispiel #55
0
    def _load_actions(self, attrs, model, resource_defs, service_model):
        """
        Actions on the resource become methods, with the ``load`` method
        being a special case which sets internal data for attributes, and
        ``reload`` is an alias for ``load``.
        """
        if 'load' in model:
            load_def = model.get('load')

            attrs['load'] = self._create_action('load',
                                                load_def,
                                                resource_defs,
                                                service_model,
                                                is_load=True)
            attrs['reload'] = attrs['load']

        for name, action in model.get('actions', {}).items():
            snake_cased = xform_name(name)
            self._check_allowed_name(attrs, snake_cased)
            attrs[snake_cased] = self._create_action(snake_cased, action,
                                                     resource_defs,
                                                     service_model)
    def _add_paginator(self, section, paginator_name):
        section = section.add_new_section(paginator_name)

        # Docment the paginator class
        section.style.start_sphinx_py_class(
            class_name='%s.Paginator.%s' %
            (self._client.__class__.__name__, paginator_name))
        section.style.start_codeblock()
        section.style.new_line()

        # Document how to instantiate the paginator.
        section.write('paginator = client.get_paginator(\'%s\')' %
                      xform_name(paginator_name))
        section.style.end_codeblock()
        section.style.new_line()
        # Get the pagination model for the particular paginator.
        paginator_config = self._service_paginator_model.get_paginator(
            paginator_name)
        document_paginate_method(section=section,
                                 paginator_name=paginator_name,
                                 event_emitter=self._client.meta.events,
                                 service_model=self._client.meta.service_model,
                                 paginator_config=paginator_config)
Beispiel #57
0
def _assert_has_waiter_documentation(generated_docs, service_name, client,
                                     waiter_model):
    ref_lines = [
        '=======',
        'Waiters',
        '=======',
        'The available waiters are:'
    ]
    for waiter_name in waiter_model.waiter_names:
        ref_lines.append(
            '* :py:class:`%s.Waiter.%s`' % (
                client.__class__.__name__, waiter_name))

    for waiter_name in waiter_model.waiter_names:
        ref_lines.append(
            '.. py:class:: %s.Waiter.%s' % (
                client.__class__.__name__, waiter_name))
        ref_lines.append(
            '    waiter = client.get_waiter(\'%s\')' % xform_name(waiter_name))
        ref_lines.append(
            '  .. py:method:: wait(')

    _assert_contains_lines_in_order(ref_lines, generated_docs)
def select_parameters_meta(module, conn, operation):
    """
    given an AWS API operation name, select those parameters that can be used for it
    """

    # we do _NOT_ enforce required parameters at this level.  That
    # should be enforced at the ansible argument parsing level to make
    # sure that incoming we have all we need and then that gets
    # checked by botocore at the moment the API call is actually made.

    params = {}

    operations_model = conn._service_model.operation_model(operation)
    relevant_parameters = operations_model.input_shape.members.keys()
    for k in relevant_parameters:
        try:
            v = module.params[xform_name(k)]
            if v is not None:
                params[k] = v
        except KeyError:
            pass

    return params
Beispiel #59
0
    def _create_argument_table(self):
        argument_table = OrderedDict()
        input_shape = self._operation_model.input_shape
        required_arguments = []
        arg_dict = {}

        if input_shape is not None:
            required_arguments = input_shape.required_members
            arg_dict = input_shape.members
        for arg_name, arg_shape in arg_dict.items():
            cli_arg_name = xform_name(arg_name, '-')
            arg_class = self.ARG_TYPES.get(arg_shape.type_name,
                                           self.DEFAULT_ARG_CLASS)
            is_token = arg_shape.metadata.get('idempotencyToken', False)
            is_required = arg_name in required_arguments and not is_token
            arg_object = arg_class(name=cli_arg_name,
                                   argument_model=arg_shape,
                                   is_required=is_required,
                                   operation_model=self._operation_model,
                                   serialized_name=arg_name,
                                   event_emitter=None)
            arg_object.add_to_arg_table(argument_table)
        return argument_table
    def _get_resource_method(self, resource_name: str, action_name: str,
                             action_shape: Dict[str, Any]) -> Method:
        return_type: FakeAnnotation = Type.none
        method_name = xform_name(action_name)
        arguments: List[Argument] = [Argument("self", None)]
        if "resource" in action_shape:
            return_type = self._parse_return_type(
                resource_name, method_name,
                Shape("resource", action_shape["resource"]))
            path = action_shape["resource"].get("path", "")
            if path.endswith("[]"):
                return_type = TypeSubscript(Type.List, [return_type])

        if "request" in action_shape:
            operation_name = action_shape["request"]["operation"]
            operation_shape = self._get_operation(operation_name)
            skip_argument_names: List[str] = [
                i["target"] for i in action_shape["request"].get("params", {})
                if i["source"] == "identifier"
            ]
            if operation_shape.input_shape is not None:
                for argument in self._parse_arguments(
                        resource_name,
                        method_name,
                        operation_name,
                        operation_shape.input_shape,
                ):
                    if argument.name not in skip_argument_names:
                        arguments.append(argument)
            if operation_shape.output_shape is not None and return_type is Type.none:
                operation_return_type = self._parse_shape(
                    operation_shape.output_shape)
                return_type = operation_return_type

        return Method(name=method_name,
                      arguments=arguments,
                      return_type=return_type)