1# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"). You 4# may not use this file except in compliance with the License. A copy of 5# the License is located at 6# 7# http://aws.amazon.com/apache2.0/ 8# 9# or in the "license" file accompanying this file. This file is 10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11# ANY KIND, either express or implied. See the License for the specific 12# language governing permissions and limitations under the License. 13import inspect 14 15from botocore.docs.params import RequestParamsDocumenter 16from botocore.docs.params import ResponseParamsDocumenter 17from botocore.docs.example import ResponseExampleDocumenter 18from botocore.docs.example import RequestExampleDocumenter 19 20 21AWS_DOC_BASE = 'https://docs.aws.amazon.com/goto/WebAPI' 22 23 24def get_instance_public_methods(instance): 25 """Retrieves an objects public methods 26 27 :param instance: The instance of the class to inspect 28 :rtype: dict 29 :returns: A dictionary that represents an instance's methods where 30 the keys are the name of the methods and the 31 values are the handler to the method. 32 """ 33 instance_members = inspect.getmembers(instance) 34 instance_methods = {} 35 for name, member in instance_members: 36 if not name.startswith('_'): 37 if inspect.ismethod(member): 38 instance_methods[name] = member 39 return instance_methods 40 41 42def document_model_driven_signature(section, name, operation_model, 43 include=None, exclude=None): 44 """Documents the signature of a model-driven method 45 46 :param section: The section to write the documentation to. 47 48 :param name: The name of the method 49 50 :param operation_model: The operation model for the method 51 52 :type include: Dictionary where keys are parameter names and 53 values are the shapes of the parameter names. 54 :param include: The parameter shapes to include in the documentation. 55 56 :type exclude: List of the names of the parameters to exclude. 57 :param exclude: The names of the parameters to exclude from 58 documentation. 59 """ 60 params = {} 61 if operation_model.input_shape: 62 params = operation_model.input_shape.members 63 64 parameter_names = list(params.keys()) 65 66 if include is not None: 67 for member in include: 68 parameter_names.append(member.name) 69 70 if exclude is not None: 71 for member in exclude: 72 if member in parameter_names: 73 parameter_names.remove(member) 74 75 signature_params = '' 76 if parameter_names: 77 signature_params = '**kwargs' 78 section.style.start_sphinx_py_method(name, signature_params) 79 80 81def document_custom_signature(section, name, method, 82 include=None, exclude=None): 83 """Documents the signature of a custom method 84 85 :param section: The section to write the documentation to. 86 87 :param name: The name of the method 88 89 :param method: The handle to the method being documented 90 91 :type include: Dictionary where keys are parameter names and 92 values are the shapes of the parameter names. 93 :param include: The parameter shapes to include in the documentation. 94 95 :type exclude: List of the names of the parameters to exclude. 96 :param exclude: The names of the parameters to exclude from 97 documentation. 98 """ 99 args, varargs, keywords, defaults = inspect.getargspec(method) 100 args = args[1:] 101 signature_params = inspect.formatargspec( 102 args, varargs, keywords, defaults) 103 signature_params = signature_params.lstrip('(') 104 signature_params = signature_params.rstrip(')') 105 section.style.start_sphinx_py_method(name, signature_params) 106 107 108def document_custom_method(section, method_name, method): 109 """Documents a non-data driven method 110 111 :param section: The section to write the documentation to. 112 113 :param method_name: The name of the method 114 115 :param method: The handle to the method being documented 116 """ 117 document_custom_signature( 118 section, method_name, method) 119 method_intro_section = section.add_new_section('method-intro') 120 method_intro_section.writeln('') 121 doc_string = inspect.getdoc(method) 122 if doc_string is not None: 123 method_intro_section.style.write_py_doc_string(doc_string) 124 125 126def document_model_driven_method(section, method_name, operation_model, 127 event_emitter, method_description=None, 128 example_prefix=None, include_input=None, 129 include_output=None, exclude_input=None, 130 exclude_output=None, document_output=True, 131 include_signature=True): 132 """Documents an individual method 133 134 :param section: The section to write to 135 136 :param method_name: The name of the method 137 138 :param operation_model: The model of the operation 139 140 :param event_emitter: The event emitter to use to emit events 141 142 :param example_prefix: The prefix to use in the method example. 143 144 :type include_input: Dictionary where keys are parameter names and 145 values are the shapes of the parameter names. 146 :param include_input: The parameter shapes to include in the 147 input documentation. 148 149 :type include_output: Dictionary where keys are parameter names and 150 values are the shapes of the parameter names. 151 :param include_input: The parameter shapes to include in the 152 output documentation. 153 154 :type exclude_input: List of the names of the parameters to exclude. 155 :param exclude_input: The names of the parameters to exclude from 156 input documentation. 157 158 :type exclude_output: List of the names of the parameters to exclude. 159 :param exclude_input: The names of the parameters to exclude from 160 output documentation. 161 162 :param document_output: A boolean flag to indicate whether to 163 document the output. 164 165 :param include_signature: Whether or not to include the signature. 166 It is useful for generating docstrings. 167 """ 168 # Add the signature if specified. 169 if include_signature: 170 document_model_driven_signature( 171 section, method_name, operation_model, include=include_input, 172 exclude=exclude_input) 173 174 # Add the description for the method. 175 method_intro_section = section.add_new_section('method-intro') 176 method_intro_section.include_doc_string(method_description) 177 if operation_model.deprecated: 178 method_intro_section.style.start_danger() 179 method_intro_section.writeln( 180 'This operation is deprecated and may not function as ' 181 'expected. This operation should not be used going forward ' 182 'and is only kept for the purpose of backwards compatiblity.') 183 method_intro_section.style.end_danger() 184 service_uid = operation_model.service_model.metadata.get('uid') 185 if service_uid is not None: 186 method_intro_section.style.new_paragraph() 187 method_intro_section.write("See also: ") 188 link = '%s/%s/%s' % (AWS_DOC_BASE, service_uid, 189 operation_model.name) 190 method_intro_section.style.external_link(title="AWS API Documentation", 191 link=link) 192 method_intro_section.writeln('') 193 194 # Add the example section. 195 example_section = section.add_new_section('example') 196 example_section.style.new_paragraph() 197 example_section.style.bold('Request Syntax') 198 199 context = { 200 'special_shape_types': { 201 'streaming_input_shape': operation_model.get_streaming_input(), 202 'streaming_output_shape': operation_model.get_streaming_output(), 203 'eventstream_output_shape': operation_model.get_event_stream_output(), 204 }, 205 } 206 207 if operation_model.input_shape: 208 RequestExampleDocumenter( 209 service_name=operation_model.service_model.service_name, 210 operation_name=operation_model.name, 211 event_emitter=event_emitter, context=context).document_example( 212 example_section, operation_model.input_shape, 213 prefix=example_prefix, include=include_input, 214 exclude=exclude_input) 215 else: 216 example_section.style.new_paragraph() 217 example_section.style.start_codeblock() 218 example_section.write(example_prefix + '()') 219 220 # Add the request parameter documentation. 221 request_params_section = section.add_new_section('request-params') 222 if operation_model.input_shape: 223 RequestParamsDocumenter( 224 service_name=operation_model.service_model.service_name, 225 operation_name=operation_model.name, 226 event_emitter=event_emitter, context=context).document_params( 227 request_params_section, operation_model.input_shape, 228 include=include_input, exclude=exclude_input) 229 230 # Add the return value documentation 231 return_section = section.add_new_section('return') 232 return_section.style.new_line() 233 if operation_model.output_shape is not None and document_output: 234 return_section.write(':rtype: dict') 235 return_section.style.new_line() 236 return_section.write(':returns: ') 237 return_section.style.indent() 238 return_section.style.new_line() 239 240 # If the operation is an event stream, describe the tagged union 241 event_stream_output = operation_model.get_event_stream_output() 242 if event_stream_output: 243 event_section = return_section.add_new_section('event-stream') 244 event_section.style.new_paragraph() 245 event_section.write( 246 'The response of this operation contains an ' 247 ':class:`.EventStream` member. When iterated the ' 248 ':class:`.EventStream` will yield events based on the ' 249 'structure below, where only one of the top level keys ' 250 'will be present for any given event.' 251 ) 252 event_section.style.new_line() 253 254 # Add an example return value 255 return_example_section = return_section.add_new_section('example') 256 return_example_section.style.new_line() 257 return_example_section.style.bold('Response Syntax') 258 return_example_section.style.new_paragraph() 259 ResponseExampleDocumenter( 260 service_name=operation_model.service_model.service_name, 261 operation_name=operation_model.name, 262 event_emitter=event_emitter, 263 context=context).document_example( 264 return_example_section, operation_model.output_shape, 265 include=include_output, exclude=exclude_output) 266 267 # Add a description for the return value 268 return_description_section = return_section.add_new_section( 269 'description') 270 return_description_section.style.new_line() 271 return_description_section.style.bold('Response Structure') 272 return_description_section.style.new_paragraph() 273 ResponseParamsDocumenter( 274 service_name=operation_model.service_model.service_name, 275 operation_name=operation_model.name, 276 event_emitter=event_emitter, 277 context=context).document_params( 278 return_description_section, operation_model.output_shape, 279 include=include_output, exclude=exclude_output) 280 else: 281 return_section.write(':returns: None') 282