Skip to content

Commit

Permalink
add client_context_params to docs
Browse files Browse the repository at this point in the history
  • Loading branch information
davidlm committed Oct 4, 2023
1 parent a6b149f commit 65ad078
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 2 deletions.
57 changes: 57 additions & 0 deletions botocore/docs/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# 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
Expand Down Expand Up @@ -399,3 +400,59 @@ def _add_response_params(self, section, shape):
shape,
include=[self._GENERIC_ERROR_SHAPE],
)


class ClientContextParamsDocumenter:
_CONFIG_GUIDE_LINK = (
'https://boto3.amazonaws.com/'
'v1/documentation/api/latest/guide/configuration.html'
)
# These context params provide overlapping functionality to settings in
# the ``s3`` config. While they will still be supported, they are
# undocumented to prevent customers from implementing conflicting behavior
# in the SDK.
_OMITTED_S3_PARAMS = ['Accelerate', 'ForcePathStyle']

def __init__(self, context_params, service_name):
if service_name == 's3':
context_params = [
param
for param in context_params
if param.name not in self._OMITTED_S3_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()
section.writeln(
f'The available ``{self._service_name}`` client context params are:'
)
for param in self._context_params:
section.style.new_line()
section.write(
f'* ``{xform_name(param.name)}`` ({param.type}) - {param.documentation}'
)
19 changes: 18 additions & 1 deletion botocore/docs/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
from botocore.docs.bcdoc.restdoc import DocumentStructure
from botocore.docs.client import ClientDocumenter, ClientExceptionsDocumenter
from botocore.docs.client import (
ClientContextParamsDocumenter,
ClientDocumenter,
ClientExceptionsDocumenter,
)
from botocore.docs.paginator import PaginatorDocumenter
from botocore.docs.waiter import WaiterDocumenter
from botocore.exceptions import DataNotFoundError
Expand All @@ -37,6 +41,7 @@ def __init__(self, service_name, session, root_docs_path):
'client-exceptions',
'paginator-api',
'waiter-api',
'client-context-params',
]

def document_service(self):
Expand All @@ -52,6 +57,9 @@ def document_service(self):
self.client_exceptions(doc_structure.get_section('client-exceptions'))
self.paginator_api(doc_structure.get_section('paginator-api'))
self.waiter_api(doc_structure.get_section('waiter-api'))
self.client_context_params(
doc_structure.get_section('client-context-params')
)
return doc_structure.flush_structure()

def title(self, section):
Expand Down Expand Up @@ -108,3 +116,12 @@ def get_examples(self, service_name, api_version=None):
service_name, 'examples-1', api_version
)
return examples['examples']

def client_context_params(self, section):
service_model = self._client.meta.service_model
context_params = service_model.client_context_parameters
if context_params:
context_param_documenter = ClientContextParamsDocumenter(
context_params, self._service_name
)
context_param_documenter.document_context_params(section)
12 changes: 12 additions & 0 deletions tests/functional/docs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@ def get_docstring_for_method(self, service_name, method_name):
method_contents = self.get_method_document_block(method_name, contents)
return method_contents

def get_client_context_params_block(self, contents):
contents = contents.decode('utf-8')
start_param_document = '===\nClient Context Parameters\n==='
start_index = contents.find(start_param_document)
self.assertNotEqual(
start_index, -1, 'Context param section is not found in contents'
)
# Context params are at the end of the service client file. This may
# change in the future. If it does, an end index should be calculated.
contents = contents[start_index:]
return contents.encode('utf-8')

def assert_is_documented_as_autopopulated_param(
self, service_name, method_name, param_name, doc_string=None
):
Expand Down
14 changes: 14 additions & 0 deletions tests/functional/docs/test_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,17 @@ def test_copy_source_param_docs_also_modified(self):
self.assert_contains_line(
"You can also provide this value as a dictionary", param_docs
)

def test_client_context_params_omitted(self):
contents = ServiceDocumenter(
's3', self._session, self.root_services_path
).document_service()
context_params_content = self.get_client_context_params_block(contents)
self.assert_not_contains_line(
'``accelerate`` (boolean)',
context_params_content,
)
self.assert_not_contains_line(
'``force_path_style`` (boolean)',
context_params_content,
)
6 changes: 6 additions & 0 deletions tests/unit/docs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,12 @@ def add_shape_to_errors(self, shape_name):
errors.append({'shape': shape_name})
operation['errors'] = errors

def add_client_context_params(self, context_params):
if 'clientContextParams' not in self.json_model:
self.json_model['clientContextParams'] = context_params
else:
self.json_model['clientContextParams'].update(context_params)

def assert_contains_line(self, line):
contents = self.doc_structure.flush_structure().decode('utf-8')
self.assertIn(line, contents)
Expand Down
44 changes: 43 additions & 1 deletion tests/unit/docs/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
# 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 ClientDocumenter, ClientExceptionsDocumenter
from botocore.docs.client import (
ClientContextParamsDocumenter,
ClientDocumenter,
ClientExceptionsDocumenter,
)
from tests.unit.docs import BaseDocsTest


Expand Down Expand Up @@ -167,3 +171,41 @@ def test_modeled_exceptions(self):
'myservice', 'client/exceptions', 'SomeException'
),
)


class TestClientContextParamsDocumenter(BaseDocsTest):
def setUp(self):
super().setUp()
self.add_client_context_params(
{
'ClientContextParam1': {
'type': 'string',
'documentation': 'A client context param',
},
'ClientContextParam2': {
'type': 'boolean',
'documentation': 'A second client context param',
},
}
)
self.setup_client()
service_model = self.client.meta.service_model
self.context_params_documenter = ClientContextParamsDocumenter(
service_model.client_context_parameters, service_model.service_name
)

def test_client_context_params(self):
self.context_params_documenter.document_context_params(
self.doc_structure
)
self.assert_contains_lines_in_order(
[
'========================',
'Client Context Parameters',
'========================',
'Client context parameters are configurable',
'The available ``myservice`` client context params are:',
'* ``client_context_param1`` (string) - A client context param',
'* ``client_context_param2`` (boolean) - A second client context param',
]
)
24 changes: 24 additions & 0 deletions tests/unit/docs/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
class TestServiceDocumenter(BaseDocsTest):
def setUp(self):
super().setUp()
self.setup_documenter()

def setup_documenter(self):
self.add_shape_to_params('Biz', 'String')
self.setup_client()
with mock.patch(
Expand Down Expand Up @@ -97,3 +100,24 @@ def test_document_service_no_waiter(self):
os.remove(self.waiter_model_file)
contents = self.service_documenter.document_service().decode('utf-8')
self.assertNotIn('Waiters', contents)

def test_document_no_context_params(self):
contents = self.service_documenter.document_service().decode('utf-8')
self.assertNotIn('Client Context Parameters', contents)

def test_document_context_params(self):
self.add_client_context_params(
{
'ClientContextParam1': {
'type': 'string',
'documentation': 'A client context param',
},
'ClientContextParam2': {
'type': 'boolean',
'documentation': 'A second client context param',
},
}
)
self.setup_documenter()
contents = self.service_documenter.document_service().decode('utf-8')
self.assertIn('Client Context Parameters', contents)

0 comments on commit 65ad078

Please sign in to comment.