Repository: boto/botocore
Pull request #2554 (2021-11-02 08:32:05)

Hide generate_presigned_url for all clients but S3
The generate_presigned_url is generically added to all clients but not all
services properly support presigned URLs. This adds a filtering mechanism to
generating client documentation and filters out documenting the method for all
clients but S3. The method is still present on all clients but will not be
documented unless we have confirmation that the service supports it.


Patch:
diff --git a/botocore/docs/client.py b/botocore/docs/client.py
index b8c71daac..1ed8e76ce 100644
--- a/botocore/docs/client.py
+++ b/botocore/docs/client.py
@@ -21,7 +21,17 @@ from botocore.docs.utils import DocumentedShape
 from botocore.compat import OrderedDict
 
 
+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(object):
+    _CLIENT_METHODS_FILTERS = [
+        _allowlist_generate_presigned_url,
+    ]
+
     def __init__(self, client, shared_examples=None):
         self._client = client
         self._shared_examples = shared_examples
@@ -36,10 +46,36 @@ class ClientDocumenter(object):
         """
         self._add_title(section)
         self._add_class_signature(section)
-        client_methods = get_instance_public_methods(self._client)
+        client_methods = self._get_client_methods()
         self._add_client_intro(section, client_methods)
         self._add_client_methods(section, 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')
 


Test patch:
diff --git a/tests/functional/docs/test_s3.py b/tests/functional/docs/test_s3.py
index b285b5acd..9a9e39721 100644
--- a/tests/functional/docs/test_s3.py
+++ b/tests/functional/docs/test_s3.py
@@ -43,6 +43,10 @@ class TestS3Docs(BaseDocsFunctionalTest):
             self.assertNotIn('ContentMD5=\'string\'',
                              method_contents.decode('utf-8'))
 
+    def test_generate_presigned_url_documented(self):
+        content = self.get_docstring_for_method('s3', 'generate_presigned_url')
+        self.assert_contains_line('generate_presigned_url', content)
+
     def test_copy_source_documented_as_union_type(self):
         content = self.get_docstring_for_method('s3', 'copy_object')
         dict_form = (
diff --git a/tests/functional/docs/test_secretsmanager.py b/tests/functional/docs/test_secretsmanager.py
new file mode 100644
index 000000000..7c619fe60
--- /dev/null
+++ b/tests/functional/docs/test_secretsmanager.py
@@ -0,0 +1,21 @@
+# Copyright 2021 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.
+from botocore.docs.service import ServiceDocumenter
+from tests.functional.docs import BaseDocsFunctionalTest
+
+
+class TestSecretsManagerDocs(BaseDocsFunctionalTest):
+    def test_generate_presigned_url_is_not_documented(self):
+        documenter = ServiceDocumenter('secretsmanager', self._session)
+        docs = documenter.document_service()
+        self.assert_not_contains_line('generate_presigned_url', docs)