Skip to content

Commit

Permalink
feat: support devsite notices (#222)
Browse files Browse the repository at this point in the history
* feat: add support for various notices

* fix: update docstrings and comments

* test: update unit test
  • Loading branch information
dandhlee authored Jul 11, 2022
1 parent c350787 commit 0da9224
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 1 deletion.
73 changes: 73 additions & 0 deletions docfx_yaml/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,33 @@ class Bcolors:
CODE = "code"
PACKAGE = "package"

# DevSite specific notices that can be used.
NOTE = 'note'
CAUTION = 'caution'
WARNING = 'warning'
IMPORTANT = 'special'
KEYPOINT = 'key-point'
KEYTERM = 'key-term'
OBJECTIVE = 'objective'
SUCCESS = 'success'
BETA = 'beta'
PREVIEW = 'preview'
DEPRECATED = 'deprecated'

NOTICES = {
NOTE: 'Note',
CAUTION: 'Caution',
WARNING: 'Warning',
IMPORTANT: 'Important',
KEYPOINT: 'Key Point',
KEYTERM: 'Key Term',
OBJECTIVE: 'Objective',
SUCCESS: 'Success',
BETA: 'Beta',
PREVIEW: 'Preview',
DEPRECATED: 'deprecated',
}

# Disable blib2to3 output that clutters debugging log.
logging.getLogger("blib2to3").setLevel(logging.ERROR)

Expand Down Expand Up @@ -407,6 +434,9 @@ def _parse_docstring_summary(summary):
attribute_type_token = ":type:"
keyword = name = description = var_type = ""

notice_open_tag = '<aside class="{notice_tag}">\n<b>{notice_name}:</b>'
notice_close_tag = '</aside>'

# We need to separate in chunks, which is defined by 3 newline breaks.
# Otherwise when parsing for code and blocks of stuff, we will not be able
# to have the entire context when just splitting by single newlines.
Expand Down Expand Up @@ -468,6 +498,24 @@ def _parse_docstring_summary(summary):

continue

elif keyword and keyword in NOTICES:
# Determine how much code block is indented to format properly.
if tab_space == -1:
parts = [split_part for split_part in part.split("\n") if split_part]
tab_space = len(parts[0]) - len(parts[0].lstrip(" "))
if tab_space == 0:
raise ValueError("Content in the block should be indented."\
f"Please check the docstring: \n{summary}")
if not part.startswith(" "*tab_space):
if notice_body:
parts = [indent_code_left(part, tab_space) for part in notice_body]
summary_parts.append("\n".join(parts))

summary_parts.append(notice_close_tag)
keyword = ""
notice_body.append(part)
continue

# Parse keywords if found.
# lstrip is added to parse code blocks that are not formatted well.
if part.lstrip('\n').startswith('..'):
Expand All @@ -491,6 +539,24 @@ def _parse_docstring_summary(summary):
found_name = False
name = part.split("::")[1].strip()

# Extracts the notice content and format it.
elif keyword and keyword in NOTICES:
summary_parts.append(notice_open_tag.format(
notice_tag=keyword, notice_name=NOTICES[keyword]))
tab_space = -1
notice_body = []
parts = [split_part for split_part in part.split("\n") if split_part][1:]
if not parts:
continue
tab_space = len(parts[0]) - len(parts[0].lstrip(" "))
if tab_space == 0:
raise ValueError("Content in the block should be indented."\
f"Please check the docstring: \n{summary}")
parts = [indent_code_left(part, tab_space) for part in parts]
summary_parts.append("\n".join(parts))
summary_parts.append(notice_close_tag)
keyword = ""

# Reserve for additional parts
# elif keyword == keyword:
else:
Expand All @@ -508,6 +574,13 @@ def _parse_docstring_summary(summary):
if summary_parts[-1] != "```\n":
summary_parts.append("```\n")

if keyword and keyword in NOTICES:
if notice_body:
parts = [indent_code_left(part, tab_space) for part in notice_body]
summary_parts.append("\n\n".join(parts))
if summary_parts[-1] != notice_close_tag:
summary_parts.append(notice_close_tag)

# Requires 2 newline chars to properly show on cloud site.
return "\n".join(summary_parts), attributes

Expand Down
44 changes: 43 additions & 1 deletion tests/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ def get_client_cert():
# Check that nothing much changes otherwise.
summary = \
"""
.. note::
.. literalinclude::
note that these are not supported yet, so they will be ignored for now.
And any other documentation that the source code would have could go here.
Expand All @@ -833,6 +833,48 @@ def get_client_cert():
with self.assertRaises(ValueError):
_parse_docstring_summary(summary)

# Check that notices are processed properly.
summary_want = \
"""<aside class="note">
<b>Note:</b>
this is a note.
</aside>
<aside class="caution">
<b>Caution:</b>
another type of notice.
</aside>
<aside class="key-term">
<b>Key Term:</b>
hyphenated term notice.
</aside>"""

summary = \
"""
.. note::
\n this is a note.
.. caution::
\n another type of notice.
.. key-term::
\n hyphenated term notice.
"""

summary_got, attributes_got = _parse_docstring_summary(summary)
self.assertEqual(summary_got, summary_want)
self.assertEqual(attributes_got, attributes_want)

# Check that exception is raised if block is not formatted properly.

summary = \
"""
.. warning::
this is not a properly formatted warning.
"""
with self.assertRaises(ValueError):
_parse_docstring_summary(summary)

def test_parse_docstring_summary_attributes(self):
# Test parsing docstring with attributes.
Expand Down

0 comments on commit 0da9224

Please sign in to comment.