def test_exclude_output(self): self.add_shape_to_params('Biz', 'String') document_model_driven_method( self.doc_structure, 'foo', self.operation_model, event_emitter=self.event_emitter, method_description='This describes the foo method.', example_prefix='response = client.foo', exclude_output=['Bar'] ) self.assert_contains_lines_in_order([ '.. py:method:: foo(**kwargs)', ' This describes the foo method.', ' **Request Syntax**', ' ::', ' response = client.foo(', ' Bar=\'string\'', ' Biz=\'string\'', ' )', ' :type Biz: string', ' :param Biz:', ' :rtype: dict', ' :returns:', ' **Response Syntax**', ' ::', ' {', ' \'Biz\': \'string\'', ' }', ' **Response Structure**', ' - *(dict) --*', ' - **Biz** *(string) --*' ]) self.assert_not_contains_lines([ '\'Bar\': \'string\'', '- **Bar** *(string) --*', ])
def test_include_output(self): include_params = [ DocumentedShape( name='Biz', type_name='string', documentation='biz docs') ] document_model_driven_method( self.doc_structure, 'foo', self.operation_model, event_emitter=self.event_emitter, method_description='This describes the foo method.', example_prefix='response = client.foo', include_output=include_params ) self.assert_contains_lines_in_order([ '.. py:method:: foo(**kwargs)', ' This describes the foo method.', ' **Request Syntax**', ' ::', ' response = client.foo(', ' Bar=\'string\'', ' )', ' :type Bar: string', ' :param Bar:', ' :rtype: dict', ' :returns:', ' **Response Syntax**', ' ::', ' {', ' \'Bar\': \'string\'', ' \'Biz\': \'string\'', ' }', ' **Response Structure**', ' - *(dict) --*', ' - **Bar** *(string) --*', ' - **Biz** *(string) --*' ])
def test_default(self): document_model_driven_method( self.doc_structure, 'foo', self.operation_model, event_emitter=self.event_emitter, method_description='This describes the foo method.', example_prefix='response = client.foo' ) self.assert_contains_lines_in_order([ '.. py:method:: foo(**kwargs)', ' This describes the foo method.', # cross_ref_link, ' **Request Syntax**', ' ::', ' response = client.foo(', ' Bar=\'string\'', ' )', ' :type Bar: string', ' :param Bar:', ' :rtype: dict', ' :returns:', ' **Response Syntax**', ' ::', ' {', ' \'Bar\': \'string\'', ' }', ' **Response Structure**', ' - *(dict) --*', ' - **Bar** *(string) --*' ])
def document_model_driven_resource_method( section, method_name, operation_model, event_emitter, method_description=None, example_prefix=None, include_input=None, include_output=None, exclude_input=None, exclude_output=None, document_output=True, resource_action_model=None, include_signature=True, ): document_model_driven_method( section=section, method_name=method_name, operation_model=operation_model, event_emitter=event_emitter, method_description=method_description, example_prefix=example_prefix, include_input=include_input, include_output=include_output, exclude_input=exclude_input, exclude_output=exclude_output, document_output=document_output, include_signature=include_signature, ) # If this action returns a resource modify the return example to # appropriately reflect that. if resource_action_model.resource: if 'return' in section.available_sections: section.delete_section('return') resource_type = resource_action_model.resource.type new_return_section = section.add_new_section('return') return_resource_type = '{}.{}'.format( operation_model.service_model.service_name, resource_type) return_type = f':py:class:`{return_resource_type}`' return_description = f'{resource_type} resource' if _method_returns_resource_list(resource_action_model.resource): return_type = f'list({return_type})' return_description = f'A list of {resource_type} resources' new_return_section.style.new_line() new_return_section.write(f':rtype: {return_type}') new_return_section.style.new_line() new_return_section.write(f':returns: {return_description}') new_return_section.style.new_line()
def test_streaming_body_in_output(self): self.add_shape_to_params('Body', 'Blob') self.json_model['shapes']['Blob'] = {'type': 'blob'} self.json_model['shapes']['SampleOperationInputOutput']['payload'] = \ 'Body' document_model_driven_method( self.doc_structure, 'foo', self.operation_model, event_emitter=self.event_emitter, method_description='This describes the foo method.', example_prefix='response = client.foo' ) self.assert_contains_line('**Body** (:class:`.StreamingBody`)')
def document_resource_waiter( section, resource_name, event_emitter, service_model, resource_waiter_model, service_waiter_model, include_signature=True, ): waiter_model = service_waiter_model.get_waiter( resource_waiter_model.waiter_name ) operation_model = service_model.operation_model(waiter_model.operation) ignore_params = get_resource_ignore_params(resource_waiter_model.params) service_module_name = get_service_module_name(service_model) description = ( 'Waits until this {} is {}. This method calls ' ':py:meth:`{}.Waiter.{}.wait` which polls. ' ':py:meth:`{}.Client.{}` every {} seconds until ' 'a successful state is reached. An error is returned ' 'after {} failed checks.'.format( resource_name, ' '.join(resource_waiter_model.name.split('_')[2:]), service_module_name, xform_name(resource_waiter_model.waiter_name), service_module_name, xform_name(waiter_model.operation), waiter_model.delay, waiter_model.max_attempts, ) ) example_prefix = '{}.{}'.format( xform_name(resource_name), resource_waiter_model.name ) document_model_driven_method( section=section, method_name=resource_waiter_model.name, operation_model=operation_model, event_emitter=event_emitter, example_prefix=example_prefix, method_description=description, exclude_input=ignore_params, include_signature=include_signature, ) if 'return' in 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 = section.get_section('return') return_section.clear_text() return_section.remove_all_sections() return_section.write(':returns: None')
def document_model_driven_resource_method(section, method_name, operation_model, event_emitter, method_description=None, example_prefix=None, include_input=None, include_output=None, exclude_input=None, exclude_output=None, document_output=True, resource_action_model=None, include_signature=True): document_model_driven_method(section=section, method_name=method_name, operation_model=operation_model, event_emitter=event_emitter, method_description=method_description, example_prefix=example_prefix, include_input=include_input, include_output=include_output, exclude_input=exclude_input, exclude_output=exclude_output, document_output=document_output, include_signature=include_signature) # If this action returns a resource modify the return example to # appropriately reflect that. if resource_action_model.resource: if 'return' in section.available_sections: section.delete_section('return') resource_type = resource_action_model.resource.type new_return_section = section.add_new_section('return') return_resource_type = '%s.%s' % ( operation_model.service_model.service_name, resource_type) return_type = ':py:class:`%s`' % return_resource_type return_description = '%s resource' % (resource_type) if _method_returns_resource_list(resource_action_model.resource): return_type = 'list(%s)' % return_type return_description = 'A list of %s resources' % (resource_type) new_return_section.style.new_line() new_return_section.write(':rtype: %s' % return_type) new_return_section.style.new_line() new_return_section.write(':returns: %s' % return_description) new_return_section.style.new_line()
def document_load_reload_action( section, action_name, resource_name, event_emitter, load_model, service_model, include_signature=True, ): """Documents the resource load action :param section: The section to write to :param action_name: The name of the loading action should be load or reload :param resource_name: The name of the resource :param event_emitter: The event emitter to use to emit events :param load_model: The model of the load action :param service_model: The model of the service :param include_signature: Whether or not to include the signature. It is useful for generating docstrings. """ description = ( 'Calls :py:meth:`{}.Client.{}` to update the attributes of the ' '{} resource. Note that the load and reload methods are ' 'the same method and can be used interchangeably.'.format( get_service_module_name(service_model), xform_name(load_model.request.operation), resource_name, )) example_resource_name = xform_name(resource_name) if service_model.service_name == resource_name: example_resource_name = resource_name example_prefix = f'{example_resource_name}.{action_name}' document_model_driven_method( section=section, method_name=action_name, operation_model=OperationModel({}, service_model), event_emitter=event_emitter, method_description=description, example_prefix=example_prefix, include_signature=include_signature, )
def test_streaming_body_in_input(self): del self.json_model['operations']['SampleOperation']['output'] self.add_shape_to_params('Body', 'Blob') self.json_model['shapes']['Blob'] = {'type': 'blob'} self.json_model['shapes']['SampleOperationInputOutput']['payload'] = \ 'Body' document_model_driven_method( self.doc_structure, 'foo', self.operation_model, event_emitter=self.event_emitter, method_description='This describes the foo method.', example_prefix='response = client.foo' ) # The line in the example self.assert_contains_line('Body=b\'bytes\'|file') # The line in the parameter description self.assert_contains_line( ':type Body: bytes or seekable file-like object')
def test_no_input_output_shape(self): del self.json_model['operations']['SampleOperation']['input'] del self.json_model['operations']['SampleOperation']['output'] document_model_driven_method( self.doc_structure, 'foo', self.operation_model, event_emitter=self.event_emitter, method_description='This describes the foo method.', example_prefix='response = client.foo' ) self.assert_contains_lines_in_order([ '.. py:method:: foo()', ' This describes the foo method.', ' **Request Syntax**', ' ::', ' response = client.foo()', ' :returns: None', ])
def _add_model_driven_method(self, section, method_name): service_model = self._client.meta.service_model operation_name = self._client.meta.method_to_api_mapping[method_name] operation_model = service_model.operation_model(operation_name) example_prefix = 'response = client.%s' % method_name document_model_driven_method( section, method_name, operation_model, event_emitter=self._client.meta.events, method_description=operation_model.documentation, example_prefix=example_prefix, ) # Add the shared examples shared_examples = self._shared_examples.get(operation_name) if shared_examples: document_shared_examples( section, operation_model, example_prefix, shared_examples)
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)
def document_paginate_method(section, paginator_name, event_emitter, service_model, paginator_config, include_signature=True): """Documents the paginate method of a paginator :param section: The section to write to :param paginator_name: The name of the paginator. It is snake cased. :param event_emitter: The event emitter to use to emit events :param service_model: The service model :param paginator_config: The paginator config associated to a particular paginator. :param include_signature: Whether or not to include the signature. It is useful for generating docstrings. """ # Retrieve the operation model of the underlying operation. operation_model = service_model.operation_model(paginator_name) # Add representations of the request and response parameters # we want to include in the description of the paginate method. # These are parameters we expose via the ibm_botocore interface. pagination_config_members = OrderedDict() pagination_config_members['MaxItems'] = DocumentedShape( name='MaxItems', type_name='integer', documentation=('<p>The total number of items to return. If the total ' 'number of items available is more than the value ' 'specified in max-items then a <code>NextToken</code> ' 'will be provided in the output that you can use to ' 'resume pagination.</p>')) pagination_config_members['PageSize'] = DocumentedShape( name='PageSize', type_name='integer', documentation='<p>The size of each page.<p>') pagination_config_members['StartingToken'] = DocumentedShape( name='StartingToken', type_name='string', documentation=('<p>A token to specify where to start paginating. ' 'This is the <code>NextToken</code> from a previous ' 'response.</p>')) botocore_pagination_params = [ DocumentedShape( name='PaginationConfig', type_name='structure', documentation=( '<p>A dictionary that provides parameters to control ' 'pagination.</p>'), members=pagination_config_members) ] botocore_pagination_response_params = [ DocumentedShape(name='NextToken', type_name='string', documentation=('<p>A token to resume pagination.</p>')) ] service_pagination_params = [] # Add the normal input token of the method to a list # of input paramters that we wish to hide since we expose our own. if isinstance(paginator_config['input_token'], list): service_pagination_params += paginator_config['input_token'] else: service_pagination_params.append(paginator_config['input_token']) # Hide the limit key in the documentation. if paginator_config.get('limit_key', None): service_pagination_params.append(paginator_config['limit_key']) # Hide the output tokens in the documentation. service_pagination_response_params = [] if isinstance(paginator_config['output_token'], list): service_pagination_response_params += paginator_config['output_token'] else: service_pagination_response_params.append( paginator_config['output_token']) paginate_description = ( 'Creates an iterator that will paginate through responses ' 'from :py:meth:`{0}.Client.{1}`.'.format( get_service_module_name(service_model), xform_name(paginator_name))) document_model_driven_method( section, 'paginate', operation_model, event_emitter=event_emitter, method_description=paginate_description, example_prefix='response_iterator = paginator.paginate', include_input=botocore_pagination_params, include_output=botocore_pagination_response_params, exclude_input=service_pagination_params, exclude_output=service_pagination_response_params, include_signature=include_signature)
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) waiter_config_members = OrderedDict() waiter_config_members['Delay'] = DocumentedShape( name='Delay', type_name='integer', documentation=('<p>The amount of time in seconds to wait between ' 'attempts. Default: {0}</p>'.format( waiter_model.delay))) waiter_config_members['MaxAttempts'] = DocumentedShape( name='MaxAttempts', type_name='integer', documentation=('<p>The maximum number of attempts to be made. ' 'Default: {0}</p>'.format(waiter_model.max_attempts))) botocore_waiter_params = [ DocumentedShape( name='WaiterConfig', type_name='structure', documentation=( '<p>A dictionary that provides parameters to control ' 'waiting behavior.</p>'), members=waiter_config_members) ] 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', include_input=botocore_waiter_params, document_output=False, include_signature=include_signature)
def _write_docstring(self, *args, **kwargs): document_model_driven_method(*args, **kwargs)