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# https://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 os
14
15from botocore import xform_name
16from botocore.docs.bcdoc.restdoc import DocumentStructure
17from botocore.docs.method import get_instance_public_methods
18from botocore.docs.utils import DocumentedShape
19
20from boto3.docs.base import NestedDocumenter
21from boto3.docs.method import document_model_driven_resource_method
22from boto3.docs.utils import (
23 add_resource_type_overview,
24 get_resource_ignore_params,
25)
26
27
28class CollectionDocumenter(NestedDocumenter):
29 def document_collections(self, section):
30 collections = self._resource.meta.resource_model.collections
31 collections_list = []
32 add_resource_type_overview(
33 section=section,
34 resource_type='Collections',
35 description=(
36 'Collections provide an interface to iterate over and '
37 'manipulate groups of resources. '
38 ),
39 intro_link='guide_collections',
40 )
41 self.member_map['collections'] = collections_list
42 for collection in collections:
43 collections_list.append(collection.name)
44 # Create a new DocumentStructure for each collection and add contents.
45 collection_doc = DocumentStructure(collection.name, target='html')
46 breadcrumb_section = collection_doc.add_new_section('breadcrumb')
47 breadcrumb_section.style.ref(self._resource_class_name, 'index')
48 breadcrumb_section.write(f' / Collection / {collection.name}')
49 collection_doc.add_title_section(collection.name)
50 collection_section = collection_doc.add_new_section(
51 collection.name,
52 context={'qualifier': f'{self.class_name}.'},
53 )
54 self._document_collection(collection_section, collection)
55
56 # Write collections in individual/nested files.
57 # Path: <root>/reference/services/<service>/<resource_name>/<collection_name>.rst
58 collections_dir_path = os.path.join(
59 self._root_docs_path,
60 f'{self._service_name}',
61 f'{self._resource_sub_path}',
62 )
63 collection_doc.write_to_file(collections_dir_path, collection.name)
64
65 def _document_collection(self, section, collection):
66 methods = get_instance_public_methods(
67 getattr(self._resource, collection.name)
68 )
69 document_collection_object(section, collection)
70 batch_actions = {}
71 for batch_action in collection.batch_actions:
72 batch_actions[batch_action.name] = batch_action
73
74 for method in sorted(methods):
75 method_section = section.add_new_section(method)
76 if method in batch_actions:
77 document_batch_action(
78 section=method_section,
79 resource_name=self._resource_name,
80 event_emitter=self._resource.meta.client.meta.events,
81 batch_action_model=batch_actions[method],
82 collection_model=collection,
83 service_model=self._resource.meta.client.meta.service_model,
84 )
85 else:
86 document_collection_method(
87 section=method_section,
88 resource_name=self._resource_name,
89 action_name=method,
90 event_emitter=self._resource.meta.client.meta.events,
91 collection_model=collection,
92 service_model=self._resource.meta.client.meta.service_model,
93 )
94
95
96def document_collection_object(
97 section,
98 collection_model,
99 include_signature=True,
100):
101 """Documents a collection resource object
102
103 :param section: The section to write to
104
105 :param collection_model: The model of the collection
106
107 :param include_signature: Whether or not to include the signature.
108 It is useful for generating docstrings.
109 """
110 if include_signature:
111 full_collection_name = (
112 f"{section.context.get('qualifier', '')}{collection_model.name}"
113 )
114 section.style.start_sphinx_py_attr(full_collection_name)
115 section.include_doc_string(
116 f'A collection of {collection_model.resource.type} resources.'
117 )
118 section.include_doc_string(
119 f'A {collection_model.resource.type} Collection will include all '
120 f'resources by default, and extreme caution should be taken when '
121 f'performing actions on all resources.'
122 )
123
124
125def document_batch_action(
126 section,
127 resource_name,
128 event_emitter,
129 batch_action_model,
130 service_model,
131 collection_model,
132 include_signature=True,
133):
134 """Documents a collection's batch action
135
136 :param section: The section to write to
137
138 :param resource_name: The name of the resource
139
140 :param action_name: The name of collection action. Currently only
141 can be all, filter, limit, or page_size
142
143 :param event_emitter: The event emitter to use to emit events
144
145 :param batch_action_model: The model of the batch action
146
147 :param collection_model: The model of the collection
148
149 :param service_model: The model of the service
150
151 :param include_signature: Whether or not to include the signature.
152 It is useful for generating docstrings.
153 """
154 operation_model = service_model.operation_model(
155 batch_action_model.request.operation
156 )
157 ignore_params = get_resource_ignore_params(
158 batch_action_model.request.params
159 )
160
161 example_return_value = 'response'
162 if batch_action_model.resource:
163 example_return_value = xform_name(batch_action_model.resource.type)
164
165 example_resource_name = xform_name(resource_name)
166 if service_model.service_name == resource_name:
167 example_resource_name = resource_name
168 example_prefix = f'{example_return_value} = {example_resource_name}.{collection_model.name}.{batch_action_model.name}'
169 document_model_driven_resource_method(
170 section=section,
171 method_name=batch_action_model.name,
172 operation_model=operation_model,
173 event_emitter=event_emitter,
174 method_description=operation_model.documentation,
175 example_prefix=example_prefix,
176 exclude_input=ignore_params,
177 resource_action_model=batch_action_model,
178 include_signature=include_signature,
179 )
180
181
182def document_collection_method(
183 section,
184 resource_name,
185 action_name,
186 event_emitter,
187 collection_model,
188 service_model,
189 include_signature=True,
190):
191 """Documents a collection method
192
193 :param section: The section to write to
194
195 :param resource_name: The name of the resource
196
197 :param action_name: The name of collection action. Currently only
198 can be all, filter, limit, or page_size
199
200 :param event_emitter: The event emitter to use to emit events
201
202 :param collection_model: The model of the collection
203
204 :param service_model: The model of the service
205
206 :param include_signature: Whether or not to include the signature.
207 It is useful for generating docstrings.
208 """
209 operation_model = service_model.operation_model(
210 collection_model.request.operation
211 )
212
213 underlying_operation_members = []
214 if operation_model.input_shape:
215 underlying_operation_members = operation_model.input_shape.members
216
217 example_resource_name = xform_name(resource_name)
218 if service_model.service_name == resource_name:
219 example_resource_name = resource_name
220
221 custom_action_info_dict = {
222 'all': {
223 'method_description': (
224 f'Creates an iterable of all {collection_model.resource.type} '
225 f'resources in the collection.'
226 ),
227 'example_prefix': f'{xform_name(collection_model.resource.type)}_iterator = {example_resource_name}.{collection_model.name}.all',
228 'exclude_input': underlying_operation_members,
229 },
230 'filter': {
231 'method_description': (
232 f'Creates an iterable of all {collection_model.resource.type} '
233 f'resources in the collection filtered by kwargs passed to '
234 f'method. A {collection_model.resource.type} collection will '
235 f'include all resources by default if no filters are provided, '
236 f'and extreme caution should be taken when performing actions '
237 f'on all resources.'
238 ),
239 'example_prefix': f'{xform_name(collection_model.resource.type)}_iterator = {example_resource_name}.{collection_model.name}.filter',
240 'exclude_input': get_resource_ignore_params(
241 collection_model.request.params
242 ),
243 },
244 'limit': {
245 'method_description': (
246 f'Creates an iterable up to a specified amount of '
247 f'{collection_model.resource.type} resources in the collection.'
248 ),
249 'example_prefix': f'{xform_name(collection_model.resource.type)}_iterator = {example_resource_name}.{collection_model.name}.limit',
250 'include_input': [
251 DocumentedShape(
252 name='count',
253 type_name='integer',
254 documentation=(
255 'The limit to the number of resources '
256 'in the iterable.'
257 ),
258 )
259 ],
260 'exclude_input': underlying_operation_members,
261 },
262 'page_size': {
263 'method_description': (
264 f'Creates an iterable of all {collection_model.resource.type} '
265 f'resources in the collection, but limits the number of '
266 f'items returned by each service call by the specified amount.'
267 ),
268 'example_prefix': f'{xform_name(collection_model.resource.type)}_iterator = {example_resource_name}.{collection_model.name}.page_size',
269 'include_input': [
270 DocumentedShape(
271 name='count',
272 type_name='integer',
273 documentation=(
274 'The number of items returned by each ' 'service call'
275 ),
276 )
277 ],
278 'exclude_input': underlying_operation_members,
279 },
280 }
281 if action_name in custom_action_info_dict:
282 action_info = custom_action_info_dict[action_name]
283 document_model_driven_resource_method(
284 section=section,
285 method_name=action_name,
286 operation_model=operation_model,
287 event_emitter=event_emitter,
288 resource_action_model=collection_model,
289 include_signature=include_signature,
290 **action_info,
291 )