From 4a52a71956a8d46fcb7294ac71734504bb09bcc2 Mon Sep 17 00:00:00 2001 From: S. Solomon Darnell Date: Fri, 28 Mar 2025 21:52:21 -0500 Subject: two version of R2R are here --- .../site-packages/botocore/docs/client.py | 453 +++++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 .venv/lib/python3.12/site-packages/botocore/docs/client.py (limited to '.venv/lib/python3.12/site-packages/botocore/docs/client.py') diff --git a/.venv/lib/python3.12/site-packages/botocore/docs/client.py b/.venv/lib/python3.12/site-packages/botocore/docs/client.py new file mode 100644 index 00000000..41e37426 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/botocore/docs/client.py @@ -0,0 +1,453 @@ +# 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 +# +# http://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. +import os + +from botocore import xform_name +from botocore.compat import OrderedDict +from botocore.docs.bcdoc.restdoc import DocumentStructure +from botocore.docs.example import ResponseExampleDocumenter +from botocore.docs.method import ( + document_custom_method, + document_model_driven_method, + get_instance_public_methods, +) +from botocore.docs.params import ResponseParamsDocumenter +from botocore.docs.sharedexample import document_shared_examples +from botocore.docs.utils import DocumentedShape, get_official_service_name + + +def _allowlist_generate_presigned_url(method_name, service_name, **kwargs): + if method_name != 'generate_presigned_url': + return None + return service_name in ['s3'] + + +class ClientDocumenter: + _CLIENT_METHODS_FILTERS = [ + _allowlist_generate_presigned_url, + ] + + def __init__(self, client, root_docs_path, shared_examples=None): + self._client = client + self._client_class_name = self._client.__class__.__name__ + self._root_docs_path = root_docs_path + self._shared_examples = shared_examples + if self._shared_examples is None: + self._shared_examples = {} + self._service_name = self._client.meta.service_model.service_name + + def document_client(self, section): + """Documents a client and its methods + + :param section: The section to write to. + """ + self._add_title(section) + self._add_class_signature(section) + client_methods = self._get_client_methods() + self._add_client_intro(section, client_methods) + self._add_client_methods(client_methods) + + def _get_client_methods(self): + client_methods = get_instance_public_methods(self._client) + return self._filter_client_methods(client_methods) + + def _filter_client_methods(self, client_methods): + filtered_methods = {} + for method_name, method in client_methods.items(): + include = self._filter_client_method( + method=method, + method_name=method_name, + service_name=self._service_name, + ) + if include: + filtered_methods[method_name] = method + return filtered_methods + + def _filter_client_method(self, **kwargs): + # Apply each filter to the method + for filter in self._CLIENT_METHODS_FILTERS: + filter_include = filter(**kwargs) + # Use the first non-None value returned by any of the filters + if filter_include is not None: + return filter_include + # Otherwise default to including it + return True + + def _add_title(self, section): + section.style.h2('Client') + + def _add_client_intro(self, section, client_methods): + section = section.add_new_section('intro') + # Write out the top level description for the client. + official_service_name = get_official_service_name( + self._client.meta.service_model + ) + section.write( + f"A low-level client representing {official_service_name}" + ) + section.style.new_line() + section.include_doc_string( + self._client.meta.service_model.documentation + ) + + # Write out the client example instantiation. + self._add_client_creation_example(section) + + # List out all of the possible client methods. + section.style.dedent() + section.style.new_paragraph() + section.writeln('These are the available methods:') + section.style.toctree() + for method_name in sorted(client_methods): + section.style.tocitem(f'{self._service_name}/client/{method_name}') + + def _add_class_signature(self, section): + section.style.start_sphinx_py_class( + class_name=f'{self._client_class_name}.Client' + ) + + def _add_client_creation_example(self, section): + section.style.start_codeblock() + section.style.new_line() + section.write( + f'client = session.create_client(\'{self._service_name}\')' + ) + section.style.end_codeblock() + + def _add_client_methods(self, client_methods): + for method_name in sorted(client_methods): + # Create a new DocumentStructure for each client method and add contents. + method_doc_structure = DocumentStructure( + method_name, target='html' + ) + self._add_client_method( + method_doc_structure, method_name, client_methods[method_name] + ) + # Write client methods in individual/nested files. + # Path: /reference/services//client/.rst + client_dir_path = os.path.join( + self._root_docs_path, self._service_name, 'client' + ) + method_doc_structure.write_to_file(client_dir_path, method_name) + + def _add_client_method(self, section, method_name, method): + breadcrumb_section = section.add_new_section('breadcrumb') + breadcrumb_section.style.ref( + self._client_class_name, f'../../{self._service_name}' + ) + breadcrumb_section.write(f' / Client / {method_name}') + section.add_title_section(method_name) + method_section = section.add_new_section( + method_name, + context={'qualifier': f'{self._client_class_name}.Client.'}, + ) + if self._is_custom_method(method_name): + self._add_custom_method( + method_section, + method_name, + method, + ) + else: + self._add_model_driven_method(method_section, method_name) + + def _is_custom_method(self, method_name): + return method_name not in self._client.meta.method_to_api_mapping + + def _add_custom_method(self, section, method_name, method): + document_custom_method(section, method_name, method) + + def _add_method_exceptions_list(self, section, operation_model): + error_section = section.add_new_section('exceptions') + error_section.style.new_line() + error_section.style.bold('Exceptions') + error_section.style.new_line() + for error in operation_model.error_shapes: + class_name = ( + f'{self._client_class_name}.Client.exceptions.{error.name}' + ) + error_section.style.li(f':py:class:`{class_name}`') + + def _add_model_driven_method(self, section, method_name): + service_model = self._client.meta.service_model + operation_name = self._client.meta.method_to_api_mapping[method_name] + operation_model = service_model.operation_model(operation_name) + + example_prefix = f'response = client.{method_name}' + full_method_name = ( + f"{section.context.get('qualifier', '')}{method_name}" + ) + document_model_driven_method( + section, + full_method_name, + operation_model, + event_emitter=self._client.meta.events, + method_description=operation_model.documentation, + example_prefix=example_prefix, + ) + + # Add any modeled exceptions + if operation_model.error_shapes: + self._add_method_exceptions_list(section, operation_model) + + # Add the shared examples + shared_examples = self._shared_examples.get(operation_name) + if shared_examples: + document_shared_examples( + section, operation_model, example_prefix, shared_examples + ) + + +class ClientExceptionsDocumenter: + _USER_GUIDE_LINK = ( + 'https://boto3.amazonaws.com/' + 'v1/documentation/api/latest/guide/error-handling.html' + ) + _GENERIC_ERROR_SHAPE = DocumentedShape( + name='Error', + type_name='structure', + documentation=('Normalized access to common exception attributes.'), + members=OrderedDict( + [ + ( + 'Code', + DocumentedShape( + name='Code', + type_name='string', + documentation=( + 'An identifier specifying the exception type.' + ), + ), + ), + ( + 'Message', + DocumentedShape( + name='Message', + type_name='string', + documentation=( + 'A descriptive message explaining why the exception ' + 'occured.' + ), + ), + ), + ] + ), + ) + + def __init__(self, client, root_docs_path): + self._client = client + self._client_class_name = self._client.__class__.__name__ + self._service_name = self._client.meta.service_model.service_name + self._root_docs_path = root_docs_path + + def document_exceptions(self, section): + self._add_title(section) + self._add_overview(section) + self._add_exceptions_list(section) + self._add_exception_classes() + + def _add_title(self, section): + section.style.h2('Client Exceptions') + + def _add_overview(self, section): + section.style.new_line() + section.write( + '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 ' + ) + section.style.external_link( + title='user guide', + link=self._USER_GUIDE_LINK, + ) + section.write('.') + section.style.new_line() + + def _exception_class_name(self, shape): + return f'{self._client_class_name}.Client.exceptions.{shape.name}' + + def _add_exceptions_list(self, section): + error_shapes = self._client.meta.service_model.error_shapes + if not error_shapes: + section.style.new_line() + section.write('This client has no modeled exception classes.') + section.style.new_line() + return + section.style.new_line() + section.writeln('The available client exceptions are:') + section.style.toctree() + for shape in error_shapes: + section.style.tocitem( + f'{self._service_name}/client/exceptions/{shape.name}' + ) + + def _add_exception_classes(self): + for shape in self._client.meta.service_model.error_shapes: + # Create a new DocumentStructure for each exception method and add contents. + exception_doc_structure = DocumentStructure( + shape.name, target='html' + ) + self._add_exception_class(exception_doc_structure, shape) + # Write exceptions in individual/nested files. + # Path: /reference/services//client/exceptions/.rst + exception_dir_path = os.path.join( + self._root_docs_path, + self._service_name, + 'client', + 'exceptions', + ) + exception_doc_structure.write_to_file( + exception_dir_path, shape.name + ) + + def _add_exception_class(self, section, shape): + breadcrumb_section = section.add_new_section('breadcrumb') + breadcrumb_section.style.ref( + self._client_class_name, f'../../../{self._service_name}' + ) + breadcrumb_section.write(f' / Client / exceptions / {shape.name}') + section.add_title_section(shape.name) + class_section = section.add_new_section(shape.name) + class_name = self._exception_class_name(shape) + class_section.style.start_sphinx_py_class(class_name=class_name) + self._add_top_level_documentation(class_section, shape) + self._add_exception_catch_example(class_section, shape) + self._add_response_attr(class_section, shape) + class_section.style.end_sphinx_py_class() + + def _add_top_level_documentation(self, section, shape): + if shape.documentation: + section.style.new_line() + section.include_doc_string(shape.documentation) + section.style.new_line() + + def _add_exception_catch_example(self, section, shape): + section.style.new_line() + section.style.bold('Example') + section.style.new_paragraph() + section.style.start_codeblock() + section.write('try:') + section.style.indent() + section.style.new_line() + section.write('...') + section.style.dedent() + section.style.new_line() + section.write(f'except client.exceptions.{shape.name} as e:') + section.style.indent() + section.style.new_line() + section.write('print(e.response)') + section.style.dedent() + section.style.end_codeblock() + + def _add_response_attr(self, section, shape): + response_section = section.add_new_section('response') + response_section.style.start_sphinx_py_attr('response') + self._add_response_attr_description(response_section) + self._add_response_example(response_section, shape) + self._add_response_params(response_section, shape) + response_section.style.end_sphinx_py_attr() + + def _add_response_attr_description(self, section): + section.style.new_line() + section.include_doc_string( + 'The parsed error response. All exceptions have a top level ' + '``Error`` key that provides normalized access to common ' + 'exception atrributes. All other keys are specific to this ' + 'service or exception class.' + ) + section.style.new_line() + + def _add_response_example(self, section, shape): + example_section = section.add_new_section('syntax') + example_section.style.new_line() + example_section.style.bold('Syntax') + example_section.style.new_paragraph() + documenter = ResponseExampleDocumenter( + service_name=self._service_name, + operation_name=None, + event_emitter=self._client.meta.events, + ) + documenter.document_example( + example_section, + shape, + include=[self._GENERIC_ERROR_SHAPE], + ) + + def _add_response_params(self, section, shape): + params_section = section.add_new_section('Structure') + params_section.style.new_line() + params_section.style.bold('Structure') + params_section.style.new_paragraph() + documenter = ResponseParamsDocumenter( + service_name=self._service_name, + operation_name=None, + event_emitter=self._client.meta.events, + ) + documenter.document_params( + params_section, + shape, + include=[self._GENERIC_ERROR_SHAPE], + ) + + +class ClientContextParamsDocumenter: + _CONFIG_GUIDE_LINK = ( + 'https://boto3.amazonaws.com/' + 'v1/documentation/api/latest/guide/configuration.html' + ) + + OMITTED_CONTEXT_PARAMS = { + 's3': ( + 'Accelerate', + 'DisableMultiRegionAccessPoints', + 'ForcePathStyle', + 'UseArnRegion', + ), + 's3control': ('UseArnRegion',), + } + + def __init__(self, service_name, context_params): + self._service_name = service_name + self._context_params = context_params + + def document_context_params(self, section): + self._add_title(section) + self._add_overview(section) + self._add_context_params_list(section) + + def _add_title(self, section): + section.style.h2('Client Context Parameters') + + def _add_overview(self, section): + section.style.new_line() + section.write( + 'Client context parameters are configurable on a client ' + 'instance via the ``client_context_params`` parameter in the ' + '``Config`` object. For more detailed instructions and examples ' + 'on the exact usage of context params see the ' + ) + section.style.external_link( + title='configuration guide', + link=self._CONFIG_GUIDE_LINK, + ) + section.write('.') + section.style.new_line() + + def _add_context_params_list(self, section): + section.style.new_line() + sn = f'``{self._service_name}``' + section.writeln(f'The available {sn} client context params are:') + for param in self._context_params: + section.style.new_line() + name = f'``{xform_name(param.name)}``' + section.write(f'* {name} ({param.type}) - {param.documentation}') -- cgit v1.2.3