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 os
14
15from botocore import xform_name
16from botocore.compat import OrderedDict
17from botocore.docs.bcdoc.restdoc import DocumentStructure
18from botocore.docs.method import document_model_driven_method
19from botocore.docs.utils import DocumentedShape
20from botocore.utils import get_service_module_name
21
22
23class WaiterDocumenter:
24 def __init__(self, client, service_waiter_model, root_docs_path):
25 self._client = client
26 self._client_class_name = self._client.__class__.__name__
27 self._service_name = self._client.meta.service_model.service_name
28 self._service_waiter_model = service_waiter_model
29 self._root_docs_path = root_docs_path
30 self._USER_GUIDE_LINK = (
31 'https://boto3.amazonaws.com/'
32 'v1/documentation/api/latest/guide/clients.html#waiters'
33 )
34
35 def document_waiters(self, section):
36 """Documents the various waiters for a service.
37
38 :param section: The section to write to.
39 """
40 section.style.h2('Waiters')
41 self._add_overview(section)
42 section.style.new_line()
43 section.writeln('The available waiters are:')
44 section.style.toctree()
45 for waiter_name in self._service_waiter_model.waiter_names:
46 section.style.tocitem(f'{self._service_name}/waiter/{waiter_name}')
47 # Create a new DocumentStructure for each waiter and add contents.
48 waiter_doc_structure = DocumentStructure(
49 waiter_name, target='html'
50 )
51 self._add_single_waiter(waiter_doc_structure, waiter_name)
52 # Write waiters in individual/nested files.
53 # Path: <root>/reference/services/<service>/waiter/<waiter_name>.rst
54 waiter_dir_path = os.path.join(
55 self._root_docs_path, self._service_name, 'waiter'
56 )
57 waiter_doc_structure.write_to_file(waiter_dir_path, waiter_name)
58
59 def _add_single_waiter(self, section, waiter_name):
60 breadcrumb_section = section.add_new_section('breadcrumb')
61 breadcrumb_section.style.ref(
62 self._client_class_name, f'../../{self._service_name}'
63 )
64 breadcrumb_section.write(f' / Waiter / {waiter_name}')
65 section.add_title_section(waiter_name)
66 waiter_section = section.add_new_section(waiter_name)
67 waiter_section.style.start_sphinx_py_class(
68 class_name=f"{self._client_class_name}.Waiter.{waiter_name}"
69 )
70
71 # Add example on how to instantiate waiter.
72 waiter_section.style.start_codeblock()
73 waiter_section.style.new_line()
74 waiter_section.write(
75 f'waiter = client.get_waiter(\'{xform_name(waiter_name)}\')'
76 )
77 waiter_section.style.end_codeblock()
78
79 # Add information on the wait() method
80 waiter_section.style.new_line()
81 document_wait_method(
82 section=waiter_section,
83 waiter_name=waiter_name,
84 event_emitter=self._client.meta.events,
85 service_model=self._client.meta.service_model,
86 service_waiter_model=self._service_waiter_model,
87 )
88
89 def _add_overview(self, section):
90 section.style.new_line()
91 section.write(
92 'Waiters are available on a client instance '
93 'via the ``get_waiter`` method. For more detailed instructions '
94 'and examples on the usage or waiters, see the '
95 'waiters '
96 )
97 section.style.external_link(
98 title='user guide',
99 link=self._USER_GUIDE_LINK,
100 )
101 section.write('.')
102 section.style.new_line()
103
104
105def document_wait_method(
106 section,
107 waiter_name,
108 event_emitter,
109 service_model,
110 service_waiter_model,
111 include_signature=True,
112):
113 """Documents a the wait method of a waiter
114
115 :param section: The section to write to
116
117 :param waiter_name: The name of the waiter
118
119 :param event_emitter: The event emitter to use to emit events
120
121 :param service_model: The service model
122
123 :param service_waiter_model: The waiter model associated to the service
124
125 :param include_signature: Whether or not to include the signature.
126 It is useful for generating docstrings.
127 """
128 waiter_model = service_waiter_model.get_waiter(waiter_name)
129 operation_model = service_model.operation_model(waiter_model.operation)
130
131 waiter_config_members = OrderedDict()
132
133 waiter_config_members['Delay'] = DocumentedShape(
134 name='Delay',
135 type_name='integer',
136 documentation=(
137 '<p>The amount of time in seconds to wait between '
138 f'attempts. Default: {waiter_model.delay}</p>'
139 ),
140 )
141
142 waiter_config_members['MaxAttempts'] = DocumentedShape(
143 name='MaxAttempts',
144 type_name='integer',
145 documentation=(
146 '<p>The maximum number of attempts to be made. '
147 f'Default: {waiter_model.max_attempts}</p>'
148 ),
149 )
150
151 botocore_waiter_params = [
152 DocumentedShape(
153 name='WaiterConfig',
154 type_name='structure',
155 documentation=(
156 '<p>A dictionary that provides parameters to control '
157 'waiting behavior.</p>'
158 ),
159 members=waiter_config_members,
160 )
161 ]
162
163 wait_description = (
164 f'Polls :py:meth:`{get_service_module_name(service_model)}.Client.'
165 f'{xform_name(waiter_model.operation)}` every {waiter_model.delay} '
166 'seconds until a successful state is reached. An error is '
167 f'raised after {waiter_model.max_attempts} failed checks.'
168 )
169
170 document_model_driven_method(
171 section,
172 'wait',
173 operation_model,
174 event_emitter=event_emitter,
175 method_description=wait_description,
176 example_prefix='waiter.wait',
177 include_input=botocore_waiter_params,
178 document_output=False,
179 include_signature=include_signature,
180 )