Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addresses admonition accessibility issue #2928

Merged
merged 13 commits into from
May 11, 2023
45 changes: 30 additions & 15 deletions botocore/docs/bcdoc/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ def end_b(self):
self.doc.do_translation = False
self.end_bold()

def write_raw_h3(self, s):
self.start_raw_directive()
self.doc.write(f"<h3>{s}</h3>")
self.end_raw_directive()

def bold(self, s):
if s:
self.start_bold()
Expand Down Expand Up @@ -186,35 +191,45 @@ def code(self, s):
self.doc.write(s)
self.end_code()

def start_note(self, attrs=None):
def start_raw_directive(self):
self.new_paragraph()
self.doc.write('.. note::')
self.doc.write('.. raw:: html')
self.indent()
self.new_paragraph()

def end_note(self):
def end_raw_directive(self):
self.dedent()
self.new_paragraph()

def start_raw_admonition(self, type):
self.start_raw_directive()
self.doc.write(f'<div class="admonition {type}">')
self.new_line()
self.doc.write(f'<h3 class="admonition-title">{type.title()}</h3>')
self.end_raw_directive()

def end_raw_admonition(self):
self.start_raw_directive()
self.doc.write('</div>')
self.end_raw_directive()

def start_note(self, attrs=None):
self.start_raw_admonition('note')

def end_note(self):
self.end_raw_admonition()

def start_important(self, attrs=None):
self.new_paragraph()
self.doc.write('.. warning::')
self.indent()
self.new_paragraph()
self.start_raw_admonition('warning')

def end_important(self):
self.dedent()
self.new_paragraph()
self.end_raw_admonition()

def start_danger(self, attrs=None):
self.new_paragraph()
self.doc.write('.. danger::')
self.indent()
self.new_paragraph()
self.start_raw_admonition('danger')

def end_danger(self):
self.dedent()
self.new_paragraph()
self.end_raw_admonition()

