Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions botocore/docs/bcdoc/docstringparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
# language governing permissions and limitations under the License.
from html.parser import HTMLParser

PRIORITY_PARENT_TAGS = ('code', 'a')
OMIT_NESTED_TAGS = ('span', 'i', 'code', 'a')
OMIT_SELF_TAGS = ('i', 'b')


class DocStringParser(HTMLParser):
"""
Expand Down Expand Up @@ -134,7 +138,23 @@ def __init__(self, tag, attrs=None, parent=None):
self.attrs = attrs
self.tag = tag

def _has_nested_tags(self):
# Returns True if any children are TagNodes and False otherwise.
return any(isinstance(child, TagNode) for child in self.children)

def write(self, doc, next_child=None):
prioritize_nested_tags = (
self.tag in OMIT_SELF_TAGS and self._has_nested_tags()
)
prioritize_parent_tag = (
isinstance(self.parent, TagNode)
and self.parent.tag in PRIORITY_PARENT_TAGS
and self.tag in OMIT_NESTED_TAGS
)
if prioritize_nested_tags or prioritize_parent_tag:
self._write_children(doc)
return

self._write_start(doc)
self._write_children(doc)
self._write_end(doc, next_child)
Expand Down Expand Up @@ -201,6 +221,11 @@ def write(self, doc):

if self.data.isspace():
str_data = ' '
if isinstance(self.parent, TagNode) and self.parent.tag == 'code':
# Inline markup content may not start or end with whitespace.
# When provided <code> Test </code>, we want to
# generate ``Test`` instead of `` Test ``.
str_data = ''
else:
end_space = self.data[-1].isspace()
words = self.data.split()
Expand Down
2 changes: 1 addition & 1 deletion botocore/docs/bcdoc/restdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def pop_write(self):
"""
Removes and returns the last content written to the stack.
"""
return self._writes.pop()
return self._writes.pop() if len(self._writes) > 0 else None

def push_write(self, s):
"""
Expand Down
32 changes: 31 additions & 1 deletion botocore/docs/bcdoc/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ def underline(self, s):
def italics(self, s):
return s

def add_trailing_space_to_previous_write(self):
# Adds a trailing space if none exists. This is mainly used for
# ensuring inline code and links are separated from surrounding text.
last_write = self.doc.pop_write()
if last_write is None:
last_write = ''
if last_write != '' and last_write[-1] != ' ':
last_write += ' '
self.doc.push_write(last_write)


class ReSTStyle(BaseStyle):
def __init__(self, doc, indent_width=2):
Expand Down Expand Up @@ -162,6 +172,7 @@ def end_p(self):

def start_code(self, attrs=None):
self.doc.do_translation = True
self.add_trailing_space_to_previous_write()
self._start_inline('``')

def end_code(self):
Expand Down Expand Up @@ -205,10 +216,15 @@ def end_danger(self):
self.new_paragraph()

def start_a(self, attrs=None):
# Write an empty space to guard against zero whitespace
# before an "a" tag. Example: hi<a>Example</a>
self.add_trailing_space_to_previous_write()
if attrs:
for attr_key, attr_value in attrs:
if attr_key == 'href':
self.a_href = attr_value
# Removes unnecessary whitespace around the href link.
# Example: <a href=" http://example.com ">Example</a>
self.a_href = attr_value.strip()
self.doc.write('`')
else:
# There are some model documentation that
Expand All @@ -229,9 +245,23 @@ def sphinx_reference_label(self, label, text=None):
else:
self.doc.write(text)

def _clean_link_text(self):
doc = self.doc
# Pop till we reach the link start character to retrieve link text.
last_write = doc.pop_write()
while not last_write.startswith('`'):
last_write = doc.pop_write() + last_write
doc.push_write('`')

# Remove whitespace from the start of link text.
last_write = last_write[1:].lstrip(' ')
if last_write != '':
doc.push_write(last_write)

def end_a(self, next_child=None):
self.doc.do_translation = False
if self.a_href:
self._clean_link_text()
last_write = self.doc.pop_write()
last_write = last_write.rstrip(' ')
if last_write and last_write != '`':
Expand Down
36 changes: 36 additions & 0 deletions tests/unit/docs/bcdoc/test_docstringparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,42 @@ def test_link_with_period(self):
result, [b'This is a test `Link <https://testing.com>`__.']
)

def test_code_with_empty_link(self):
html = "<code> <a>Link</a> </code>"
result = self.parse(html)
self.assert_contains_exact_lines_in_order(result, [b'``Link`` '])

def test_code_with_link_spaces(self):
html = "<code> <a href=\"https://testing.com\">Link</a> </code>"
result = self.parse(html)
self.assert_contains_exact_lines_in_order(result, [b'``Link`` '])

def test_code_with_link_no_spaces(self):
html = "<code><a href=\"https://testing.com\">Link</a></code>"
result = self.parse(html)
self.assert_contains_exact_lines_in_order(result, [b'``Link`` '])

def test_href_with_spaces(self):
html = "<p><a href=\" https://testing.com\">Link</a></p>"
result = self.parse(html)
self.assert_contains_exact_lines_in_order(
result, [b' `Link <https://testing.com>`__ ']
)

def test_bold_with_nested_formatting(self):
html = "<b><code>Test</code>test<a href=\" https://testing.com\">Link</a></b>"
result = self.parse(html)
self.assert_contains_exact_lines_in_order(
result, [b'``Test`` test `Link <https://testing.com>`__ ']
)

def test_link_with_nested_formatting(self):
html = "<a href=\"https://testing.com\"><code>Test</code></a>"
result = self.parse(html)
self.assert_contains_exact_lines_in_order(
result, [b'`Test <https://testing.com>`__ ']
)


class TestHTMLTree(unittest.TestCase):
def setUp(self):
Expand Down