Skip to content

Commit

Permalink
Add client exceptions to boto3 docs (#4343)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgromero authored Nov 20, 2024
1 parent 2b3edf9 commit 65db73f
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 0 deletions.
2 changes: 2 additions & 0 deletions boto3/docs/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def __init__(self, service_name, session, root_docs_path):
self.sections = [
'title',
'client',
'client-exceptions',
'paginators',
'waiters',
'resources',
Expand All @@ -65,6 +66,7 @@ def document_service(self):
self.title(doc_structure.get_section('title'))

self.client_api(doc_structure.get_section('client'))
self.client_exceptions(doc_structure.get_section('client-exceptions'))
self.paginator_api(doc_structure.get_section('paginators'))
self.waiter_api(doc_structure.get_section('waiters'))
if self._service_resource:
Expand Down
6 changes: 6 additions & 0 deletions tests/unit/docs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,12 @@ def add_shape_to_params(
required_list.append(param_name)
params_shape['required'] = required_list

def add_shape_to_errors(self, shape_name):
operation = self.json_model['operations']['SampleOperation']
errors = operation.get('errors', [])
errors.append({'shape': shape_name})
operation['errors'] = errors

def assert_contains_lines_in_order(self, lines, contents=None):
if contents is None:
contents = self.doc_structure.flush_structure().decode('utf-8')
Expand Down
86 changes: 86 additions & 0 deletions tests/unit/docs/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,25 @@
# 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.docs.client import ClientExceptionsDocumenter

from boto3.docs.client import Boto3ClientDocumenter
from tests.unit.docs import BaseDocsTest


class TestBoto3ClientDocumenter(BaseDocsTest):
def setUp(self):
super().setUp()
exception_shape = {
'SomeException': {
'exception': True,
'type': 'structure',
'members': {'Message': {'shape': 'String'}},
}
}
self.add_shape(exception_shape)
self.add_shape_to_errors('SomeException')
self.setup_client_and_resource()
self.client_documenter = Boto3ClientDocumenter(
self.client, self.root_services_path
)
Expand Down Expand Up @@ -96,8 +108,82 @@ def test_document_client(self):
' - *(dict) --*',
' - **Foo** *(string) --*',
' - **Bar** *(string) --*',
'**Exceptions**',
'* :py:class:`MyService.Client.exceptions.SomeException`',
],
self.get_nested_service_contents(
'myservice', 'client', 'sample_operation'
),
)


class TestClientExceptionsDocumenter(BaseDocsTest):
def setup_documenter(self):
self.setup_client_and_resource()
self.exceptions_documenter = ClientExceptionsDocumenter(
self.client, self.root_services_path
)

def test_no_modeled_exceptions(self):
self.setup_documenter()
self.exceptions_documenter.document_exceptions(self.doc_structure)
self.assert_contains_lines_in_order(
[
'=================',
'Client Exceptions',
'=================',
'Client exceptions are available',
'This client has no modeled exception classes.',
]
)

def test_modeled_exceptions(self):
exception_shape = {
'SomeException': {
'exception': True,
'type': 'structure',
'members': {'Message': {'shape': 'String'}},
}
}
self.add_shape(exception_shape)
self.setup_documenter()
self.exceptions_documenter.document_exceptions(self.doc_structure)
self.assert_contains_lines_in_order(
[
'=================',
'Client Exceptions',
'=================',
'Client exceptions are available',
'The available client exceptions are:',
'.. toctree::',
':maxdepth: 1',
':titlesonly:',
' myservice/client/exceptions/SomeException',
]
)
self.assert_contains_lines_in_order(
[
'.. py:class:: MyService.Client.exceptions.SomeException',
'**Example**',
'::',
'except client.exceptions.SomeException as e:',
'.. py:attribute:: response',
'**Syntax**',
'{',
"'Message': 'string',",
"'Error': {",
"'Code': 'string',",
"'Message': 'string'",
'}',
'}',
'**Structure**',
'- *(dict) --*',
'- **Message** *(string) --* ',
'- **Error** *(dict) --* ',
'- **Code** *(string) --* ',
'- **Message** *(string) --* ',
],
self.get_nested_service_contents(
'myservice', 'client/exceptions', 'SomeException'
),
)
8 changes: 8 additions & 0 deletions tests/unit/docs/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ def test_document_service(self):
'.. py:class:: MyService.Client',
'These are the available methods:',
' myservice/client/sample_operation',
'=================',
'Client Exceptions',
'=================',
'Client exceptions are available on a client instance ',
'via the ``exceptions`` property. For more detailed instructions ',
'and examples on the exact usage of client exceptions, see the ',
'error handling ',
'This client has no modeled exception classes.',
'==========',
'Paginators',
'==========',
Expand Down

0 comments on commit 65db73f

Please sign in to comment.