def start_a(self, attrs=None):
# Write an empty space to guard against zero whitespace
Expand Down
8 changes: 4 additions & 4 deletions botocore/docs/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def _add_custom_method(self, section, method_name, method):
def _add_method_exceptions_list(self, section, operation_model):
error_section = section.add_new_section('exceptions')
error_section.style.new_line()
error_section.style.bold('Exceptions')
error_section.style.write_raw_h3('Exceptions')
error_section.style.new_line()
for error in operation_model.error_shapes:
class_name = (
Expand Down Expand Up @@ -334,7 +334,7 @@ def _add_top_level_documentation(self, section, shape):

def _add_exception_catch_example(self, section, shape):
section.style.new_line()
section.style.bold('Example')
section.style.write_raw_h3('Example')
section.style.start_codeblock()
section.write('try:')
section.style.indent()
Expand Down Expand Up @@ -370,7 +370,7 @@ def _add_response_attr_description(self, section):
def _add_response_example(self, section, shape):
example_section = section.add_new_section('syntax')
example_section.style.new_line()
example_section.style.bold('Syntax')
example_section.style.write_raw_h3('Syntax')
example_section.style.new_paragraph()
documenter = ResponseExampleDocumenter(
service_name=self._service_name,
Expand All @@ -386,7 +386,7 @@ def _add_response_example(self, section, shape):
def _add_response_params(self, section, shape):
params_section = section.add_new_section('Structure')
params_section.style.new_line()
params_section.style.bold('Structure')
params_section.style.write_raw_h3('Structure')
params_section.style.new_paragraph()
documenter = ResponseParamsDocumenter(
service_name=self._service_name,
Expand Down
6 changes: 3 additions & 3 deletions botocore/docs/method.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def document_model_driven_method(
# Add the example section.
example_section = section.add_new_section('request-example')
example_section.style.new_paragraph()
example_section.style.bold('Request Syntax')
example_section.style.write_raw_h3('Request Syntax')

context = {
'special_shape_types': {
Expand Down Expand Up @@ -292,7 +292,7 @@ def document_model_driven_method(
'response-example'
)
return_example_section.style.new_line()
return_example_section.style.bold('Response Syntax')
return_example_section.style.write_raw_h3('Response Syntax')
return_example_section.style.new_paragraph()
ResponseExampleDocumenter(
service_name=operation_model.service_model.service_name,
Expand All @@ -311,7 +311,7 @@ def document_model_driven_method(
'description'
)
return_description_section.style.new_line()
return_description_section.style.bold('Response Structure')
return_description_section.style.write_raw_h3('Response Structure')
return_description_section.style.new_paragraph()
ResponseParamsDocumenter(
service_name=operation_model.service_model.service_name,
Expand Down
2 changes: 1 addition & 1 deletion botocore/docs/sharedexample.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def document_shared_examples(
"""
container_section = section.add_new_section('shared-examples')
container_section.style.new_paragraph()
container_section.style.bold('Examples')
container_section.style.write_raw_h3('Examples')
documenter = SharedExampleDocumenter()
for example in shared_examples:
documenter.document_shared_example(
Expand Down
29 changes: 29 additions & 0 deletions docs/source/_static/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,32 @@ h1, code, li {
.sidebar-logo{
padding: 20% 15%;
}

/* Supporting style for replacing admonition titles from <p> to <h3>. */
h3.admonition-title {
position: relative;
margin: 0 -0.5rem 0.5rem;
padding-left: 2.5rem;
padding-right: .5rem;
padding-top: .4rem;
padding-bottom: .4rem;
font-weight: 700;
font-size: 1.5em;
line-height: 1.25;
border-radius: unset;
}
h3.admonition-title::before {
content: "";
position: absolute;
left: 0.5rem;
width: 1.5rem;
height: 1.5rem;
}
h3.admonition-title {
background-color: var(--color-admonition-title-background);
}
h3.admonition-title::before {
background-color: var(--color-admonition-title);
mask-image: var(--icon-admonition-default);
mask-repeat: no-repeat;
}
21 changes: 0 additions & 21 deletions docs/source/_static/js/custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,6 @@ function makeServiceLinkCurrent(serviceName) {
}
const currentPagePath = window.location.pathname.split('/');
const codeBlockSelector = 'div.highlight pre';
const boldTextSelector = 'strong';
const boldElements = document.querySelectorAll(boldTextSelector);
const headings = [
'Example',
'Examples',
'Exceptions',
'Request Syntax',
'Response Structure',
'Response Syntax',
'Structure',
'Syntax'
];
// Expands the "Available Services" sub-menu in the side-bar when viewing
// nested doc pages and highlights the corresponding service list item.
function expandSubMenu() {
Expand All @@ -112,18 +100,9 @@ function makeCodeBlocksScrollable() {
codeCell.tabIndex = 0;
});
}
// Converts implicit bold headings into actual headings with h3 tags.
function convertImplicitHeadings() {
boldElements.forEach(boldElement => {
if (headings.includes(boldElement.innerHTML)) {
boldElement.parentElement.outerHTML = `<h3>${ boldElement.innerHTML }</h3>`;
}
});
}
// Functions to run after the DOM loads.
function runAfterDOMLoads() {
expandSubMenu();
convertImplicitHeadings();
makeCodeBlocksScrollable();
}
// Run a function after the DOM loads.
Expand Down
6 changes: 4 additions & 2 deletions tests/functional/docs/test_lex.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ def test_jsonheader_docs(self):
docs = self.get_docstring_for_method('lex-runtime', 'post_content')
self.assert_contains_lines_in_order(
[
'**Request Syntax**',
' .. raw:: html',
' <h3>Request Syntax</h3>',
'sessionAttributes=%s,' % self.TYPE_STRING,
':type sessionAttributes: JSON serializable',
'**Response Syntax**',
' .. raw:: html',
' <h3>Response Syntax</h3>',
'\'slots\': %s,' % self.TYPE_STRING,
'\'sessionAttributes\': %s' % self.TYPE_STRING,
'**slots** (JSON serializable)',
Expand Down
31 changes: 28 additions & 3 deletions tests/unit/docs/bcdoc/test_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,19 +128,44 @@ def test_important(self):
style = ReSTStyle(ReSTDocument())
style.start_important()
style.end_important()
self.assertEqual(style.doc.getvalue(), b'\n\n.. warning::\n\n \n\n')
self.assertEqual(
style.doc.getvalue(),
(
b'\n\n.. raw:: html\n\n'
b' <div class="admonition warning">\n'
b' <h3 class="admonition-title">Warning</h3>\n\n'
b'\n\n.. raw:: html\n\n </div>\n\n'
),
)

def test_note(self):
style = ReSTStyle(ReSTDocument())
style.start_note()
style.end_note()
self.assertEqual(style.doc.getvalue(), b'\n\n.. note::\n\n \n\n')
self.assertEqual(
style.doc.getvalue(),
(
b'\n\n.. raw:: html\n\n'
b' <div class="admonition note">\n'
b' <h3 class="admonition-title">Note</h3>\n\n'
b'\n\n.. raw:: html\n\n </div>\n\n'
),
)

def test_danger(self):
style = ReSTStyle(ReSTDocument())
style.start_danger()
style.end_danger()
self.assertEqual(style.doc.getvalue(), b'\n\n.. danger::\n\n \n\n')
print(style.doc.getvalue())
jonathan343 marked this conversation as resolved.
Show resolved Hide resolved
self.assertEqual(
style.doc.getvalue(),
(
b'\n\n.. raw:: html\n\n'
b' <div class="admonition danger">\n'
b' <h3 class="admonition-title">Danger</h3>\n\n'
b'\n\n.. raw:: html\n\n </div>\n\n'
),
)

def test_toctree_html(self):
style = ReSTStyle(ReSTDocument())
Expand Down
22 changes: 15 additions & 7 deletions tests/unit/docs/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ def test_document_client(self):
self.assert_contains_lines_in_order(
[
'.. py:method:: MyService.Client.sample_operation(**kwargs)',
' **Request Syntax**',
' .. raw:: html',
' <h3>Request Syntax</h3>',
' ::',
' response = client.sample_operation(',
' Biz=\'string\'',
Expand All @@ -80,15 +81,18 @@ def test_document_client(self):
' :param Biz:',
' :rtype: dict',
' :returns:',
' **Response Syntax**',
' .. raw:: html',
' <h3>Response Syntax</h3>',
' ::',
' {',
' \'Biz\': \'string\'',
' }',
' **Response Structure**',
' .. raw:: html',
' <h3>Response Structure</h3>',
' - *(dict) --*',
' - **Biz** *(string) --*',
'**Exceptions**',
' .. raw:: html',
' <h3>Exceptions</h3>',
'* :py:class:`MyService.Client.exceptions.SomeException`',
],
self.get_nested_service_contents(
Expand Down Expand Up @@ -144,18 +148,22 @@ def test_modeled_exceptions(self):
self.assert_contains_lines_in_order(
[
'.. py:class:: MyService.Client.exceptions.SomeException',
'**Example**::',
' .. raw:: html',
' <h3>Example</h3>',
'::',
'except client.exceptions.SomeException as e:',
'.. py:attribute:: response',
'**Syntax**',
' .. raw:: html',
' <h3>Syntax</h3>',
'{',
"'Message': 'string',",
"'Error': {",
"'Code': 'string',",
"'Message': 'string'",
'}',
'}',
'**Structure**',
' .. raw:: html',
' <h3>Structure</h3>',
jonathan343 marked this conversation as resolved.
Show resolved Hide resolved
'- *(dict) --*',
'- **Message** *(string) --* ',
'- **Error** *(dict) --* ',
Expand Down
Loading