# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You # may not use this file except in compliance with the License. A copy of # the License is located at # # https://aws.amazon.com/apache2.0/ # # or in the "license" file accompanying this file. This file is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. from botocore import xform_name from botocore.docs.utils import get_official_service_name from boto3.docs.action import ActionDocumenter from boto3.docs.attr import ( document_attribute, document_identifier, document_reference, ) from boto3.docs.base import BaseDocumenter from boto3.docs.collection import CollectionDocumenter from boto3.docs.subresource import SubResourceDocumenter from boto3.docs.utils import ( add_resource_type_overview, get_identifier_args_for_signature, get_identifier_description, get_identifier_values_for_example, ) from boto3.docs.waiter import WaiterResourceDocumenter class ResourceDocumenter(BaseDocumenter): def __init__(self, resource, botocore_session): super().__init__(resource) self._botocore_session = botocore_session def document_resource(self, section): self._add_title(section) self._add_intro(section) overview_section = section.add_new_section('member-overview') self._add_identifiers(section) self._add_attributes(section) self._add_references(section) self._add_actions(section) self._add_sub_resources(section) self._add_collections(section) self._add_waiters(section) self._add_overview_of_members(overview_section) def _add_title(self, section): section.style.h2(self._resource_name) def _add_intro(self, section): identifier_names = [] if self._resource_model.identifiers: for identifier in self._resource_model.identifiers: identifier_names.append(identifier.name) # Write out the class signature. class_args = get_identifier_args_for_signature(identifier_names) section.style.start_sphinx_py_class( class_name=f'{self.class_name}({class_args})' ) # Add as short description about the resource description_section = section.add_new_section('description') self._add_description(description_section) # Add an example of how to instantiate the resource example_section = section.add_new_section('example') self._add_example(example_section, identifier_names) # Add the description for the parameters to instantiate the # resource. param_section = section.add_new_section('params') self._add_params_description(param_section, identifier_names) def _add_description(self, section): official_service_name = get_official_service_name(self._service_model) section.write( 'A resource representing an {} {}'.format( official_service_name, self._resource_name ) ) def _add_example(self, section, identifier_names): section.style.start_codeblock() section.style.new_line() section.write('import boto3') section.style.new_line() section.style.new_line() section.write( '{} = boto3.resource(\'{}\')'.format( self._service_name, self._service_name ) ) section.style.new_line() example_values = get_identifier_values_for_example(identifier_names) section.write( '{} = {}.{}({})'.format( xform_name(self._resource_name), self._service_name, self._resource_name, example_values, ) ) section.style.end_codeblock() def _add_params_description(self, section, identifier_names): for identifier_name in identifier_names: description = get_identifier_description( self._resource_name, identifier_name ) section.write(f':type {identifier_name}: string') section.style.new_line() section.write(f':param {identifier_name}: {description}') section.style.new_line() def _add_overview_of_members(self, section): for resource_member_type in self.member_map: section.style.new_line() section.write( f'These are the resource\'s available {resource_member_type}:' ) section.style.new_line() for member in self.member_map[resource_member_type]: if resource_member_type in ( 'attributes', 'collections', 'identifiers', 'references', ): section.style.li(f':py:attr:`{member}`') else: section.style.li(f':py:meth:`{member}()`') def _add_identifiers(self, section): identifiers = self._resource.meta.resource_model.identifiers section = section.add_new_section('identifiers') member_list = [] if identifiers: self.member_map['identifiers'] = member_list add_resource_type_overview( section=section, resource_type='Identifiers', description=( 'Identifiers are properties of a resource that are ' 'set upon instantiation of the resource.' ), intro_link='identifiers_attributes_intro', ) for identifier in identifiers: identifier_section = section.add_new_section(identifier.name) member_list.append(identifier.name) document_identifier( section=identifier_section, resource_name=self._resource_name, identifier_model=identifier, ) def _add_attributes(self, section): service_model = self._resource.meta.client.meta.service_model attributes = {} if self._resource.meta.resource_model.shape: shape = service_model.shape_for( self._resource.meta.resource_model.shape ) attributes = self._resource.meta.resource_model.get_attributes( shape ) section = section.add_new_section('attributes') attribute_list = [] if attributes: add_resource_type_overview( section=section, resource_type='Attributes', description=( 'Attributes provide access' ' to the properties of a resource. Attributes are lazy-' 'loaded the first time one is accessed via the' ' :py:meth:`load` method.' ), intro_link='identifiers_attributes_intro', ) self.member_map['attributes'] = attribute_list for attr_name in sorted(attributes): _, attr_shape = attributes[attr_name] attribute_section = section.add_new_section(attr_name) attribute_list.append(attr_name) document_attribute( section=attribute_section, service_name=self._service_name, resource_name=self._resource_name, attr_name=attr_name, event_emitter=self._resource.meta.client.meta.events, attr_model=attr_shape, ) def _add_references(self, section): section = section.add_new_section('references') references = self._resource.meta.resource_model.references reference_list = [] if references: add_resource_type_overview( section=section, resource_type='References', description=( 'References are related resource instances that have ' 'a belongs-to relationship.' ), intro_link='references_intro', ) self.member_map['references'] = reference_list for reference in references: reference_section = section.add_new_section(reference.name) reference_list.append(reference.name) document_reference( section=reference_section, reference_model=reference ) def _add_actions(self, section): section = section.add_new_section('actions') actions = self._resource.meta.resource_model.actions if actions: documenter = ActionDocumenter(self._resource) documenter.member_map = self.member_map documenter.document_actions(section) def _add_sub_resources(self, section): section = section.add_new_section('sub-resources') sub_resources = self._resource.meta.resource_model.subresources if sub_resources: documenter = SubResourceDocumenter(self._resource) documenter.member_map = self.member_map documenter.document_sub_resources(section) def _add_collections(self, section): section = section.add_new_section('collections') collections = self._resource.meta.resource_model.collections if collections: documenter = CollectionDocumenter(self._resource) documenter.member_map = self.member_map documenter.document_collections(section) def _add_waiters(self, section): section = section.add_new_section('waiters') waiters = self._resource.meta.resource_model.waiters if waiters: service_waiter_model = self._botocore_session.get_waiter_model( self._service_name ) documenter = WaiterResourceDocumenter( self._resource, service_waiter_model ) documenter.member_map = self.member_map documenter.document_resource_waiters(section) class ServiceResourceDocumenter(ResourceDocumenter): @property def class_name(self): return f'{self._service_docs_name}.ServiceResource' def _add_title(self, section): section.style.h2('Service Resource') def _add_description(self, section): official_service_name = get_official_service_name(self._service_model) section.write(f'A resource representing {official_service_name}') def _add_example(self, section, identifier_names): section.style.start_codeblock() section.style.new_line() section.write('import boto3') section.style.new_line() section.style.new_line() section.write( f'{self._service_name} = boto3.resource(\'{self._service_name}\')' ) section.style.end_codeblock()