Skip to content

Commit

Permalink
Merge pull request #7205 from hssyoo/doc-tagged-unions
Browse files Browse the repository at this point in the history
Add note for Tagged Unions
  • Loading branch information
kyleknap authored Aug 26, 2022
2 parents d95a1a8 + 15472bf commit 9677fd4
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changes/next-release/enhancement-docs-3408.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "enhancement",
"category": "docs",
"description": "Generate a usage note for Tagged Union structures."
}
19 changes: 18 additions & 1 deletion awscli/clidocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
from awscli.topictags import TopicTagDB
from awscli.utils import (
find_service_and_method_in_event_name, is_document_type,
operation_uses_document_types, is_streaming_blob_type
operation_uses_document_types, is_streaming_blob_type,
is_tagged_union_type
)

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -56,6 +57,8 @@ def _get_argument_type_name(self, shape, default):
return 'document'
if is_streaming_blob_type(shape):
return 'streaming blob'
if is_tagged_union_type(shape):
return 'tagged union structure'
return default

def _map_handlers(self, session, event_class, mapfn):
Expand Down Expand Up @@ -185,6 +188,8 @@ def doc_option(self, arg_name, help_command, **kwargs):
doc.include_doc_string(argument.documentation)
if is_streaming_blob_type(argument.argument_model):
self._add_streaming_blob_note(doc)
if is_tagged_union_type(argument.argument_model):
self._add_tagged_union_note(argument.argument_model, doc)
if hasattr(argument, 'argument_model'):
self._document_enums(argument.argument_model, doc)
self._document_nested_structure(argument.argument_model, doc)
Expand Down Expand Up @@ -264,6 +269,8 @@ def _do_doc_member(self, doc, member_name, member_shape, stack):
doc.style.indent()
doc.style.new_paragraph()
doc.include_doc_string(docs)
if is_tagged_union_type(member_shape):
self._add_tagged_union_note(member_shape, doc)
doc.style.new_paragraph()
member_type_name = member_shape.type_name
if member_type_name == 'structure':
Expand All @@ -290,6 +297,16 @@ def _add_streaming_blob_note(self, doc):
doc.writeln(msg)
doc.style.end_note()

def _add_tagged_union_note(self, shape, doc):
doc.style.start_note()
members_str = ", ".join(
[f'``{key}``' for key in shape.members.keys()]
)
msg = ("This is a Tagged Union structure. Only one of the "
f"following top level keys can be set: {members_str}.")
doc.writeln(msg)
doc.style.end_note()


class ProviderDocumentEventHandler(CLIDocumentEventHandler):

Expand Down
5 changes: 5 additions & 0 deletions awscli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ def is_streaming_blob_type(shape):
shape.serialization.get('streaming', False))


def is_tagged_union_type(shape):
"""Check if the shape is a tagged union structure."""
return getattr(shape, 'is_tagged_union', False)


def operation_uses_document_types(operation_model):
"""Check if document types are ever used in the operation"""
recording_visitor = ShapeRecordingVisitor()
Expand Down
55 changes: 54 additions & 1 deletion tests/unit/test_clidocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import json

from botocore.model import ShapeResolver, StructureShape, StringShape, \
ListShape, MapShape, Shape
ListShape, MapShape, Shape, DenormalizedStructureBuilder

from awscli.testutils import mock, unittest, FileCreator
from awscli.clidocs import OperationDocumentEventHandler, \
Expand Down Expand Up @@ -150,6 +150,15 @@ def create_help_command(self):
help_command.obj = operation_model
return help_command

def create_tagged_union_shape(self):
shape_model = {
'type': 'structure',
'union': True,
'members': {}
}
tagged_union = StructureShape('tagged_union', shape_model)
return tagged_union

def get_help_docs_for_argument(self, shape):
arg_table = {'arg-name': mock.Mock(argument_model=shape)}
help_command = mock.Mock()
Expand Down Expand Up @@ -391,6 +400,50 @@ def test_streaming_blob_comes_after_docstring(self):
rendered = help_command.doc.getvalue().decode('utf-8')
self.assertRegex(rendered, r'FooBar[\s\S]*streaming blob')

def test_includes_tagged_union_options(self):
help_command = self.create_help_command()
tagged_union = self.create_tagged_union_shape()
arg = CustomArgument(name='tagged_union',
argument_model=tagged_union)
help_command.arg_table = {'tagged_union': arg}
operation_handler = OperationDocumentEventHandler(help_command)
operation_handler.doc_option(arg_name='tagged_union',
help_command=help_command)
rendered = help_command.doc.getvalue().decode('utf-8')
self.assertIn('(tagged union structure)', rendered)

def test_tagged_union_comes_after_docstring_options(self):
help_command = self.create_help_command()
tagged_union = self.create_tagged_union_shape()
arg = CustomArgument(name='tagged_union',
argument_model=tagged_union,
help_text='FooBar')
help_command.arg_table = {'tagged_union': arg}
operation_handler = OperationDocumentEventHandler(help_command)
operation_handler.doc_option(arg_name='tagged_union',
help_command=help_command)
rendered = help_command.doc.getvalue().decode('utf-8')
self.assertRegex(rendered, r'FooBar[\s\S]*Tagged Union')

def test_tagged_union_comes_after_docstring_output(self):
help_command = self.create_help_command()
tagged_union = self.create_tagged_union_shape()
tagged_union.documentation = "FooBar"
shape = DenormalizedStructureBuilder().with_members({
'foo': {
'type': 'structure',
'union': True,
'documentation': 'FooBar',
'members': {}
}
}).build_model()
help_command.obj.output_shape = shape
operation_handler = OperationDocumentEventHandler(help_command)
operation_handler.doc_output(help_command=help_command,
event_name='foobar')
rendered = help_command.doc.getvalue().decode('utf-8')
self.assertRegex(rendered, r'FooBar[\s\S]*Tagged Union')


class TestTopicDocumentEventHandlerBase(unittest.TestCase):
def setUp(self):
Expand Down
14 changes: 12 additions & 2 deletions tests/unit/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
from awscli.utils import (
split_on_commas, ignore_ctrl_c, find_service_and_method_in_event_name,
is_document_type, is_document_type_container, is_streaming_blob_type,
operation_uses_document_types, ShapeWalker, ShapeRecordingVisitor,
OutputStreamFactory
is_tagged_union_type, operation_uses_document_types, ShapeWalker,
ShapeRecordingVisitor, OutputStreamFactory
)


Expand Down Expand Up @@ -433,3 +433,13 @@ def test_non_blob_is_not_streaming(self, argument_model):
argument_model.type_name = 'string'
argument_model.serialization = {}
assert not is_streaming_blob_type(argument_model)


@pytest.mark.usefixtures('argument_model')
class TestTaggedUnion:
def test_shape_is_tagged_union(self, argument_model):
setattr(argument_model, 'is_tagged_union', True)
assert is_tagged_union_type(argument_model)

def test_shape_is_not_tagged_union(self, argument_model):
assert not is_tagged_union_type(argument_model)

0 comments on commit 9677fd4

Please sign in to comment.